mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
chore: add 'classic_parameter_flow' column setting to templates (#17828)
We are forcing users to try the dynamic parameter experience first. Currently this setting only comes into effect if an experiment is enabled.
This commit is contained in:
3
coderd/apidoc/docs.go
generated
3
coderd/apidoc/docs.go
generated
@ -15573,6 +15573,9 @@ const docTemplate = `{
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"use_classic_parameter_flow": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
3
coderd/apidoc/swagger.json
generated
3
coderd/apidoc/swagger.json
generated
@ -14167,6 +14167,9 @@
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"use_classic_parameter_flow": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -11084,6 +11084,7 @@ func (q *FakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.Upd
|
||||
tpl.GroupACL = arg.GroupACL
|
||||
tpl.AllowUserCancelWorkspaceJobs = arg.AllowUserCancelWorkspaceJobs
|
||||
tpl.MaxPortSharingLevel = arg.MaxPortSharingLevel
|
||||
tpl.UseClassicParameterFlow = arg.UseClassicParameterFlow
|
||||
q.templates[idx] = tpl
|
||||
return nil
|
||||
}
|
||||
|
6
coderd/database/dump.sql
generated
6
coderd/database/dump.sql
generated
@ -1560,7 +1560,8 @@ CREATE TABLE templates (
|
||||
require_active_version boolean DEFAULT false NOT NULL,
|
||||
deprecated text DEFAULT ''::text NOT NULL,
|
||||
activity_bump bigint DEFAULT '3600000000000'::bigint NOT NULL,
|
||||
max_port_sharing_level app_sharing_level DEFAULT 'owner'::app_sharing_level NOT NULL
|
||||
max_port_sharing_level app_sharing_level DEFAULT 'owner'::app_sharing_level NOT NULL,
|
||||
use_classic_parameter_flow boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.';
|
||||
@ -1581,6 +1582,8 @@ COMMENT ON COLUMN templates.autostart_block_days_of_week IS 'A bitmap of days of
|
||||
|
||||
COMMENT ON COLUMN templates.deprecated IS 'If set to a non empty string, the template will no longer be able to be used. The message will be displayed to the user.';
|
||||
|
||||
COMMENT ON COLUMN templates.use_classic_parameter_flow IS 'Determines whether to default to the dynamic parameter creation flow for this template or continue using the legacy classic parameter creation flow.This is a template wide setting, the template admin can revert to the classic flow if there are any issues. An escape hatch is required, as workspace creation is a core workflow and cannot break. This column will be removed when the dynamic parameter creation flow is stable.';
|
||||
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.id,
|
||||
templates.created_at,
|
||||
@ -1610,6 +1613,7 @@ CREATE VIEW template_with_names AS
|
||||
templates.deprecated,
|
||||
templates.activity_bump,
|
||||
templates.max_port_sharing_level,
|
||||
templates.use_classic_parameter_flow,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(organizations.name, ''::text) AS organization_name,
|
||||
|
@ -0,0 +1,28 @@
|
||||
DROP VIEW template_with_names;
|
||||
|
||||
-- Drop the column
|
||||
ALTER TABLE templates DROP COLUMN use_classic_parameter_flow;
|
||||
|
||||
|
||||
CREATE VIEW
|
||||
template_with_names
|
||||
AS
|
||||
SELECT
|
||||
templates.*,
|
||||
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
|
||||
coalesce(visible_users.username, '') AS created_by_username,
|
||||
coalesce(organizations.name, '') AS organization_name,
|
||||
coalesce(organizations.display_name, '') AS organization_display_name,
|
||||
coalesce(organizations.icon, '') AS organization_icon
|
||||
FROM
|
||||
templates
|
||||
LEFT JOIN
|
||||
visible_users
|
||||
ON
|
||||
templates.created_by = visible_users.id
|
||||
LEFT JOIN
|
||||
organizations
|
||||
ON templates.organization_id = organizations.id
|
||||
;
|
||||
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
@ -0,0 +1,36 @@
|
||||
-- Default to `false`. Users will have to manually opt back into the classic parameter flow.
|
||||
-- We want the new experience to be tried first.
|
||||
ALTER TABLE templates ADD COLUMN use_classic_parameter_flow BOOL NOT NULL DEFAULT false;
|
||||
|
||||
COMMENT ON COLUMN templates.use_classic_parameter_flow IS
|
||||
'Determines whether to default to the dynamic parameter creation flow for this template '
|
||||
'or continue using the legacy classic parameter creation flow.'
|
||||
'This is a template wide setting, the template admin can revert to the classic flow if there are any issues. '
|
||||
'An escape hatch is required, as workspace creation is a core workflow and cannot break. '
|
||||
'This column will be removed when the dynamic parameter creation flow is stable.';
|
||||
|
||||
|
||||
-- Update the template_with_names view by recreating it.
|
||||
DROP VIEW template_with_names;
|
||||
CREATE VIEW
|
||||
template_with_names
|
||||
AS
|
||||
SELECT
|
||||
templates.*,
|
||||
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
|
||||
coalesce(visible_users.username, '') AS created_by_username,
|
||||
coalesce(organizations.name, '') AS organization_name,
|
||||
coalesce(organizations.display_name, '') AS organization_display_name,
|
||||
coalesce(organizations.icon, '') AS organization_icon
|
||||
FROM
|
||||
templates
|
||||
LEFT JOIN
|
||||
visible_users
|
||||
ON
|
||||
templates.created_by = visible_users.id
|
||||
LEFT JOIN
|
||||
organizations
|
||||
ON templates.organization_id = organizations.id
|
||||
;
|
||||
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
@ -117,6 +117,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
&i.Deprecated,
|
||||
&i.ActivityBump,
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
|
@ -3114,6 +3114,7 @@ type Template struct {
|
||||
Deprecated string `db:"deprecated" json:"deprecated"`
|
||||
ActivityBump int64 `db:"activity_bump" json:"activity_bump"`
|
||||
MaxPortSharingLevel AppSharingLevel `db:"max_port_sharing_level" json:"max_port_sharing_level"`
|
||||
UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"`
|
||||
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
||||
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
||||
OrganizationName string `db:"organization_name" json:"organization_name"`
|
||||
@ -3159,6 +3160,8 @@ type TemplateTable struct {
|
||||
Deprecated string `db:"deprecated" json:"deprecated"`
|
||||
ActivityBump int64 `db:"activity_bump" json:"activity_bump"`
|
||||
MaxPortSharingLevel AppSharingLevel `db:"max_port_sharing_level" json:"max_port_sharing_level"`
|
||||
// Determines whether to default to the dynamic parameter creation flow for this template or continue using the legacy classic parameter creation flow.This is a template wide setting, the template admin can revert to the classic flow if there are any issues. An escape hatch is required, as workspace creation is a core workflow and cannot break. This column will be removed when the dynamic parameter creation flow is stable.
|
||||
UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"`
|
||||
}
|
||||
|
||||
// Records aggregated usage statistics for templates/users. All usage is rounded up to the nearest minute.
|
||||
|
@ -10427,7 +10427,7 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, arg GetTem
|
||||
|
||||
const getTemplateByID = `-- name: GetTemplateByID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon
|
||||
FROM
|
||||
template_with_names
|
||||
WHERE
|
||||
@ -10468,6 +10468,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
&i.Deprecated,
|
||||
&i.ActivityBump,
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
@ -10479,7 +10480,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
|
||||
const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon
|
||||
FROM
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
@ -10528,6 +10529,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
&i.Deprecated,
|
||||
&i.ActivityBump,
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
@ -10538,7 +10540,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
}
|
||||
|
||||
const getTemplates = `-- name: GetTemplates :many
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates
|
||||
ORDER BY (name, id) ASC
|
||||
`
|
||||
|
||||
@ -10580,6 +10582,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
&i.Deprecated,
|
||||
&i.ActivityBump,
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
@ -10601,7 +10604,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
|
||||
const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, created_by_avatar_url, created_by_username, organization_name, organization_display_name, organization_icon
|
||||
FROM
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
@ -10701,6 +10704,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
&i.Deprecated,
|
||||
&i.ActivityBump,
|
||||
&i.MaxPortSharingLevel,
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.OrganizationName,
|
||||
@ -10877,7 +10881,8 @@ SET
|
||||
display_name = $6,
|
||||
allow_user_cancel_workspace_jobs = $7,
|
||||
group_acl = $8,
|
||||
max_port_sharing_level = $9
|
||||
max_port_sharing_level = $9,
|
||||
use_classic_parameter_flow = $10
|
||||
WHERE
|
||||
id = $1
|
||||
`
|
||||
@ -10892,6 +10897,7 @@ type UpdateTemplateMetaByIDParams struct {
|
||||
AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
|
||||
GroupACL TemplateACL `db:"group_acl" json:"group_acl"`
|
||||
MaxPortSharingLevel AppSharingLevel `db:"max_port_sharing_level" json:"max_port_sharing_level"`
|
||||
UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error {
|
||||
@ -10905,6 +10911,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl
|
||||
arg.AllowUserCancelWorkspaceJobs,
|
||||
arg.GroupACL,
|
||||
arg.MaxPortSharingLevel,
|
||||
arg.UseClassicParameterFlow,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@ -18197,7 +18204,7 @@ LEFT JOIN LATERAL (
|
||||
) latest_build ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow
|
||||
FROM
|
||||
templates
|
||||
WHERE
|
||||
|
@ -124,7 +124,8 @@ SET
|
||||
display_name = $6,
|
||||
allow_user_cancel_workspace_jobs = $7,
|
||||
group_acl = $8,
|
||||
max_port_sharing_level = $9
|
||||
max_port_sharing_level = $9,
|
||||
use_classic_parameter_flow = $10
|
||||
WHERE
|
||||
id = $1
|
||||
;
|
||||
|
@ -728,6 +728,12 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Defaults to the existing.
|
||||
classicTemplateFlow := template.UseClassicParameterFlow
|
||||
if req.UseClassicParameterFlow != nil {
|
||||
classicTemplateFlow = *req.UseClassicParameterFlow
|
||||
}
|
||||
|
||||
var updated database.Template
|
||||
err = api.Database.InTx(func(tx database.Store) error {
|
||||
if req.Name == template.Name &&
|
||||
@ -747,6 +753,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
req.TimeTilDormantAutoDeleteMillis == time.Duration(template.TimeTilDormantAutoDelete).Milliseconds() &&
|
||||
req.RequireActiveVersion == template.RequireActiveVersion &&
|
||||
(deprecationMessage == template.Deprecated) &&
|
||||
(classicTemplateFlow == template.UseClassicParameterFlow) &&
|
||||
maxPortShareLevel == template.MaxPortSharingLevel {
|
||||
return nil
|
||||
}
|
||||
@ -788,6 +795,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
AllowUserCancelWorkspaceJobs: req.AllowUserCancelWorkspaceJobs,
|
||||
GroupACL: groupACL,
|
||||
MaxPortSharingLevel: maxPortShareLevel,
|
||||
UseClassicParameterFlow: classicTemplateFlow,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("update template metadata: %w", err)
|
||||
@ -1070,6 +1078,7 @@ func (api *API) convertTemplate(
|
||||
Deprecated: templateAccessControl.IsDeprecated(),
|
||||
DeprecationMessage: templateAccessControl.Deprecated,
|
||||
MaxPortShareLevel: maxPortShareLevel,
|
||||
UseClassicParameterFlow: template.UseClassicParameterFlow,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1540,6 +1540,41 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
require.False(t, template.Deprecated)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("ClassicParameterFlow", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
require.False(t, template.UseClassicParameterFlow, "default is false")
|
||||
|
||||
bTrue := true
|
||||
bFalse := false
|
||||
req := codersdk.UpdateTemplateMeta{
|
||||
UseClassicParameterFlow: &bTrue,
|
||||
}
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
// set to true
|
||||
updated, err := client.UpdateTemplateMeta(ctx, template.ID, req)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, updated.UseClassicParameterFlow, "expected true")
|
||||
|
||||
// noop
|
||||
req.UseClassicParameterFlow = nil
|
||||
updated, err = client.UpdateTemplateMeta(ctx, template.ID, req)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, updated.UseClassicParameterFlow, "expected true")
|
||||
|
||||
// back to false
|
||||
req.UseClassicParameterFlow = &bFalse
|
||||
updated, err = client.UpdateTemplateMeta(ctx, template.ID, req)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, updated.UseClassicParameterFlow, "expected false")
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteTemplate(t *testing.T) {
|
||||
|
@ -61,6 +61,8 @@ type Template struct {
|
||||
// template version.
|
||||
RequireActiveVersion bool `json:"require_active_version"`
|
||||
MaxPortShareLevel WorkspaceAgentPortShareLevel `json:"max_port_share_level"`
|
||||
|
||||
UseClassicParameterFlow bool `json:"use_classic_parameter_flow"`
|
||||
}
|
||||
|
||||
// WeekdaysToBitmap converts a list of weekdays to a bitmap in accordance with
|
||||
@ -250,6 +252,12 @@ type UpdateTemplateMeta struct {
|
||||
// of the template.
|
||||
DisableEveryoneGroupAccess bool `json:"disable_everyone_group_access"`
|
||||
MaxPortShareLevel *WorkspaceAgentPortShareLevel `json:"max_port_share_level,omitempty"`
|
||||
// UseClassicParameterFlow is a flag that switches the default behavior to use the classic
|
||||
// parameter flow when creating a workspace. This only affects deployments with the experiment
|
||||
// "dynamic-parameters" enabled. This setting will live for a period after the experiment is
|
||||
// made the default.
|
||||
// An "opt-out" is present in case the new feature breaks some existing templates.
|
||||
UseClassicParameterFlow *bool `json:"use_classic_parameter_flow,omitempty"`
|
||||
}
|
||||
|
||||
type TemplateExample struct {
|
||||
|
@ -9,7 +9,7 @@ We track the following resources:
|
||||
<!-- Code generated by 'make docs/admin/security/audit-logs.md'. DO NOT EDIT -->
|
||||
|
||||
| <b>Resource<b> | | |
|
||||
|----------------------------------------------------------|----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|----------------------------------------------------------|----------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| APIKey<br><i>login, logout, register, create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>ip_address</td><td>false</td></tr><tr><td>last_used</td><td>true</td></tr><tr><td>lifetime_seconds</td><td>false</td></tr><tr><td>login_type</td><td>false</td></tr><tr><td>scope</td><td>false</td></tr><tr><td>token_name</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
|
||||
@ -26,7 +26,7 @@ We track the following resources:
|
||||
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
||||
| OrganizationSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>assign_default</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| RoleSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_classic_parameter_flow</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>is_system</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceAgent<br><i>connect, disconnect</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>api_key_scope</td><td>false</td></tr><tr><td>api_version</td><td>false</td></tr><tr><td>architecture</td><td>false</td></tr><tr><td>auth_instance_id</td><td>false</td></tr><tr><td>auth_token</td><td>false</td></tr><tr><td>connection_timeout_seconds</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>directory</td><td>false</td></tr><tr><td>disconnected_at</td><td>false</td></tr><tr><td>display_apps</td><td>false</td></tr><tr><td>display_order</td><td>false</td></tr><tr><td>environment_variables</td><td>false</td></tr><tr><td>expanded_directory</td><td>false</td></tr><tr><td>first_connected_at</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>instance_metadata</td><td>false</td></tr><tr><td>last_connected_at</td><td>false</td></tr><tr><td>last_connected_replica_id</td><td>false</td></tr><tr><td>lifecycle_state</td><td>false</td></tr><tr><td>logs_length</td><td>false</td></tr><tr><td>logs_overflowed</td><td>false</td></tr><tr><td>motd_file</td><td>false</td></tr><tr><td>name</td><td>false</td></tr><tr><td>operating_system</td><td>false</td></tr><tr><td>parent_id</td><td>false</td></tr><tr><td>ready_at</td><td>false</td></tr><tr><td>resource_id</td><td>false</td></tr><tr><td>resource_metadata</td><td>false</td></tr><tr><td>started_at</td><td>false</td></tr><tr><td>subsystems</td><td>false</td></tr><tr><td>troubleshooting_url</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>version</td><td>false</td></tr></tbody></table> |
|
||||
|
4
docs/reference/api/schemas.md
generated
4
docs/reference/api/schemas.md
generated
@ -6593,7 +6593,8 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
"require_active_version": true,
|
||||
"time_til_dormant_autodelete_ms": 0,
|
||||
"time_til_dormant_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"use_classic_parameter_flow": true
|
||||
}
|
||||
```
|
||||
|
||||
@ -6632,6 +6633,7 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
| `time_til_dormant_autodelete_ms` | integer | false | | |
|
||||
| `time_til_dormant_ms` | integer | false | | |
|
||||
| `updated_at` | string | false | | |
|
||||
| `use_classic_parameter_flow` | boolean | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
|
20
docs/reference/api/templates.md
generated
20
docs/reference/api/templates.md
generated
@ -78,7 +78,8 @@ To include deprecated templates, specify `deprecated:true` in the search query.
|
||||
"require_active_version": true,
|
||||
"time_til_dormant_autodelete_ms": 0,
|
||||
"time_til_dormant_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"use_classic_parameter_flow": true
|
||||
}
|
||||
]
|
||||
```
|
||||
@ -134,6 +135,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|
||||
|`» time_til_dormant_autodelete_ms`|integer|false|||
|
||||
|`» time_til_dormant_ms`|integer|false|||
|
||||
|`» updated_at`|string(date-time)|false|||
|
||||
|`» use_classic_parameter_flow`|boolean|false|||
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
@ -255,7 +257,8 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||
"require_active_version": true,
|
||||
"time_til_dormant_autodelete_ms": 0,
|
||||
"time_til_dormant_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"use_classic_parameter_flow": true
|
||||
}
|
||||
```
|
||||
|
||||
@ -403,7 +406,8 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||
"require_active_version": true,
|
||||
"time_til_dormant_autodelete_ms": 0,
|
||||
"time_til_dormant_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"use_classic_parameter_flow": true
|
||||
}
|
||||
```
|
||||
|
||||
@ -802,7 +806,8 @@ To include deprecated templates, specify `deprecated:true` in the search query.
|
||||
"require_active_version": true,
|
||||
"time_til_dormant_autodelete_ms": 0,
|
||||
"time_til_dormant_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"use_classic_parameter_flow": true
|
||||
}
|
||||
]
|
||||
```
|
||||
@ -858,6 +863,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|
||||
|`» time_til_dormant_autodelete_ms`|integer|false|||
|
||||
|`» time_til_dormant_ms`|integer|false|||
|
||||
|`» updated_at`|string(date-time)|false|||
|
||||
|`» use_classic_parameter_flow`|boolean|false|||
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
@ -999,7 +1005,8 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template} \
|
||||
"require_active_version": true,
|
||||
"time_til_dormant_autodelete_ms": 0,
|
||||
"time_til_dormant_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"use_classic_parameter_flow": true
|
||||
}
|
||||
```
|
||||
|
||||
@ -1128,7 +1135,8 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
|
||||
"require_active_version": true,
|
||||
"time_til_dormant_autodelete_ms": 0,
|
||||
"time_til_dormant_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"use_classic_parameter_flow": true
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -115,6 +115,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||
"deprecated": ActionTrack,
|
||||
"max_port_sharing_level": ActionTrack,
|
||||
"activity_bump": ActionTrack,
|
||||
"use_classic_parameter_flow": ActionTrack,
|
||||
},
|
||||
&database.TemplateVersion{}: {
|
||||
"id": ActionTrack,
|
||||
|
2
site/src/api/typesGenerated.ts
generated
2
site/src/api/typesGenerated.ts
generated
@ -2586,6 +2586,7 @@ export interface Template {
|
||||
readonly time_til_dormant_autodelete_ms: number;
|
||||
readonly require_active_version: boolean;
|
||||
readonly max_port_share_level: WorkspaceAgentPortShareLevel;
|
||||
readonly use_classic_parameter_flow: boolean;
|
||||
}
|
||||
|
||||
// From codersdk/templates.go
|
||||
@ -2956,6 +2957,7 @@ export interface UpdateTemplateMeta {
|
||||
readonly deprecation_message?: string;
|
||||
readonly disable_everyone_group_access: boolean;
|
||||
readonly max_port_share_level?: WorkspaceAgentPortShareLevel;
|
||||
readonly use_classic_parameter_flow?: boolean;
|
||||
}
|
||||
|
||||
// From codersdk/users.go
|
||||
|
@ -47,6 +47,7 @@ export const validationSchema = Yup.object({
|
||||
allow_user_cancel_workspace_jobs: Yup.boolean(),
|
||||
icon: iconValidator,
|
||||
require_active_version: Yup.boolean(),
|
||||
use_classic_parameter_flow: Yup.boolean(),
|
||||
deprecation_message: Yup.string(),
|
||||
max_port_sharing_level: Yup.string().oneOf(WorkspaceAppSharingLevels),
|
||||
});
|
||||
@ -89,6 +90,7 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
|
||||
deprecation_message: template.deprecation_message,
|
||||
disable_everyone_group_access: false,
|
||||
max_port_share_level: template.max_port_share_level,
|
||||
use_classic_parameter_flow: template.use_classic_parameter_flow,
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit,
|
||||
@ -222,6 +224,34 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
|
||||
</StackLabel>
|
||||
}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
size="small"
|
||||
id="use_classic_parameter_flow"
|
||||
name="use_classic_parameter_flow"
|
||||
checked={form.values.use_classic_parameter_flow}
|
||||
onChange={form.handleChange}
|
||||
disabled={false}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<StackLabel>
|
||||
Use classic workspace creation form
|
||||
<StackLabelHelperText>
|
||||
<span>
|
||||
Show the original workspace creation form without dynamic
|
||||
parameters or live updates. Recommended if your provisioners
|
||||
aren't updated or the new form causes issues.
|
||||
<strong>
|
||||
Users can always manually switch experiences in the
|
||||
workspace creation form.
|
||||
</strong>
|
||||
</span>
|
||||
</StackLabelHelperText>
|
||||
</StackLabel>
|
||||
}
|
||||
/>
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
|
||||
|
@ -54,6 +54,7 @@ const validFormValues: FormValues = {
|
||||
require_active_version: false,
|
||||
disable_everyone_group_access: false,
|
||||
max_port_share_level: "owner",
|
||||
use_classic_parameter_flow: false,
|
||||
};
|
||||
|
||||
const renderTemplateSettingsPage = async () => {
|
||||
|
@ -824,6 +824,7 @@ export const MockTemplate: TypesGen.Template = {
|
||||
deprecated: false,
|
||||
deprecation_message: "",
|
||||
max_port_share_level: "public",
|
||||
use_classic_parameter_flow: false,
|
||||
};
|
||||
|
||||
const MockTemplateVersionFiles: TemplateVersionFiles = {
|
||||
|
Reference in New Issue
Block a user