diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index cec325a7b8..659fca44b9 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -11412,6 +11412,10 @@ const docTemplate = `{ "description": "RequireActiveVersion mandates that workspaces are built with the active\ntemplate version.", "type": "boolean" }, + "template_use_classic_parameter_flow": { + "description": "UseClassicParameterFlow allows optionally specifying whether\nthe template should use the classic parameter flow. The default if unset is\ntrue, and is why ` + "`" + `*bool` + "`" + ` is used here. When dynamic parameters becomes\nthe default, this will default to false.", + "type": "boolean" + }, "template_version_id": { "description": "VersionID is an in-progress or completed job to use as an initial version\nof the template.\n\nThis is required on creation to enable a user-flow of validating a\ntemplate works. There is no reason the data-model cannot support empty\ntemplates, but it doesn't make sense for users.", "type": "string", diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 6841978b12..6a7a67e6a4 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -10170,6 +10170,10 @@ "description": "RequireActiveVersion mandates that workspaces are built with the active\ntemplate version.", "type": "boolean" }, + "template_use_classic_parameter_flow": { + "description": "UseClassicParameterFlow allows optionally specifying whether\nthe template should use the classic parameter flow. The default if unset is\ntrue, and is why `*bool` is used here. When dynamic parameters becomes\nthe default, this will default to false.", + "type": "boolean" + }, "template_version_id": { "description": "VersionID is an in-progress or completed job to use as an initial version\nof the template.\n\nThis is required on creation to enable a user-flow of validating a\ntemplate works. There is no reason the data-model cannot support empty\ntemplates, but it doesn't make sense for users.", "type": "string", diff --git a/coderd/coderdtest/dynamicparameters.go b/coderd/coderdtest/dynamicparameters.go index cb295eeaae..fbc61b745d 100644 --- a/coderd/coderdtest/dynamicparameters.go +++ b/coderd/coderdtest/dynamicparameters.go @@ -50,22 +50,25 @@ func DynamicParameterTemplate(t *testing.T, client *codersdk.Client, org uuid.UU }) AwaitTemplateVersionJobCompleted(t, client, version.ID) - tplID := args.TemplateID - if args.TemplateID == uuid.Nil { - tpl := CreateTemplate(t, client, org, version.ID) - tplID = tpl.ID - } - + var tpl codersdk.Template var err error - tpl, err := client.UpdateTemplateMeta(t.Context(), tplID, codersdk.UpdateTemplateMeta{ - UseClassicParameterFlow: ptr.Ref(false), - }) - require.NoError(t, err) + + if args.TemplateID == uuid.Nil { + tpl = CreateTemplate(t, client, org, version.ID, func(request *codersdk.CreateTemplateRequest) { + request.UseClassicParameterFlow = ptr.Ref(false) + }) + } else { + tpl, err = client.UpdateTemplateMeta(t.Context(), args.TemplateID, codersdk.UpdateTemplateMeta{ + UseClassicParameterFlow: ptr.Ref(false), + }) + require.NoError(t, err) + } err = client.UpdateActiveTemplateVersion(t.Context(), tpl.ID, codersdk.UpdateActiveTemplateVersion{ ID: version.ID, }) require.NoError(t, err) + require.Equal(t, tpl.UseClassicParameterFlow, false, "template should use dynamic parameters") return tpl, version } diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 1244fa1393..4bcecdcc09 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -100,6 +100,7 @@ func Template(t testing.TB, db database.Store, seed database.Template) database. DisplayName: takeFirst(seed.DisplayName, testutil.GetRandomName(t)), AllowUserCancelWorkspaceJobs: seed.AllowUserCancelWorkspaceJobs, MaxPortSharingLevel: takeFirst(seed.MaxPortSharingLevel, database.AppSharingLevelOwner), + UseClassicParameterFlow: takeFirst(seed.UseClassicParameterFlow, true), }) require.NoError(t, err, "insert template") diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index ec879ed375..2279a9b0d9 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -9330,7 +9330,7 @@ func (q *FakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl AllowUserAutostart: true, AllowUserAutostop: true, MaxPortSharingLevel: arg.MaxPortSharingLevel, - UseClassicParameterFlow: true, + UseClassicParameterFlow: arg.UseClassicParameterFlow, } q.templates = append(q.templates, template) return nil diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 27ec73ee3c..0f85ef4c43 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -11031,10 +11031,11 @@ INSERT INTO group_acl, display_name, allow_user_cancel_workspace_jobs, - max_port_sharing_level + max_port_sharing_level, + use_classic_parameter_flow ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) ` type InsertTemplateParams struct { @@ -11053,6 +11054,7 @@ type InsertTemplateParams struct { DisplayName string `db:"display_name" json:"display_name"` AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"` 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) InsertTemplate(ctx context.Context, arg InsertTemplateParams) error { @@ -11072,6 +11074,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam arg.DisplayName, arg.AllowUserCancelWorkspaceJobs, arg.MaxPortSharingLevel, + arg.UseClassicParameterFlow, ) return err } diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql index 8b399fae87..d10d09daaf 100644 --- a/coderd/database/queries/templates.sql +++ b/coderd/database/queries/templates.sql @@ -98,10 +98,11 @@ INSERT INTO group_acl, display_name, allow_user_cancel_workspace_jobs, - max_port_sharing_level + max_port_sharing_level, + use_classic_parameter_flow ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15); + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16); -- name: UpdateTemplateActiveVersionByID :exec UPDATE diff --git a/coderd/templates.go b/coderd/templates.go index 2a3e0326b1..bba38bb033 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -197,16 +197,20 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque return } + // Default is true until dynamic parameters are promoted to stable. + useClassicParameterFlow := ptr.NilToDefault(createTemplate.UseClassicParameterFlow, true) + // Make a temporary struct to represent the template. This is used for // auditing if any of the following checks fail. It will be overwritten when // the template is inserted into the db. templateAudit.New = database.Template{ - OrganizationID: organization.ID, - Name: createTemplate.Name, - Description: createTemplate.Description, - CreatedBy: apiKey.UserID, - Icon: createTemplate.Icon, - DisplayName: createTemplate.DisplayName, + OrganizationID: organization.ID, + Name: createTemplate.Name, + Description: createTemplate.Description, + CreatedBy: apiKey.UserID, + Icon: createTemplate.Icon, + DisplayName: createTemplate.DisplayName, + UseClassicParameterFlow: useClassicParameterFlow, } _, err := api.Database.GetTemplateByOrganizationAndName(ctx, database.GetTemplateByOrganizationAndNameParams{ @@ -404,6 +408,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque Icon: createTemplate.Icon, AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs, MaxPortSharingLevel: maxPortShareLevel, + UseClassicParameterFlow: useClassicParameterFlow, }) if err != nil { return xerrors.Errorf("insert template: %s", err) diff --git a/coderd/templates_test.go b/coderd/templates_test.go index f8861da246..5e7fcea756 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -77,6 +77,7 @@ func TestPostTemplateByOrganization(t *testing.T) { assert.Equal(t, expected.Name, got.Name) assert.Equal(t, expected.Description, got.Description) assert.Equal(t, expected.ActivityBumpMillis, got.ActivityBumpMillis) + assert.Equal(t, expected.UseClassicParameterFlow, true) // Current default is true require.Len(t, auditor.AuditLogs(), 3) assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[0].Action) diff --git a/codersdk/organizations.go b/codersdk/organizations.go index 08c1fb0034..35a1e0be0a 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -200,6 +200,12 @@ type CreateTemplateRequest struct { // MaxPortShareLevel allows optionally specifying the maximum port share level // for workspaces created from the template. MaxPortShareLevel *WorkspaceAgentPortShareLevel `json:"max_port_share_level"` + + // UseClassicParameterFlow allows optionally specifying whether + // the template should use the classic parameter flow. The default if unset is + // true, and is why `*bool` is used here. When dynamic parameters becomes + // the default, this will default to false. + UseClassicParameterFlow *bool `json:"template_use_classic_parameter_flow,omitempty"` } // CreateWorkspaceRequest provides options for creating a new workspace. diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index efb4be973f..92e02fb4f4 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -1258,31 +1258,33 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "max_port_share_level": "owner", "name": "string", "require_active_version": true, + "template_use_classic_parameter_flow": true, "template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -|------------------------------------|--------------------------------------------------------------------------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `activity_bump_ms` | integer | false | | Activity bump ms allows optionally specifying the activity bump duration for all workspaces created from this template. Defaults to 1h but can be set to 0 to disable activity bumping. | -| `allow_user_autostart` | boolean | false | | Allow user autostart allows users to set a schedule for autostarting their workspace. By default this is true. This can only be disabled when using an enterprise license. | -| `allow_user_autostop` | boolean | false | | Allow user autostop allows users to set a custom workspace TTL to use in place of the template's DefaultTTL field. By default this is true. If false, the DefaultTTL will always be used. This can only be disabled when using an enterprise license. | -| `allow_user_cancel_workspace_jobs` | boolean | false | | Allow users to cancel in-progress workspace jobs. *bool as the default value is "true". | -| `autostart_requirement` | [codersdk.TemplateAutostartRequirement](#codersdktemplateautostartrequirement) | false | | Autostart requirement allows optionally specifying the autostart allowed days for workspaces created from this template. This is an enterprise feature. | -| `autostop_requirement` | [codersdk.TemplateAutostopRequirement](#codersdktemplateautostoprequirement) | false | | Autostop requirement allows optionally specifying the autostop requirement for workspaces created from this template. This is an enterprise feature. | -| `default_ttl_ms` | integer | false | | Default ttl ms allows optionally specifying the default TTL for all workspaces created from this template. | -| `delete_ttl_ms` | integer | false | | Delete ttl ms allows optionally specifying the max lifetime before Coder permanently deletes dormant workspaces created from this template. | -| `description` | string | false | | Description is a description of what the template contains. It must be less than 128 bytes. | -| `disable_everyone_group_access` | boolean | false | | Disable everyone group access allows optionally disabling the default behavior of granting the 'everyone' group access to use the template. If this is set to true, the template will not be available to all users, and must be explicitly granted to users or groups in the permissions settings of the template. | -| `display_name` | string | false | | Display name is the displayed name of the template. | -| `dormant_ttl_ms` | integer | false | | Dormant ttl ms allows optionally specifying the max lifetime before Coder locks inactive workspaces created from this template. | -| `failure_ttl_ms` | integer | false | | Failure ttl ms allows optionally specifying the max lifetime before Coder stops all resources for failed workspaces created from this template. | -| `icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | -| `max_port_share_level` | [codersdk.WorkspaceAgentPortShareLevel](#codersdkworkspaceagentportsharelevel) | false | | Max port share level allows optionally specifying the maximum port share level for workspaces created from the template. | -| `name` | string | true | | Name is the name of the template. | -| `require_active_version` | boolean | false | | Require active version mandates that workspaces are built with the active template version. | +| Name | Type | Required | Restrictions | Description | +|---------------------------------------|--------------------------------------------------------------------------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `activity_bump_ms` | integer | false | | Activity bump ms allows optionally specifying the activity bump duration for all workspaces created from this template. Defaults to 1h but can be set to 0 to disable activity bumping. | +| `allow_user_autostart` | boolean | false | | Allow user autostart allows users to set a schedule for autostarting their workspace. By default this is true. This can only be disabled when using an enterprise license. | +| `allow_user_autostop` | boolean | false | | Allow user autostop allows users to set a custom workspace TTL to use in place of the template's DefaultTTL field. By default this is true. If false, the DefaultTTL will always be used. This can only be disabled when using an enterprise license. | +| `allow_user_cancel_workspace_jobs` | boolean | false | | Allow users to cancel in-progress workspace jobs. *bool as the default value is "true". | +| `autostart_requirement` | [codersdk.TemplateAutostartRequirement](#codersdktemplateautostartrequirement) | false | | Autostart requirement allows optionally specifying the autostart allowed days for workspaces created from this template. This is an enterprise feature. | +| `autostop_requirement` | [codersdk.TemplateAutostopRequirement](#codersdktemplateautostoprequirement) | false | | Autostop requirement allows optionally specifying the autostop requirement for workspaces created from this template. This is an enterprise feature. | +| `default_ttl_ms` | integer | false | | Default ttl ms allows optionally specifying the default TTL for all workspaces created from this template. | +| `delete_ttl_ms` | integer | false | | Delete ttl ms allows optionally specifying the max lifetime before Coder permanently deletes dormant workspaces created from this template. | +| `description` | string | false | | Description is a description of what the template contains. It must be less than 128 bytes. | +| `disable_everyone_group_access` | boolean | false | | Disable everyone group access allows optionally disabling the default behavior of granting the 'everyone' group access to use the template. If this is set to true, the template will not be available to all users, and must be explicitly granted to users or groups in the permissions settings of the template. | +| `display_name` | string | false | | Display name is the displayed name of the template. | +| `dormant_ttl_ms` | integer | false | | Dormant ttl ms allows optionally specifying the max lifetime before Coder locks inactive workspaces created from this template. | +| `failure_ttl_ms` | integer | false | | Failure ttl ms allows optionally specifying the max lifetime before Coder stops all resources for failed workspaces created from this template. | +| `icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | +| `max_port_share_level` | [codersdk.WorkspaceAgentPortShareLevel](#codersdkworkspaceagentportsharelevel) | false | | Max port share level allows optionally specifying the maximum port share level for workspaces created from the template. | +| `name` | string | true | | Name is the name of the template. | +| `require_active_version` | boolean | false | | Require active version mandates that workspaces are built with the active template version. | +| `template_use_classic_parameter_flow` | boolean | false | | Template use classic parameter flow allows optionally specifying whether the template should use the classic parameter flow. The default if unset is true, and is why `*bool` is used here. When dynamic parameters becomes the default, this will default to false. | |`template_version_id`|string|true||Template version ID is an in-progress or completed job to use as an initial version of the template. This is required on creation to enable a user-flow of validating a template works. There is no reason the data-model cannot support empty templates, but it doesn't make sense for users.| diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md index cf99922877..4c21b3644b 100644 --- a/docs/reference/api/templates.md +++ b/docs/reference/api/templates.md @@ -193,6 +193,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa "max_port_share_level": "owner", "name": "string", "require_active_version": true, + "template_use_classic_parameter_flow": true, "template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1" } ``` diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index a29943fafb..727f514fc9 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -394,6 +394,7 @@ export interface CreateTemplateRequest { readonly disable_everyone_group_access: boolean; readonly require_active_version: boolean; readonly max_port_share_level: WorkspaceAgentPortShareLevel | null; + readonly template_use_classic_parameter_flow?: boolean; } // From codersdk/templateversions.go