From 18f8bcbfdc564ee53c8c2db02016d1088a332f25 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 31 Oct 2025 11:06:31 -0500 Subject: [PATCH 1/2] chore: per template opt into cached terraform directories --- coderd/apidoc/docs.go | 7 ++++ coderd/apidoc/swagger.json | 7 ++++ coderd/database/dump.sql | 6 +++- ...experimental_terraform_workspaces.down.sql | 26 ++++++++++++++ ...7_experimental_terraform_workspaces.up.sql | 33 +++++++++++++++++ coderd/database/modelqueries.go | 1 + coderd/database/models.go | 3 ++ coderd/database/queries.sql.go | 19 ++++++---- coderd/database/queries/templates.sql | 3 +- .../provisionerdserver/provisionerdserver.go | 5 ++- coderd/templates.go | 22 ++++++++---- codersdk/templates.go | 8 ++++- docs/reference/api/schemas.md | 8 +++-- docs/reference/api/templates.md | 23 ++++++++---- enterprise/audit/table.go | 1 + provisionersdk/tfpath/x/tfpath.go | 2 +- site/src/api/typesGenerated.ts | 8 +++++ .../TemplateSettingsForm.tsx | 36 +++++++++++++++++++ .../TemplateSettingsPage.jest.tsx | 1 + site/src/testHelpers/entities.ts | 1 + 20 files changed, 193 insertions(+), 27 deletions(-) create mode 100644 coderd/database/migrations/000397_experimental_terraform_workspaces.down.sql create mode 100644 coderd/database/migrations/000397_experimental_terraform_workspaces.up.sql diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 67dc8279278fa..de7cd416f287d 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -18138,6 +18138,9 @@ const docTemplate = `{ }, "use_classic_parameter_flow": { "type": "boolean" + }, + "use_terraform_workspace_cache": { + "type": "boolean" } } }, @@ -19066,6 +19069,10 @@ const docTemplate = `{ "use_classic_parameter_flow": { "description": "UseClassicParameterFlow is a flag that switches the default behavior to use the classic\nparameter flow when creating a workspace. This only affects deployments with the experiment\n\"dynamic-parameters\" enabled. This setting will live for a period after the experiment is\nmade the default.\nAn \"opt-out\" is present in case the new feature breaks some existing templates.", "type": "boolean" + }, + "use_terraform_workspace_cache": { + "description": "UseTerraformWorkspaceCache allows optionally specifying whether to use cached\nterraform directories for workspaces created from this template. This field\nonly applies when the correct experiment is enabled. This field is subject to\nbeing removed in the future.", + "type": "boolean" } } }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 1577e55b8693e..80d705f335f13 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -16613,6 +16613,9 @@ }, "use_classic_parameter_flow": { "type": "boolean" + }, + "use_terraform_workspace_cache": { + "type": "boolean" } } }, @@ -17497,6 +17500,10 @@ "use_classic_parameter_flow": { "description": "UseClassicParameterFlow is a flag that switches the default behavior to use the classic\nparameter flow when creating a workspace. This only affects deployments with the experiment\n\"dynamic-parameters\" enabled. This setting will live for a period after the experiment is\nmade the default.\nAn \"opt-out\" is present in case the new feature breaks some existing templates.", "type": "boolean" + }, + "use_terraform_workspace_cache": { + "description": "UseTerraformWorkspaceCache allows optionally specifying whether to use cached\nterraform directories for workspaces created from this template. This field\nonly applies when the correct experiment is enabled. This field is subject to\nbeing removed in the future.", + "type": "boolean" } } }, diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index fe92992de0727..c2e4091e56c96 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -2286,7 +2286,8 @@ CREATE TABLE templates ( activity_bump bigint DEFAULT '3600000000000'::bigint 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, - cors_behavior cors_behavior DEFAULT 'simple'::cors_behavior NOT NULL + cors_behavior cors_behavior DEFAULT 'simple'::cors_behavior NOT NULL, + use_terraform_workspace_cache boolean DEFAULT false NOT NULL ); COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.'; @@ -2309,6 +2310,8 @@ COMMENT ON COLUMN templates.deprecated IS 'If set to a non empty string, the tem 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.'; +COMMENT ON COLUMN templates.use_terraform_workspace_cache IS 'Determines whether to keep terraform directories cached between runs for workspaces created from this template. When enabled, this can significantly speed up the `terraform init` step at the cost of increased disk usage. This is an opt-in experience, as it prevents modules from being updated, and therefore is a behavioral difference from the default.'; + CREATE VIEW template_with_names AS SELECT templates.id, templates.created_at, @@ -2340,6 +2343,7 @@ CREATE VIEW template_with_names AS templates.max_port_sharing_level, templates.use_classic_parameter_flow, templates.cors_behavior, + templates.use_terraform_workspace_cache, COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url, COALESCE(visible_users.username, ''::text) AS created_by_username, COALESCE(visible_users.name, ''::text) AS created_by_name, diff --git a/coderd/database/migrations/000397_experimental_terraform_workspaces.down.sql b/coderd/database/migrations/000397_experimental_terraform_workspaces.down.sql new file mode 100644 index 0000000000000..394c31975a901 --- /dev/null +++ b/coderd/database/migrations/000397_experimental_terraform_workspaces.down.sql @@ -0,0 +1,26 @@ +DROP VIEW template_with_names; +-- Drop the column +ALTER TABLE templates DROP COLUMN use_terraform_workspace_cache; + +-- Update the template_with_names view by recreating it. +CREATE VIEW template_with_names AS +SELECT + templates.*, + COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url, + COALESCE(visible_users.username, ''::text) AS created_by_username, + COALESCE(visible_users.name, ''::text) AS created_by_name, + COALESCE(organizations.name, ''::text) AS organization_name, + COALESCE(organizations.display_name, ''::text) AS organization_display_name, + COALESCE(organizations.icon, ''::text) 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.'; diff --git a/coderd/database/migrations/000397_experimental_terraform_workspaces.up.sql b/coderd/database/migrations/000397_experimental_terraform_workspaces.up.sql new file mode 100644 index 0000000000000..3b6a57e01b5ef --- /dev/null +++ b/coderd/database/migrations/000397_experimental_terraform_workspaces.up.sql @@ -0,0 +1,33 @@ +-- Default to `false`. Users will have to manually opt into the terraform workspace cache feature. +ALTER TABLE templates ADD COLUMN use_terraform_workspace_cache BOOL NOT NULL DEFAULT false; + +COMMENT ON COLUMN templates.use_terraform_workspace_cache IS + 'Determines whether to keep terraform directories cached between runs for workspaces created from this template. ' + 'When enabled, this can significantly speed up the `terraform init` step at the cost of increased disk usage. ' + 'This is an opt-in experience, as it prevents modules from being updated, and therefore is a behavioral difference ' + 'from the default.'; + ; + +-- 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, ''::text) AS created_by_avatar_url, + COALESCE(visible_users.username, ''::text) AS created_by_username, + COALESCE(visible_users.name, ''::text) AS created_by_name, + COALESCE(organizations.name, ''::text) AS organization_name, + COALESCE(organizations.display_name, ''::text) AS organization_display_name, + COALESCE(organizations.icon, ''::text) 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.'; diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go index eec69671c90ab..fae0f3eca4fa4 100644 --- a/coderd/database/modelqueries.go +++ b/coderd/database/modelqueries.go @@ -127,6 +127,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate &i.MaxPortSharingLevel, &i.UseClassicParameterFlow, &i.CorsBehavior, + &i.UseTerraformWorkspaceCache, &i.CreatedByAvatarURL, &i.CreatedByUsername, &i.CreatedByName, diff --git a/coderd/database/models.go b/coderd/database/models.go index 961d62d52e2b3..5cce4d95aa7f5 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -4294,6 +4294,7 @@ type Template struct { MaxPortSharingLevel AppSharingLevel `db:"max_port_sharing_level" json:"max_port_sharing_level"` UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"` CorsBehavior CorsBehavior `db:"cors_behavior" json:"cors_behavior"` + UseTerraformWorkspaceCache bool `db:"use_terraform_workspace_cache" json:"use_terraform_workspace_cache"` CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"` CreatedByUsername string `db:"created_by_username" json:"created_by_username"` CreatedByName string `db:"created_by_name" json:"created_by_name"` @@ -4343,6 +4344,8 @@ type TemplateTable struct { // 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"` CorsBehavior CorsBehavior `db:"cors_behavior" json:"cors_behavior"` + // Determines whether to keep terraform directories cached between runs for workspaces created from this template. When enabled, this can significantly speed up the `terraform init` step at the cost of increased disk usage. This is an opt-in experience, as it prevents modules from being updated, and therefore is a behavioral difference from the default. + UseTerraformWorkspaceCache bool `db:"use_terraform_workspace_cache" json:"use_terraform_workspace_cache"` } // Records aggregated usage statistics for templates/users. All usage is rounded up to the nearest minute. diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 0f761697d3d43..4e8f3d36b2bc7 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -13522,7 +13522,7 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, templateID 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, use_classic_parameter_flow, cors_behavior, created_by_avatar_url, created_by_username, created_by_name, 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, cors_behavior, use_terraform_workspace_cache, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon FROM template_with_names WHERE @@ -13565,6 +13565,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat &i.MaxPortSharingLevel, &i.UseClassicParameterFlow, &i.CorsBehavior, + &i.UseTerraformWorkspaceCache, &i.CreatedByAvatarURL, &i.CreatedByUsername, &i.CreatedByName, @@ -13577,7 +13578,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, use_classic_parameter_flow, cors_behavior, created_by_avatar_url, created_by_username, created_by_name, 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, cors_behavior, use_terraform_workspace_cache, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates WHERE @@ -13628,6 +13629,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G &i.MaxPortSharingLevel, &i.UseClassicParameterFlow, &i.CorsBehavior, + &i.UseTerraformWorkspaceCache, &i.CreatedByAvatarURL, &i.CreatedByUsername, &i.CreatedByName, @@ -13639,7 +13641,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, use_classic_parameter_flow, cors_behavior, created_by_avatar_url, created_by_username, created_by_name, 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, cors_behavior, use_terraform_workspace_cache, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates ORDER BY (name, id) ASC ` @@ -13683,6 +13685,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) { &i.MaxPortSharingLevel, &i.UseClassicParameterFlow, &i.CorsBehavior, + &i.UseTerraformWorkspaceCache, &i.CreatedByAvatarURL, &i.CreatedByUsername, &i.CreatedByName, @@ -13705,7 +13708,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) { const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many SELECT - t.id, t.created_at, t.updated_at, t.organization_id, t.deleted, t.name, t.provisioner, t.active_version_id, t.description, t.default_ttl, t.created_by, t.icon, t.user_acl, t.group_acl, t.display_name, t.allow_user_cancel_workspace_jobs, t.allow_user_autostart, t.allow_user_autostop, t.failure_ttl, t.time_til_dormant, t.time_til_dormant_autodelete, t.autostop_requirement_days_of_week, t.autostop_requirement_weeks, t.autostart_block_days_of_week, t.require_active_version, t.deprecated, t.activity_bump, t.max_port_sharing_level, t.use_classic_parameter_flow, t.cors_behavior, t.created_by_avatar_url, t.created_by_username, t.created_by_name, t.organization_name, t.organization_display_name, t.organization_icon + t.id, t.created_at, t.updated_at, t.organization_id, t.deleted, t.name, t.provisioner, t.active_version_id, t.description, t.default_ttl, t.created_by, t.icon, t.user_acl, t.group_acl, t.display_name, t.allow_user_cancel_workspace_jobs, t.allow_user_autostart, t.allow_user_autostop, t.failure_ttl, t.time_til_dormant, t.time_til_dormant_autodelete, t.autostop_requirement_days_of_week, t.autostop_requirement_weeks, t.autostart_block_days_of_week, t.require_active_version, t.deprecated, t.activity_bump, t.max_port_sharing_level, t.use_classic_parameter_flow, t.cors_behavior, t.use_terraform_workspace_cache, t.created_by_avatar_url, t.created_by_username, t.created_by_name, t.organization_name, t.organization_display_name, t.organization_icon FROM template_with_names AS t LEFT JOIN @@ -13864,6 +13867,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate &i.MaxPortSharingLevel, &i.UseClassicParameterFlow, &i.CorsBehavior, + &i.UseTerraformWorkspaceCache, &i.CreatedByAvatarURL, &i.CreatedByUsername, &i.CreatedByName, @@ -14049,7 +14053,8 @@ SET group_acl = $8, max_port_sharing_level = $9, use_classic_parameter_flow = $10, - cors_behavior = $11 + cors_behavior = $11, + use_terraform_workspace_cache = $12 WHERE id = $1 ` @@ -14066,6 +14071,7 @@ type UpdateTemplateMetaByIDParams struct { MaxPortSharingLevel AppSharingLevel `db:"max_port_sharing_level" json:"max_port_sharing_level"` UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"` CorsBehavior CorsBehavior `db:"cors_behavior" json:"cors_behavior"` + UseTerraformWorkspaceCache bool `db:"use_terraform_workspace_cache" json:"use_terraform_workspace_cache"` } func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error { @@ -14081,6 +14087,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl arg.MaxPortSharingLevel, arg.UseClassicParameterFlow, arg.CorsBehavior, + arg.UseTerraformWorkspaceCache, ) return err } @@ -22370,7 +22377,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, use_classic_parameter_flow, cors_behavior + 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, cors_behavior, use_terraform_workspace_cache FROM templates WHERE diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql index 43f1aea6c561f..4de4e2fadbebd 100644 --- a/coderd/database/queries/templates.sql +++ b/coderd/database/queries/templates.sql @@ -173,7 +173,8 @@ SET group_acl = $8, max_port_sharing_level = $9, use_classic_parameter_flow = $10, - cors_behavior = $11 + cors_behavior = $11, + use_terraform_workspace_cache = $12 WHERE id = $1 ; diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index ce58d90468026..5ea01afcac829 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -711,7 +711,10 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo ExternalAuthProviders: externalAuthProviders, // If active and experiment is enabled, allow workspace reuse existing TF // workspaces (directories) for a faster startup. - ExpReuseTerraformWorkspace: ptr.Ref(activeVersion && s.Experiments.Enabled(codersdk.ExperimentTerraformWorkspace)), + ExpReuseTerraformWorkspace: ptr.Ref(s.Experiments.Enabled(codersdk.ExperimentTerraformWorkspace) && // Experiment required + template.UseTerraformWorkspaceCache && // Template setting + activeVersion, // Only for active versions + ), Metadata: &sdkproto.Metadata{ CoderUrl: s.AccessURL.String(), WorkspaceTransition: transition, diff --git a/coderd/templates.go b/coderd/templates.go index c93d0debf06e7..39892aa5fef8c 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -773,6 +773,11 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { classicTemplateFlow = *req.UseClassicParameterFlow } + useTerraformWorkspaceCache := template.UseTerraformWorkspaceCache + if req.UseTerraformWorkspaceCache != nil { + useTerraformWorkspaceCache = *req.UseTerraformWorkspaceCache + } + displayName := ptr.NilToDefault(req.DisplayName, template.DisplayName) description := ptr.NilToDefault(req.Description, template.Description) icon := ptr.NilToDefault(req.Icon, template.Icon) @@ -798,7 +803,8 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { (deprecationMessage == template.Deprecated) && (classicTemplateFlow == template.UseClassicParameterFlow) && maxPortShareLevel == template.MaxPortSharingLevel && - corsBehavior == template.CorsBehavior { + corsBehavior == template.CorsBehavior && + useTerraformWorkspaceCache == template.UseTerraformWorkspaceCache { return nil } @@ -841,6 +847,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { MaxPortSharingLevel: maxPortShareLevel, UseClassicParameterFlow: classicTemplateFlow, CorsBehavior: corsBehavior, + UseTerraformWorkspaceCache: useTerraformWorkspaceCache, }) if err != nil { return xerrors.Errorf("update template metadata: %w", err) @@ -1119,12 +1126,13 @@ func (api *API) convertTemplate( DaysOfWeek: codersdk.BitmapToWeekdays(template.AutostartAllowedDays()), }, // These values depend on entitlements and come from the templateAccessControl - RequireActiveVersion: templateAccessControl.RequireActiveVersion, - Deprecated: templateAccessControl.IsDeprecated(), - DeprecationMessage: templateAccessControl.Deprecated, - MaxPortShareLevel: maxPortShareLevel, - UseClassicParameterFlow: template.UseClassicParameterFlow, - CORSBehavior: codersdk.CORSBehavior(template.CorsBehavior), + RequireActiveVersion: templateAccessControl.RequireActiveVersion, + Deprecated: templateAccessControl.IsDeprecated(), + DeprecationMessage: templateAccessControl.Deprecated, + MaxPortShareLevel: maxPortShareLevel, + UseClassicParameterFlow: template.UseClassicParameterFlow, + UseTerraformWorkspaceCache: template.UseTerraformWorkspaceCache, + CORSBehavior: codersdk.CORSBehavior(template.CorsBehavior), } } diff --git a/codersdk/templates.go b/codersdk/templates.go index 49c1f9e7c57f9..a96dcb495dad8 100644 --- a/codersdk/templates.go +++ b/codersdk/templates.go @@ -63,7 +63,8 @@ type Template struct { MaxPortShareLevel WorkspaceAgentPortShareLevel `json:"max_port_share_level"` CORSBehavior CORSBehavior `json:"cors_behavior"` - UseClassicParameterFlow bool `json:"use_classic_parameter_flow"` + UseClassicParameterFlow bool `json:"use_classic_parameter_flow"` + UseTerraformWorkspaceCache bool `json:"use_terraform_workspace_cache"` } // WeekdaysToBitmap converts a list of weekdays to a bitmap in accordance with @@ -263,6 +264,11 @@ type UpdateTemplateMeta struct { // 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"` + // UseTerraformWorkspaceCache allows optionally specifying whether to use cached + // terraform directories for workspaces created from this template. This field + // only applies when the correct experiment is enabled. This field is subject to + // being removed in the future. + UseTerraformWorkspaceCache *bool `json:"use_terraform_workspace_cache,omitempty"` } type TemplateExample struct { diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index e466abaa6fba0..0f43255ad60c7 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -8119,7 +8119,8 @@ Only certain features set these fields: - FeatureManagedAgentLimit| "time_til_dormant_autodelete_ms": 0, "time_til_dormant_ms": 0, "updated_at": "2019-08-24T14:15:22Z", - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ``` @@ -8160,6 +8161,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit| | `time_til_dormant_ms` | integer | false | | | | `updated_at` | string | false | | | | `use_classic_parameter_flow` | boolean | false | | | +| `use_terraform_workspace_cache` | boolean | false | | | #### Enumerated Values @@ -9211,7 +9213,8 @@ Restarts will only happen on weekdays in this list on weeks which line up with W "time_til_dormant_ms": 0, "update_workspace_dormant_at": true, "update_workspace_last_used_at": true, - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ``` @@ -9241,6 +9244,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W | `update_workspace_dormant_at` | boolean | false | | Update workspace dormant at updates the dormant_at field of workspaces spawned from the template. This is useful for preventing dormant workspaces being immediately deleted when updating the dormant_ttl field to a new, shorter value. | | `update_workspace_last_used_at` | boolean | false | | Update workspace last used at updates the last_used_at field of workspaces spawned from the template. This is useful for preventing workspaces being immediately locked when updating the inactivity_ttl field to a new, shorter value. | | `use_classic_parameter_flow` | boolean | false | | Use classic parameter flow 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. | +| `use_terraform_workspace_cache` | boolean | false | | Use terraform workspace cache allows optionally specifying whether to use cached terraform directories for workspaces created from this template. This field only applies when the correct experiment is enabled. This field is subject to being removed in the future. | ## codersdk.UpdateUserAppearanceSettingsRequest diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md index 2c516f4788b4d..7849b79957006 100644 --- a/docs/reference/api/templates.md +++ b/docs/reference/api/templates.md @@ -80,7 +80,8 @@ To include deprecated templates, specify `deprecated:true` in the search query. "time_til_dormant_autodelete_ms": 0, "time_til_dormant_ms": 0, "updated_at": "2019-08-24T14:15:22Z", - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ] ``` @@ -138,6 +139,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W |`» time_til_dormant_ms`|integer|false||| |`» updated_at`|string(date-time)|false||| |`» use_classic_parameter_flow`|boolean|false||| +|`» use_terraform_workspace_cache`|boolean|false||| #### Enumerated Values @@ -266,7 +268,8 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa "time_til_dormant_autodelete_ms": 0, "time_til_dormant_ms": 0, "updated_at": "2019-08-24T14:15:22Z", - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ``` @@ -416,7 +419,8 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat "time_til_dormant_autodelete_ms": 0, "time_til_dormant_ms": 0, "updated_at": "2019-08-24T14:15:22Z", - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ``` @@ -832,7 +836,8 @@ To include deprecated templates, specify `deprecated:true` in the search query. "time_til_dormant_autodelete_ms": 0, "time_til_dormant_ms": 0, "updated_at": "2019-08-24T14:15:22Z", - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ] ``` @@ -890,6 +895,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W |`» time_til_dormant_ms`|integer|false||| |`» updated_at`|string(date-time)|false||| |`» use_classic_parameter_flow`|boolean|false||| +|`» use_terraform_workspace_cache`|boolean|false||| #### Enumerated Values @@ -1036,7 +1042,8 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template} \ "time_til_dormant_autodelete_ms": 0, "time_til_dormant_ms": 0, "updated_at": "2019-08-24T14:15:22Z", - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ``` @@ -1140,7 +1147,8 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \ "time_til_dormant_ms": 0, "update_workspace_dormant_at": true, "update_workspace_last_used_at": true, - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ``` @@ -1207,7 +1215,8 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \ "time_til_dormant_autodelete_ms": 0, "time_til_dormant_ms": 0, "updated_at": "2019-08-24T14:15:22Z", - "use_classic_parameter_flow": true + "use_classic_parameter_flow": true, + "use_terraform_workspace_cache": true } ``` diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index e09f0b5876268..e5661687a1ddb 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -117,6 +117,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "activity_bump": ActionTrack, "use_classic_parameter_flow": ActionTrack, "cors_behavior": ActionTrack, + "use_terraform_workspace_cache": ActionTrack, }, &database.TemplateVersion{}: { "id": ActionTrack, diff --git a/provisionersdk/tfpath/x/tfpath.go b/provisionersdk/tfpath/x/tfpath.go index bc91315324158..c6b9f5d669e94 100644 --- a/provisionersdk/tfpath/x/tfpath.go +++ b/provisionersdk/tfpath/x/tfpath.go @@ -1,7 +1,7 @@ package x // This file will replace the `tfpath.go` in the parent `tfpath` package when the -// `terraform-workspace` experiment is graduated. +// `terraform-directory-reuse` experiment is graduated. import ( "archive/tar" diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index ea65957316e53..c2c94aa314b3d 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -4922,6 +4922,7 @@ export interface Template { readonly max_port_share_level: WorkspaceAgentPortShareLevel; readonly cors_behavior: CORSBehavior; readonly use_classic_parameter_flow: boolean; + readonly use_terraform_workspace_cache: boolean; } // From codersdk/templates.go @@ -5443,6 +5444,13 @@ export interface UpdateTemplateMeta { * An "opt-out" is present in case the new feature breaks some existing templates. */ readonly use_classic_parameter_flow?: boolean; + /** + * UseTerraformWorkspaceCache allows optionally specifying whether to use cached + * terraform directories for workspaces created from this template. This field + * only applies when the correct experiment is enabled. This field is subject to + * being removed in the future. + */ + readonly use_terraform_workspace_cache?: boolean; } // From codersdk/users.go diff --git a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx index 5b35b5ba26f14..e1ed15d198a0e 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx @@ -26,6 +26,7 @@ import { StackLabelHelperText, } from "components/StackLabel/StackLabel"; import { type FormikTouched, useFormik } from "formik"; +import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; import { docs } from "utils/docs"; import { @@ -96,12 +97,14 @@ export const TemplateSettingsForm: FC = ({ max_port_share_level: template.max_port_share_level, use_classic_parameter_flow: template.use_classic_parameter_flow, cors_behavior: template.cors_behavior, + use_terraform_workspace_cache: template.use_terraform_workspace_cache, }, validationSchema, onSubmit, initialTouched, }); const getFieldHelpers = getFormHelpers(form, error); + const { experiments } = useDashboard(); return ( = ({ } /> + {experiments.includes("terraform-directory-reuse") && ( + + } + label={ + + + Enable Terraform directory caching on provisioners + + +
+ When enabled, the provisioner reuses the .terraform + directory for all workspace builds using the active + version. This significantly reduces Terraform init time by + caching module and provider downloads.{" "} + + Unpinned modules may cause inconsistent builds between + provisioners. + +
+
+
+ } + /> + )} diff --git a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.jest.tsx b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.jest.tsx index 2ed53059665bf..f9ac0553f90f4 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.jest.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.jest.tsx @@ -56,6 +56,7 @@ const validFormValues: FormValues = { max_port_share_level: "owner", use_classic_parameter_flow: true, cors_behavior: "simple", + use_terraform_workspace_cache: false, }; const renderTemplateSettingsPage = async () => { diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 03d108b859648..5df216d769e21 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -855,6 +855,7 @@ export const MockTemplate: TypesGen.Template = { max_port_share_level: "public", use_classic_parameter_flow: false, cors_behavior: "simple", + use_terraform_workspace_cache: false, }; const _MockTemplateVersionFiles: TemplateVersionFiles = { From 0ddd796d4b9047b234c65932a4132dcaf13af391 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 13 Nov 2025 18:27:55 +0000 Subject: [PATCH 2/2] make gen --- docs/admin/security/audit-logs.md | 52 +++++++++---------- .../TemplateSettingsPageView.stories.tsx | 2 + 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index a5b12f4e87449..381bb61ddbce1 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -13,32 +13,32 @@ We track the following resources: -| Resource | | | -|----------------------------------------------------------|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| APIKey
login, logout, register, create, delete | |
FieldTracked
allow_listfalse
created_attrue
expires_attrue
hashed_secretfalse
idfalse
ip_addressfalse
last_usedtrue
lifetime_secondsfalse
login_typefalse
scopesfalse
token_namefalse
updated_atfalse
user_idtrue
| -| AuditOAuthConvertState
| |
FieldTracked
created_attrue
expires_attrue
from_login_typetrue
to_login_typetrue
user_idtrue
| -| Group
create, write, delete | |
FieldTracked
avatar_urltrue
display_nametrue
idtrue
memberstrue
nametrue
organization_idfalse
quota_allowancetrue
sourcefalse
| -| AuditableOrganizationMember
| |
FieldTracked
created_attrue
organization_idfalse
rolestrue
updated_attrue
user_idtrue
usernametrue
| -| CustomRole
| |
FieldTracked
created_atfalse
display_nametrue
idfalse
nametrue
org_permissionstrue
organization_idfalse
site_permissionstrue
updated_atfalse
user_permissionstrue
| -| GitSSHKey
create | |
FieldTracked
created_atfalse
private_keytrue
public_keytrue
updated_atfalse
user_idtrue
| -| GroupSyncSettings
| |
FieldTracked
auto_create_missing_groupstrue
fieldtrue
legacy_group_name_mappingfalse
mappingtrue
regex_filtertrue
| -| HealthSettings
| |
FieldTracked
dismissed_healthcheckstrue
idfalse
| -| License
create, delete | |
FieldTracked
exptrue
idfalse
jwtfalse
uploaded_attrue
uuidtrue
| -| NotificationTemplate
| |
FieldTracked
actionstrue
body_templatetrue
enabled_by_defaulttrue
grouptrue
idfalse
kindtrue
methodtrue
nametrue
title_templatetrue
| -| NotificationsSettings
| |
FieldTracked
idfalse
notifier_pausedtrue
| -| OAuth2ProviderApp
| |
FieldTracked
callback_urltrue
client_id_issued_atfalse
client_secret_expires_attrue
client_typetrue
client_uritrue
contactstrue
created_atfalse
dynamically_registeredtrue
grant_typestrue
icontrue
idfalse
jwkstrue
jwks_uritrue
logo_uritrue
nametrue
policy_uritrue
redirect_uristrue
registration_access_tokentrue
registration_client_uritrue
response_typestrue
scopetrue
software_idtrue
software_versiontrue
token_endpoint_auth_methodtrue
tos_uritrue
updated_atfalse
| -| OAuth2ProviderAppSecret
| |
FieldTracked
app_idfalse
created_atfalse
display_secretfalse
hashed_secretfalse
idfalse
last_used_atfalse
secret_prefixfalse
| -| Organization
| |
FieldTracked
created_atfalse
deletedtrue
descriptiontrue
display_nametrue
icontrue
idfalse
is_defaulttrue
nametrue
updated_attrue
| -| OrganizationSyncSettings
| |
FieldTracked
assign_defaulttrue
fieldtrue
mappingtrue
| -| PrebuildsSettings
| |
FieldTracked
idfalse
reconciliation_pausedtrue
| -| RoleSyncSettings
| |
FieldTracked
fieldtrue
mappingtrue
| -| TaskTable
| |
FieldTracked
created_atfalse
deleted_atfalse
idtrue
nametrue
organization_idfalse
owner_idtrue
prompttrue
template_parameterstrue
template_version_idtrue
workspace_idtrue
| -| Template
write, delete | |
FieldTracked
active_version_idtrue
activity_bumptrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
autostart_block_days_of_weektrue
autostop_requirement_days_of_weektrue
autostop_requirement_weekstrue
cors_behaviortrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_namefalse
created_by_usernamefalse
default_ttltrue
deletedfalse
deprecatedtrue
descriptiontrue
display_nametrue
failure_ttltrue
group_acltrue
icontrue
idtrue
max_port_sharing_leveltrue
nametrue
organization_display_namefalse
organization_iconfalse
organization_idfalse
organization_namefalse
provisionertrue
require_active_versiontrue
time_til_dormanttrue
time_til_dormant_autodeletetrue
updated_atfalse
use_classic_parameter_flowtrue
user_acltrue
| -| TemplateVersion
create, write | |
FieldTracked
archivedtrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_namefalse
created_by_usernamefalse
external_auth_providersfalse
has_ai_taskfalse
has_external_agentfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
source_example_idfalse
template_idtrue
updated_atfalse
| -| User
create, write, delete | |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_one_time_passcodefalse
hashed_passwordtrue
idtrue
is_systemtrue
last_seen_atfalse
login_typetrue
nametrue
one_time_passcode_expires_attrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
updated_atfalse
usernametrue
| -| WorkspaceBuild
start, stop | |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
has_ai_taskfalse
has_external_agentfalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_namefalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
template_version_preset_idfalse
transitionfalse
updated_atfalse
workspace_idfalse
| -| WorkspaceProxy
| |
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| -| WorkspaceTable
| |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
group_acltrue
idtrue
last_used_atfalse
nametrue
next_start_attrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
user_acltrue
| +| Resource | | | +|----------------------------------------------------------|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| APIKey
login, logout, register, create, delete | |
FieldTracked
allow_listfalse
created_attrue
expires_attrue
hashed_secretfalse
idfalse
ip_addressfalse
last_usedtrue
lifetime_secondsfalse
login_typefalse
scopesfalse
token_namefalse
updated_atfalse
user_idtrue
| +| AuditOAuthConvertState
| |
FieldTracked
created_attrue
expires_attrue
from_login_typetrue
to_login_typetrue
user_idtrue
| +| Group
create, write, delete | |
FieldTracked
avatar_urltrue
display_nametrue
idtrue
memberstrue
nametrue
organization_idfalse
quota_allowancetrue
sourcefalse
| +| AuditableOrganizationMember
| |
FieldTracked
created_attrue
organization_idfalse
rolestrue
updated_attrue
user_idtrue
usernametrue
| +| CustomRole
| |
FieldTracked
created_atfalse
display_nametrue
idfalse
nametrue
org_permissionstrue
organization_idfalse
site_permissionstrue
updated_atfalse
user_permissionstrue
| +| GitSSHKey
create | |
FieldTracked
created_atfalse
private_keytrue
public_keytrue
updated_atfalse
user_idtrue
| +| GroupSyncSettings
| |
FieldTracked
auto_create_missing_groupstrue
fieldtrue
legacy_group_name_mappingfalse
mappingtrue
regex_filtertrue
| +| HealthSettings
| |
FieldTracked
dismissed_healthcheckstrue
idfalse
| +| License
create, delete | |
FieldTracked
exptrue
idfalse
jwtfalse
uploaded_attrue
uuidtrue
| +| NotificationTemplate
| |
FieldTracked
actionstrue
body_templatetrue
enabled_by_defaulttrue
grouptrue
idfalse
kindtrue
methodtrue
nametrue
title_templatetrue
| +| NotificationsSettings
| |
FieldTracked
idfalse
notifier_pausedtrue
| +| OAuth2ProviderApp
| |
FieldTracked
callback_urltrue
client_id_issued_atfalse
client_secret_expires_attrue
client_typetrue
client_uritrue
contactstrue
created_atfalse
dynamically_registeredtrue
grant_typestrue
icontrue
idfalse
jwkstrue
jwks_uritrue
logo_uritrue
nametrue
policy_uritrue
redirect_uristrue
registration_access_tokentrue
registration_client_uritrue
response_typestrue
scopetrue
software_idtrue
software_versiontrue
token_endpoint_auth_methodtrue
tos_uritrue
updated_atfalse
| +| OAuth2ProviderAppSecret
| |
FieldTracked
app_idfalse
created_atfalse
display_secretfalse
hashed_secretfalse
idfalse
last_used_atfalse
secret_prefixfalse
| +| Organization
| |
FieldTracked
created_atfalse
deletedtrue
descriptiontrue
display_nametrue
icontrue
idfalse
is_defaulttrue
nametrue
updated_attrue
| +| OrganizationSyncSettings
| |
FieldTracked
assign_defaulttrue
fieldtrue
mappingtrue
| +| PrebuildsSettings
| |
FieldTracked
idfalse
reconciliation_pausedtrue
| +| RoleSyncSettings
| |
FieldTracked
fieldtrue
mappingtrue
| +| TaskTable
| |
FieldTracked
created_atfalse
deleted_atfalse
idtrue
nametrue
organization_idfalse
owner_idtrue
prompttrue
template_parameterstrue
template_version_idtrue
workspace_idtrue
| +| Template
write, delete | |
FieldTracked
active_version_idtrue
activity_bumptrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
autostart_block_days_of_weektrue
autostop_requirement_days_of_weektrue
autostop_requirement_weekstrue
cors_behaviortrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_namefalse
created_by_usernamefalse
default_ttltrue
deletedfalse
deprecatedtrue
descriptiontrue
display_nametrue
failure_ttltrue
group_acltrue
icontrue
idtrue
max_port_sharing_leveltrue
nametrue
organization_display_namefalse
organization_iconfalse
organization_idfalse
organization_namefalse
provisionertrue
require_active_versiontrue
time_til_dormanttrue
time_til_dormant_autodeletetrue
updated_atfalse
use_classic_parameter_flowtrue
use_terraform_workspace_cachetrue
user_acltrue
| +| TemplateVersion
create, write | |
FieldTracked
archivedtrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_namefalse
created_by_usernamefalse
external_auth_providersfalse
has_ai_taskfalse
has_external_agentfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
source_example_idfalse
template_idtrue
updated_atfalse
| +| User
create, write, delete | |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_one_time_passcodefalse
hashed_passwordtrue
idtrue
is_systemtrue
last_seen_atfalse
login_typetrue
nametrue
one_time_passcode_expires_attrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
updated_atfalse
usernametrue
| +| WorkspaceBuild
start, stop | |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
has_ai_taskfalse
has_external_agentfalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_namefalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
template_version_preset_idfalse
transitionfalse
updated_atfalse
workspace_idfalse
| +| WorkspaceProxy
| |
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| +| WorkspaceTable
| |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
group_acltrue
idtrue
last_used_atfalse
nametrue
next_start_attrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
user_acltrue
| diff --git a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPageView.stories.tsx b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPageView.stories.tsx index 5d65ffaf15c5a..a17b7cbb31b6c 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPageView.stories.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPageView.stories.tsx @@ -1,4 +1,5 @@ import { MockTemplate, mockApiError } from "testHelpers/entities"; +import { withDashboardProvider } from "testHelpers/storybook"; import type { Meta, StoryObj } from "@storybook/react-vite"; import { action } from "storybook/actions"; import { TemplateSettingsPageView } from "./TemplateSettingsPageView"; @@ -12,6 +13,7 @@ const meta: Meta = { advancedSchedulingEnabled: true, onCancel: action("onCancel"), }, + decorators: [withDashboardProvider], }; export default meta;