From c1a1dce48aeb2cca4753af37e2ea4d4cafaf14eb Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 3 Oct 2023 23:23:33 +0000 Subject: [PATCH 1/5] chore: remove workspace_actions experiment --- codersdk/deployment.go | 3 --- .../components/Dashboard/DashboardProvider.tsx | 5 ++--- .../WorkspaceDeletion/DormantDeletionStat.tsx | 11 +---------- .../WorkspaceDeletion/DormantDeletionText.tsx | 13 ++----------- .../components/WorkspaceDeletion/utils.test.ts | 17 ++++------------- site/src/components/WorkspaceDeletion/utils.ts | 7 +------ .../TemplateScheduleForm.tsx | 4 +--- .../TemplateSchedulePage.test.tsx | 3 --- .../TemplateSchedulePage.tsx | 4 +--- .../TemplateSchedulePageView.tsx | 3 --- site/src/testHelpers/entities.ts | 5 +---- 11 files changed, 13 insertions(+), 62 deletions(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 057d26cd30e84..2bacc4fa84678 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -1958,9 +1958,6 @@ const ( // feature is not yet complete in functionality. ExperimentMoons Experiment = "moons" - // https://github.com/coder/coder/milestone/19 - ExperimentWorkspaceActions Experiment = "workspace_actions" - // ExperimentTailnetPGCoordinator enables the PGCoord in favor of the pubsub- // only Coordinator ExperimentTailnetPGCoordinator Experiment = "tailnet_pg_coordinator" diff --git a/site/src/components/Dashboard/DashboardProvider.tsx b/site/src/components/Dashboard/DashboardProvider.tsx index e1b54165e7128..ed0f76db3342d 100644 --- a/site/src/components/Dashboard/DashboardProvider.tsx +++ b/site/src/components/Dashboard/DashboardProvider.tsx @@ -112,11 +112,10 @@ export const useDashboard = (): DashboardProviderValue => { }; export const useIsWorkspaceActionsEnabled = (): boolean => { - const { entitlements, experiments } = useDashboard(); + const { entitlements } = useDashboard(); const allowAdvancedScheduling = entitlements.features["advanced_template_scheduling"].enabled; // This check can be removed when https://github.com/coder/coder/milestone/19 // is merged up - const allowWorkspaceActions = experiments.includes("workspace_actions"); - return allowWorkspaceActions && allowAdvancedScheduling; + return allowAdvancedScheduling; }; diff --git a/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx b/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx index 8dc7a289d21f9..ba1863cbb4ad5 100644 --- a/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx +++ b/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx @@ -17,17 +17,8 @@ export const DormantDeletionStat: FC = ({ const { entitlements, experiments } = useDashboard(); const allowAdvancedScheduling = entitlements.features["advanced_template_scheduling"].enabled; - // This check can be removed when https://github.com/coder/coder/milestone/19 - // is merged up - const allowWorkspaceActions = experiments.includes("workspace_actions"); - if ( - !displayDormantDeletion( - workspace, - allowAdvancedScheduling, - allowWorkspaceActions, - ) - ) { + if (!displayDormantDeletion(workspace, allowAdvancedScheduling)) { return null; } diff --git a/site/src/components/WorkspaceDeletion/DormantDeletionText.tsx b/site/src/components/WorkspaceDeletion/DormantDeletionText.tsx index 0d1b8692674fa..5e7ed87962954 100644 --- a/site/src/components/WorkspaceDeletion/DormantDeletionText.tsx +++ b/site/src/components/WorkspaceDeletion/DormantDeletionText.tsx @@ -9,20 +9,11 @@ export const DormantDeletionText = ({ }: { workspace: Workspace; }): JSX.Element | null => { - const { entitlements, experiments } = useDashboard(); + const { entitlements } = useDashboard(); const allowAdvancedScheduling = entitlements.features["advanced_template_scheduling"].enabled; - // This check can be removed when https://github.com/coder/coder/milestone/19 - // is merged up - const allowWorkspaceActions = experiments.includes("workspace_actions"); - if ( - !displayDormantDeletion( - workspace, - allowAdvancedScheduling, - allowWorkspaceActions, - ) - ) { + if (!displayDormantDeletion(workspace, allowAdvancedScheduling)) { return null; } return Impending deletion; diff --git a/site/src/components/WorkspaceDeletion/utils.test.ts b/site/src/components/WorkspaceDeletion/utils.test.ts index caca6c5661993..9b390c02a9dd1 100644 --- a/site/src/components/WorkspaceDeletion/utils.test.ts +++ b/site/src/components/WorkspaceDeletion/utils.test.ts @@ -34,23 +34,14 @@ describe("displayDormantDeletion", () => { [new Date().toISOString(), true, false, false], // Workspace Actions off ])( `deleting_at=%p, allowAdvancedScheduling=%p, AllowWorkspaceActions=%p, shouldDisplay=%p`, - ( - deleting_at, - allowAdvancedScheduling, - allowWorkspaceActions, - shouldDisplay, - ) => { + (deleting_at, allowAdvancedScheduling, shouldDisplay) => { const workspace: TypesGen.Workspace = { ...Mocks.MockWorkspace, deleting_at, }; - expect( - displayDormantDeletion( - workspace, - allowAdvancedScheduling, - allowWorkspaceActions, - ), - ).toBe(shouldDisplay); + expect(displayDormantDeletion(workspace, allowAdvancedScheduling)).toBe( + shouldDisplay, + ); }, ); }); diff --git a/site/src/components/WorkspaceDeletion/utils.ts b/site/src/components/WorkspaceDeletion/utils.ts index 14ac74f4a00bd..1265647878a82 100644 --- a/site/src/components/WorkspaceDeletion/utils.ts +++ b/site/src/components/WorkspaceDeletion/utils.ts @@ -14,14 +14,9 @@ const IMPENDING_DELETION_DISPLAY_THRESHOLD = 14; // 14 days export const displayDormantDeletion = ( workspace: Workspace, allowAdvancedScheduling: boolean, - allowWorkspaceActions: boolean, ) => { const today = new Date(); - if ( - !workspace.deleting_at || - !allowAdvancedScheduling || - !allowWorkspaceActions - ) { + if (!workspace.deleting_at || !allowAdvancedScheduling) { return false; } return ( diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx index 818ea0657eda3..88c272fe78ced 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx @@ -50,7 +50,6 @@ export interface TemplateScheduleForm { isSubmitting: boolean; error?: unknown; allowAdvancedScheduling: boolean; - allowWorkspaceActions: boolean; allowAutostopRequirement: boolean; // Helpful to show field errors on Storybook initialTouched?: FormikTouched; @@ -62,7 +61,6 @@ export const TemplateScheduleForm: FC = ({ onCancel, error, allowAdvancedScheduling, - allowWorkspaceActions, allowAutostopRequirement, isSubmitting, initialTouched, @@ -459,7 +457,7 @@ export const TemplateScheduleForm: FC = ({ - {allowAdvancedScheduling && allowWorkspaceActions && ( + {allowAdvancedScheduling && ( <> { jest .spyOn(API, "getEntitlements") .mockResolvedValue(MockEntitlementsWithScheduling); - - // remove when https://github.com/coder/coder/milestone/19 is completed. - jest.spyOn(API, "getExperiments").mockResolvedValue(["workspace_actions"]); }); it("Calls the API when user fills in and submits a form", async () => { diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx index 8bdc37ab494fb..ce90c980a07f2 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx @@ -18,12 +18,11 @@ const TemplateSchedulePage: FC = () => { const queryClient = useQueryClient(); const orgId = useOrganizationId(); const { template } = useTemplateSettings(); - const { entitlements, experiments } = useDashboard(); + const { entitlements } = useDashboard(); const allowAdvancedScheduling = entitlements.features["advanced_template_scheduling"].enabled; // This check can be removed when https://github.com/coder/coder/milestone/19 // is merged up - const allowWorkspaceActions = experiments.includes("workspace_actions"); const allowAutostopRequirement = entitlements.features["template_autostop_requirement"].enabled; const { clearLocal } = useLocalStorage(); @@ -54,7 +53,6 @@ const TemplateSchedulePage: FC = () => { ["initialTouched"]; allowAdvancedScheduling: boolean; - allowWorkspaceActions: boolean; allowAutostopRequirement: boolean; } @@ -24,7 +23,6 @@ export const TemplateSchedulePageView: FC = ({ onSubmit, isSubmitting, allowAdvancedScheduling, - allowWorkspaceActions, allowAutostopRequirement, submitError, initialTouched, @@ -39,7 +37,6 @@ export const TemplateSchedulePageView: FC = ({ Date: Tue, 3 Oct 2023 23:31:23 +0000 Subject: [PATCH 2/5] make gen --- cli/templatecreate.go | 10 -- cli/templateedit.go | 12 -- coderd/apidoc/docs.go | 2 - coderd/apidoc/swagger.json | 2 - coderd/database/queries.sql.go | 226 ++++++++++++++++----------------- docs/api/schemas.md | 1 - site/src/api/typesGenerated.ts | 4 +- 7 files changed, 114 insertions(+), 143 deletions(-) diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 2ac9cef963b3a..b2e9a45cc8be8 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -47,16 +47,6 @@ func (r *RootCmd) templateCreate() *clibase.Cmd { ), Handler: func(inv *clibase.Invocation) error { if failureTTL != 0 || inactivityTTL != 0 || maxTTL != 0 { - // This call can be removed when workspace_actions is no longer experimental - experiments, exErr := client.Experiments(inv.Context()) - if exErr != nil { - return xerrors.Errorf("get experiments: %w", exErr) - } - - if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) { - return xerrors.Errorf("--failure-ttl and --inactivityTTL are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.") - } - entitlements, err := client.Entitlements(inv.Context()) var sdkErr *codersdk.Error if xerrors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound { diff --git a/cli/templateedit.go b/cli/templateedit.go index f64d2c5fc4b50..1a62ec531d3af 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -41,18 +41,6 @@ func (r *RootCmd) templateEdit() *clibase.Cmd { ), Short: "Edit the metadata of a template by name.", Handler: func(inv *clibase.Invocation) error { - // This clause can be removed when workspace_actions is no longer experimental - if failureTTL != 0 || inactivityTTL != 0 { - experiments, exErr := client.Experiments(inv.Context()) - if exErr != nil { - return xerrors.Errorf("get experiments: %w", exErr) - } - - if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) { - return xerrors.Errorf("--failure-ttl and --inactivityTTL are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.") - } - } - unsetAutostopRequirementDaysOfWeek := len(autostopRequirementDaysOfWeek) == 1 && autostopRequirementDaysOfWeek[0] == "none" requiresEntitlement := (len(autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) || autostopRequirementWeeks > 0 || diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 759671714f3a4..5913dd9eab3da 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -8171,7 +8171,6 @@ const docTemplate = `{ "type": "string", "enum": [ "moons", - "workspace_actions", "tailnet_pg_coordinator", "single_tailnet", "template_autostop_requirement", @@ -8179,7 +8178,6 @@ const docTemplate = `{ ], "x-enum-varnames": [ "ExperimentMoons", - "ExperimentWorkspaceActions", "ExperimentTailnetPGCoordinator", "ExperimentSingleTailnet", "ExperimentTemplateAutostopRequirement", diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 90272bcbf8349..37b3c5ea66b57 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -7319,7 +7319,6 @@ "type": "string", "enum": [ "moons", - "workspace_actions", "tailnet_pg_coordinator", "single_tailnet", "template_autostop_requirement", @@ -7327,7 +7326,6 @@ ], "x-enum-varnames": [ "ExperimentMoons", - "ExperimentWorkspaceActions", "ExperimentTailnetPGCoordinator", "ExperimentSingleTailnet", "ExperimentTemplateAutostopRequirement", diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index a2949bb542f3d..687a411c9ec84 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -9561,6 +9561,119 @@ func (q *sqlQuerier) InsertWorkspaceResourceMetadata(ctx context.Context, arg In return items, nil } +const getWorkspaceAgentScriptsByAgentIDs = `-- name: GetWorkspaceAgentScriptsByAgentIDs :many +SELECT workspace_agent_id, log_source_id, log_path, created_at, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds FROM workspace_agent_scripts WHERE workspace_agent_id = ANY($1 :: uuid [ ]) +` + +func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgentScript, error) { + rows, err := q.db.QueryContext(ctx, getWorkspaceAgentScriptsByAgentIDs, pq.Array(ids)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WorkspaceAgentScript + for rows.Next() { + var i WorkspaceAgentScript + if err := rows.Scan( + &i.WorkspaceAgentID, + &i.LogSourceID, + &i.LogPath, + &i.CreatedAt, + &i.Script, + &i.Cron, + &i.StartBlocksLogin, + &i.RunOnStart, + &i.RunOnStop, + &i.TimeoutSeconds, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const insertWorkspaceAgentScripts = `-- name: InsertWorkspaceAgentScripts :many +INSERT INTO + workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds) +SELECT + $1 :: uuid AS workspace_agent_id, + $2 :: timestamptz AS created_at, + unnest($3 :: uuid [ ]) AS log_source_id, + unnest($4 :: text [ ]) AS log_path, + unnest($5 :: text [ ]) AS script, + unnest($6 :: text [ ]) AS cron, + unnest($7 :: boolean [ ]) AS start_blocks_login, + unnest($8 :: boolean [ ]) AS run_on_start, + unnest($9 :: boolean [ ]) AS run_on_stop, + unnest($10 :: integer [ ]) AS timeout_seconds +RETURNING workspace_agent_scripts.workspace_agent_id, workspace_agent_scripts.log_source_id, workspace_agent_scripts.log_path, workspace_agent_scripts.created_at, workspace_agent_scripts.script, workspace_agent_scripts.cron, workspace_agent_scripts.start_blocks_login, workspace_agent_scripts.run_on_start, workspace_agent_scripts.run_on_stop, workspace_agent_scripts.timeout_seconds +` + +type InsertWorkspaceAgentScriptsParams struct { + WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + LogSourceID []uuid.UUID `db:"log_source_id" json:"log_source_id"` + LogPath []string `db:"log_path" json:"log_path"` + Script []string `db:"script" json:"script"` + Cron []string `db:"cron" json:"cron"` + StartBlocksLogin []bool `db:"start_blocks_login" json:"start_blocks_login"` + RunOnStart []bool `db:"run_on_start" json:"run_on_start"` + RunOnStop []bool `db:"run_on_stop" json:"run_on_stop"` + TimeoutSeconds []int32 `db:"timeout_seconds" json:"timeout_seconds"` +} + +func (q *sqlQuerier) InsertWorkspaceAgentScripts(ctx context.Context, arg InsertWorkspaceAgentScriptsParams) ([]WorkspaceAgentScript, error) { + rows, err := q.db.QueryContext(ctx, insertWorkspaceAgentScripts, + arg.WorkspaceAgentID, + arg.CreatedAt, + pq.Array(arg.LogSourceID), + pq.Array(arg.LogPath), + pq.Array(arg.Script), + pq.Array(arg.Cron), + pq.Array(arg.StartBlocksLogin), + pq.Array(arg.RunOnStart), + pq.Array(arg.RunOnStop), + pq.Array(arg.TimeoutSeconds), + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WorkspaceAgentScript + for rows.Next() { + var i WorkspaceAgentScript + if err := rows.Scan( + &i.WorkspaceAgentID, + &i.LogSourceID, + &i.LogPath, + &i.CreatedAt, + &i.Script, + &i.Cron, + &i.StartBlocksLogin, + &i.RunOnStart, + &i.RunOnStop, + &i.TimeoutSeconds, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getDeploymentWorkspaceStats = `-- name: GetDeploymentWorkspaceStats :one WITH workspaces_with_jobs AS ( SELECT @@ -10489,116 +10602,3 @@ func (q *sqlQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.C _, err := q.db.ExecContext(ctx, updateWorkspacesDormantDeletingAtByTemplateID, arg.TimeTilDormantAutodeleteMs, arg.DormantAt, arg.TemplateID) return err } - -const getWorkspaceAgentScriptsByAgentIDs = `-- name: GetWorkspaceAgentScriptsByAgentIDs :many -SELECT workspace_agent_id, log_source_id, log_path, created_at, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds FROM workspace_agent_scripts WHERE workspace_agent_id = ANY($1 :: uuid [ ]) -` - -func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgentScript, error) { - rows, err := q.db.QueryContext(ctx, getWorkspaceAgentScriptsByAgentIDs, pq.Array(ids)) - if err != nil { - return nil, err - } - defer rows.Close() - var items []WorkspaceAgentScript - for rows.Next() { - var i WorkspaceAgentScript - if err := rows.Scan( - &i.WorkspaceAgentID, - &i.LogSourceID, - &i.LogPath, - &i.CreatedAt, - &i.Script, - &i.Cron, - &i.StartBlocksLogin, - &i.RunOnStart, - &i.RunOnStop, - &i.TimeoutSeconds, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const insertWorkspaceAgentScripts = `-- name: InsertWorkspaceAgentScripts :many -INSERT INTO - workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds) -SELECT - $1 :: uuid AS workspace_agent_id, - $2 :: timestamptz AS created_at, - unnest($3 :: uuid [ ]) AS log_source_id, - unnest($4 :: text [ ]) AS log_path, - unnest($5 :: text [ ]) AS script, - unnest($6 :: text [ ]) AS cron, - unnest($7 :: boolean [ ]) AS start_blocks_login, - unnest($8 :: boolean [ ]) AS run_on_start, - unnest($9 :: boolean [ ]) AS run_on_stop, - unnest($10 :: integer [ ]) AS timeout_seconds -RETURNING workspace_agent_scripts.workspace_agent_id, workspace_agent_scripts.log_source_id, workspace_agent_scripts.log_path, workspace_agent_scripts.created_at, workspace_agent_scripts.script, workspace_agent_scripts.cron, workspace_agent_scripts.start_blocks_login, workspace_agent_scripts.run_on_start, workspace_agent_scripts.run_on_stop, workspace_agent_scripts.timeout_seconds -` - -type InsertWorkspaceAgentScriptsParams struct { - WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - LogSourceID []uuid.UUID `db:"log_source_id" json:"log_source_id"` - LogPath []string `db:"log_path" json:"log_path"` - Script []string `db:"script" json:"script"` - Cron []string `db:"cron" json:"cron"` - StartBlocksLogin []bool `db:"start_blocks_login" json:"start_blocks_login"` - RunOnStart []bool `db:"run_on_start" json:"run_on_start"` - RunOnStop []bool `db:"run_on_stop" json:"run_on_stop"` - TimeoutSeconds []int32 `db:"timeout_seconds" json:"timeout_seconds"` -} - -func (q *sqlQuerier) InsertWorkspaceAgentScripts(ctx context.Context, arg InsertWorkspaceAgentScriptsParams) ([]WorkspaceAgentScript, error) { - rows, err := q.db.QueryContext(ctx, insertWorkspaceAgentScripts, - arg.WorkspaceAgentID, - arg.CreatedAt, - pq.Array(arg.LogSourceID), - pq.Array(arg.LogPath), - pq.Array(arg.Script), - pq.Array(arg.Cron), - pq.Array(arg.StartBlocksLogin), - pq.Array(arg.RunOnStart), - pq.Array(arg.RunOnStop), - pq.Array(arg.TimeoutSeconds), - ) - if err != nil { - return nil, err - } - defer rows.Close() - var items []WorkspaceAgentScript - for rows.Next() { - var i WorkspaceAgentScript - if err := rows.Scan( - &i.WorkspaceAgentID, - &i.LogSourceID, - &i.LogPath, - &i.CreatedAt, - &i.Script, - &i.Cron, - &i.StartBlocksLogin, - &i.RunOnStart, - &i.RunOnStop, - &i.TimeoutSeconds, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} diff --git a/docs/api/schemas.md b/docs/api/schemas.md index e02b0f818d76b..93b14beab75c2 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -2752,7 +2752,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | Value | | ------------------------------- | | `moons` | -| `workspace_actions` | | `tailnet_pg_coordinator` | | `single_tailnet` | | `template_autostop_requirement` | diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 6f9dc91527652..401485d55078a 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1662,15 +1662,13 @@ export type Experiment = | "moons" | "single_tailnet" | "tailnet_pg_coordinator" - | "template_autostop_requirement" - | "workspace_actions"; + | "template_autostop_requirement"; export const Experiments: Experiment[] = [ "deployment_health_page", "moons", "single_tailnet", "tailnet_pg_coordinator", "template_autostop_requirement", - "workspace_actions", ]; // From codersdk/deployment.go From 06028294199eb1af82bc2070d904457e597c75b1 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 3 Oct 2023 23:34:43 +0000 Subject: [PATCH 3/5] a test --- site/src/components/WorkspaceDeletion/utils.test.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/site/src/components/WorkspaceDeletion/utils.test.ts b/site/src/components/WorkspaceDeletion/utils.test.ts index 9b390c02a9dd1..87d32de1f832e 100644 --- a/site/src/components/WorkspaceDeletion/utils.test.ts +++ b/site/src/components/WorkspaceDeletion/utils.test.ts @@ -4,36 +4,31 @@ import { displayDormantDeletion } from "./utils"; describe("displayDormantDeletion", () => { const today = new Date(); - it.each<[string, boolean, boolean, boolean]>([ + it.each<[string, boolean, boolean]>([ [ new Date(new Date().setDate(today.getDate() + 15)).toISOString(), true, - true, false, ], // today + 15 days out [ new Date(new Date().setDate(today.getDate() + 14)).toISOString(), true, true, - true, ], // today + 14 [ new Date(new Date().setDate(today.getDate() + 13)).toISOString(), true, true, - true, ], // today + 13 [ new Date(new Date().setDate(today.getDate() + 1)).toISOString(), true, true, - true, ], // today + 1 - [new Date().toISOString(), true, true, true], // today + 0 - [new Date().toISOString(), false, true, false], // Advanced Scheduling off - [new Date().toISOString(), true, false, false], // Workspace Actions off + [new Date().toISOString(), true, true], // today + 0 + [new Date().toISOString(), false, false], // Advanced Scheduling off ])( - `deleting_at=%p, allowAdvancedScheduling=%p, AllowWorkspaceActions=%p, shouldDisplay=%p`, + `deleting_at=%p, allowAdvancedScheduling=%p, shouldDisplay=%p`, (deleting_at, allowAdvancedScheduling, shouldDisplay) => { const workspace: TypesGen.Workspace = { ...Mocks.MockWorkspace, From a45ec9eb1179de1230b478b93ffa6bd8a08bac1c Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 3 Oct 2023 23:41:26 +0000 Subject: [PATCH 4/5] make lint --- coderd/database/queries.sql.go | 226 +++++++++--------- .../WorkspaceDeletion/DormantDeletionStat.tsx | 2 +- 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 687a411c9ec84..a2949bb542f3d 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -9561,119 +9561,6 @@ func (q *sqlQuerier) InsertWorkspaceResourceMetadata(ctx context.Context, arg In return items, nil } -const getWorkspaceAgentScriptsByAgentIDs = `-- name: GetWorkspaceAgentScriptsByAgentIDs :many -SELECT workspace_agent_id, log_source_id, log_path, created_at, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds FROM workspace_agent_scripts WHERE workspace_agent_id = ANY($1 :: uuid [ ]) -` - -func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgentScript, error) { - rows, err := q.db.QueryContext(ctx, getWorkspaceAgentScriptsByAgentIDs, pq.Array(ids)) - if err != nil { - return nil, err - } - defer rows.Close() - var items []WorkspaceAgentScript - for rows.Next() { - var i WorkspaceAgentScript - if err := rows.Scan( - &i.WorkspaceAgentID, - &i.LogSourceID, - &i.LogPath, - &i.CreatedAt, - &i.Script, - &i.Cron, - &i.StartBlocksLogin, - &i.RunOnStart, - &i.RunOnStop, - &i.TimeoutSeconds, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const insertWorkspaceAgentScripts = `-- name: InsertWorkspaceAgentScripts :many -INSERT INTO - workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds) -SELECT - $1 :: uuid AS workspace_agent_id, - $2 :: timestamptz AS created_at, - unnest($3 :: uuid [ ]) AS log_source_id, - unnest($4 :: text [ ]) AS log_path, - unnest($5 :: text [ ]) AS script, - unnest($6 :: text [ ]) AS cron, - unnest($7 :: boolean [ ]) AS start_blocks_login, - unnest($8 :: boolean [ ]) AS run_on_start, - unnest($9 :: boolean [ ]) AS run_on_stop, - unnest($10 :: integer [ ]) AS timeout_seconds -RETURNING workspace_agent_scripts.workspace_agent_id, workspace_agent_scripts.log_source_id, workspace_agent_scripts.log_path, workspace_agent_scripts.created_at, workspace_agent_scripts.script, workspace_agent_scripts.cron, workspace_agent_scripts.start_blocks_login, workspace_agent_scripts.run_on_start, workspace_agent_scripts.run_on_stop, workspace_agent_scripts.timeout_seconds -` - -type InsertWorkspaceAgentScriptsParams struct { - WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - LogSourceID []uuid.UUID `db:"log_source_id" json:"log_source_id"` - LogPath []string `db:"log_path" json:"log_path"` - Script []string `db:"script" json:"script"` - Cron []string `db:"cron" json:"cron"` - StartBlocksLogin []bool `db:"start_blocks_login" json:"start_blocks_login"` - RunOnStart []bool `db:"run_on_start" json:"run_on_start"` - RunOnStop []bool `db:"run_on_stop" json:"run_on_stop"` - TimeoutSeconds []int32 `db:"timeout_seconds" json:"timeout_seconds"` -} - -func (q *sqlQuerier) InsertWorkspaceAgentScripts(ctx context.Context, arg InsertWorkspaceAgentScriptsParams) ([]WorkspaceAgentScript, error) { - rows, err := q.db.QueryContext(ctx, insertWorkspaceAgentScripts, - arg.WorkspaceAgentID, - arg.CreatedAt, - pq.Array(arg.LogSourceID), - pq.Array(arg.LogPath), - pq.Array(arg.Script), - pq.Array(arg.Cron), - pq.Array(arg.StartBlocksLogin), - pq.Array(arg.RunOnStart), - pq.Array(arg.RunOnStop), - pq.Array(arg.TimeoutSeconds), - ) - if err != nil { - return nil, err - } - defer rows.Close() - var items []WorkspaceAgentScript - for rows.Next() { - var i WorkspaceAgentScript - if err := rows.Scan( - &i.WorkspaceAgentID, - &i.LogSourceID, - &i.LogPath, - &i.CreatedAt, - &i.Script, - &i.Cron, - &i.StartBlocksLogin, - &i.RunOnStart, - &i.RunOnStop, - &i.TimeoutSeconds, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const getDeploymentWorkspaceStats = `-- name: GetDeploymentWorkspaceStats :one WITH workspaces_with_jobs AS ( SELECT @@ -10602,3 +10489,116 @@ func (q *sqlQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.C _, err := q.db.ExecContext(ctx, updateWorkspacesDormantDeletingAtByTemplateID, arg.TimeTilDormantAutodeleteMs, arg.DormantAt, arg.TemplateID) return err } + +const getWorkspaceAgentScriptsByAgentIDs = `-- name: GetWorkspaceAgentScriptsByAgentIDs :many +SELECT workspace_agent_id, log_source_id, log_path, created_at, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds FROM workspace_agent_scripts WHERE workspace_agent_id = ANY($1 :: uuid [ ]) +` + +func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgentScript, error) { + rows, err := q.db.QueryContext(ctx, getWorkspaceAgentScriptsByAgentIDs, pq.Array(ids)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WorkspaceAgentScript + for rows.Next() { + var i WorkspaceAgentScript + if err := rows.Scan( + &i.WorkspaceAgentID, + &i.LogSourceID, + &i.LogPath, + &i.CreatedAt, + &i.Script, + &i.Cron, + &i.StartBlocksLogin, + &i.RunOnStart, + &i.RunOnStop, + &i.TimeoutSeconds, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const insertWorkspaceAgentScripts = `-- name: InsertWorkspaceAgentScripts :many +INSERT INTO + workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds) +SELECT + $1 :: uuid AS workspace_agent_id, + $2 :: timestamptz AS created_at, + unnest($3 :: uuid [ ]) AS log_source_id, + unnest($4 :: text [ ]) AS log_path, + unnest($5 :: text [ ]) AS script, + unnest($6 :: text [ ]) AS cron, + unnest($7 :: boolean [ ]) AS start_blocks_login, + unnest($8 :: boolean [ ]) AS run_on_start, + unnest($9 :: boolean [ ]) AS run_on_stop, + unnest($10 :: integer [ ]) AS timeout_seconds +RETURNING workspace_agent_scripts.workspace_agent_id, workspace_agent_scripts.log_source_id, workspace_agent_scripts.log_path, workspace_agent_scripts.created_at, workspace_agent_scripts.script, workspace_agent_scripts.cron, workspace_agent_scripts.start_blocks_login, workspace_agent_scripts.run_on_start, workspace_agent_scripts.run_on_stop, workspace_agent_scripts.timeout_seconds +` + +type InsertWorkspaceAgentScriptsParams struct { + WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + LogSourceID []uuid.UUID `db:"log_source_id" json:"log_source_id"` + LogPath []string `db:"log_path" json:"log_path"` + Script []string `db:"script" json:"script"` + Cron []string `db:"cron" json:"cron"` + StartBlocksLogin []bool `db:"start_blocks_login" json:"start_blocks_login"` + RunOnStart []bool `db:"run_on_start" json:"run_on_start"` + RunOnStop []bool `db:"run_on_stop" json:"run_on_stop"` + TimeoutSeconds []int32 `db:"timeout_seconds" json:"timeout_seconds"` +} + +func (q *sqlQuerier) InsertWorkspaceAgentScripts(ctx context.Context, arg InsertWorkspaceAgentScriptsParams) ([]WorkspaceAgentScript, error) { + rows, err := q.db.QueryContext(ctx, insertWorkspaceAgentScripts, + arg.WorkspaceAgentID, + arg.CreatedAt, + pq.Array(arg.LogSourceID), + pq.Array(arg.LogPath), + pq.Array(arg.Script), + pq.Array(arg.Cron), + pq.Array(arg.StartBlocksLogin), + pq.Array(arg.RunOnStart), + pq.Array(arg.RunOnStop), + pq.Array(arg.TimeoutSeconds), + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WorkspaceAgentScript + for rows.Next() { + var i WorkspaceAgentScript + if err := rows.Scan( + &i.WorkspaceAgentID, + &i.LogSourceID, + &i.LogPath, + &i.CreatedAt, + &i.Script, + &i.Cron, + &i.StartBlocksLogin, + &i.RunOnStart, + &i.RunOnStop, + &i.TimeoutSeconds, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx b/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx index ba1863cbb4ad5..b8749cdde9cad 100644 --- a/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx +++ b/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx @@ -14,7 +14,7 @@ interface DormantDeletionStatProps { export const DormantDeletionStat: FC = ({ workspace, }) => { - const { entitlements, experiments } = useDashboard(); + const { entitlements } = useDashboard(); const allowAdvancedScheduling = entitlements.features["advanced_template_scheduling"].enabled; From a949d39ba871fc35effd6666b7582ea6bd4b448e Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Wed, 4 Oct 2023 19:46:10 +0000 Subject: [PATCH 5/5] remove experiment enabled helper fn --- .../components/Dashboard/DashboardProvider.tsx | 9 --------- .../WorkspaceDeletion/DormantWorkspaceBanner.tsx | 8 +++++--- .../GeneralSettingsPageView.stories.tsx | 8 +------- .../TemplateSchedulePageView.stories.tsx | 1 - site/src/pages/WorkspacesPage/WorkspacesPage.tsx | 15 +++++++-------- site/src/pages/WorkspacesPage/filter/filter.tsx | 7 +++++-- 6 files changed, 18 insertions(+), 30 deletions(-) diff --git a/site/src/components/Dashboard/DashboardProvider.tsx b/site/src/components/Dashboard/DashboardProvider.tsx index ed0f76db3342d..d5caa2397c0f8 100644 --- a/site/src/components/Dashboard/DashboardProvider.tsx +++ b/site/src/components/Dashboard/DashboardProvider.tsx @@ -110,12 +110,3 @@ export const useDashboard = (): DashboardProviderValue => { return context; }; - -export const useIsWorkspaceActionsEnabled = (): boolean => { - const { entitlements } = useDashboard(); - const allowAdvancedScheduling = - entitlements.features["advanced_template_scheduling"].enabled; - // This check can be removed when https://github.com/coder/coder/milestone/19 - // is merged up - return allowAdvancedScheduling; -}; diff --git a/site/src/components/WorkspaceDeletion/DormantWorkspaceBanner.tsx b/site/src/components/WorkspaceDeletion/DormantWorkspaceBanner.tsx index 677b8d3dc8894..304da5071483c 100644 --- a/site/src/components/WorkspaceDeletion/DormantWorkspaceBanner.tsx +++ b/site/src/components/WorkspaceDeletion/DormantWorkspaceBanner.tsx @@ -1,5 +1,5 @@ import { Workspace } from "api/typesGenerated"; -import { useIsWorkspaceActionsEnabled } from "components/Dashboard/DashboardProvider"; +import { useDashboard } from "components/Dashboard/DashboardProvider"; import { Alert } from "components/Alert/Alert"; import { formatDistanceToNow } from "date-fns"; import Link from "@mui/material/Link"; @@ -21,7 +21,9 @@ export const DormantWorkspaceBanner = ({ shouldRedisplayBanner: boolean; count?: Count; }): JSX.Element | null => { - const experimentEnabled = useIsWorkspaceActionsEnabled(); + const { entitlements } = useDashboard(); + const schedulingEnabled = + entitlements.features["advanced_template_scheduling"].enabled; if (!workspaces) { return null; @@ -37,7 +39,7 @@ export const DormantWorkspaceBanner = ({ if ( // Only show this if the experiment is included. - !experimentEnabled || + !schedulingEnabled || !hasDormantWorkspaces || // Banners should be redisplayed after dismissal when additional workspaces are newly scheduled for deletion !shouldRedisplayBanner diff --git a/site/src/pages/DeploySettingsPage/GeneralSettingsPage/GeneralSettingsPageView.stories.tsx b/site/src/pages/DeploySettingsPage/GeneralSettingsPage/GeneralSettingsPageView.stories.tsx index a711161f8671f..549e72f1767ae 100644 --- a/site/src/pages/DeploySettingsPage/GeneralSettingsPage/GeneralSettingsPageView.stories.tsx +++ b/site/src/pages/DeploySettingsPage/GeneralSettingsPage/GeneralSettingsPageView.stories.tsx @@ -30,13 +30,7 @@ const meta: Meta = { description: "Enable one or more experiments. These are not ready for production. Separate multiple experiments with commas, or enter '*' to opt-in to all available experiments.", flag: "experiments", - value: [ - "*", - "moons", - "workspace_actions", - "single_tailnet", - "deployment_health_page", - ], + value: ["*", "moons", "single_tailnet", "deployment_health_page"], flag_shorthand: "", hidden: false, }, diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.stories.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.stories.tsx index cb6e254662344..f1b0c796e3c5a 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.stories.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.stories.tsx @@ -31,7 +31,6 @@ type Story = StoryObj; const defaultArgs = { allowAdvancedScheduling: true, - allowWorkspaceActions: true, template: MockTemplate, onSubmit: action("onSubmit"), onCancel: action("cancel"), diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index 5273cd2f4486f..ae2c39cabedff 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -1,9 +1,6 @@ import { usePagination } from "hooks/usePagination"; import { Workspace } from "api/typesGenerated"; -import { - useDashboard, - useIsWorkspaceActionsEnabled, -} from "components/Dashboard/DashboardProvider"; +import { useDashboard } from "components/Dashboard/DashboardProvider"; import { type FC, useEffect, useState } from "react"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; @@ -54,13 +51,16 @@ const WorkspacesPage: FC = () => { query: filterProps.filter.query, }); - const experimentEnabled = useIsWorkspaceActionsEnabled(); + const { entitlements } = useDashboard(); + const schedulingEnabled = + entitlements.features["advanced_template_scheduling"].enabled; + // If workspace actions are enabled we need to fetch the dormant // workspaces as well. This lets us determine whether we should // show a banner to the user indicating that some of their workspaces // are at risk of being deleted. useEffect(() => { - if (experimentEnabled) { + if (schedulingEnabled) { const includesDormant = filterProps.filter.query.includes("dormant_at"); const dormantQuery = includesDormant ? filterProps.filter.query @@ -82,12 +82,11 @@ const WorkspacesPage: FC = () => { // like dormant workspaces don't exist. setDormantWorkspaces([]); } - }, [experimentEnabled, data, filterProps.filter.query]); + }, [schedulingEnabled, data, filterProps.filter.query]); const updateWorkspace = useWorkspaceUpdate(queryKey); const [checkedWorkspaces, setCheckedWorkspaces] = useState([]); const [isDeletingAll, setIsDeletingAll] = useState(false); const [urlSearchParams] = searchParamsResult; - const { entitlements } = useDashboard(); const canCheckWorkspaces = entitlements.features["workspace_batch_actions"].enabled; diff --git a/site/src/pages/WorkspacesPage/filter/filter.tsx b/site/src/pages/WorkspacesPage/filter/filter.tsx index b1fe3edb677d3..cdc5d39ae68cf 100644 --- a/site/src/pages/WorkspacesPage/filter/filter.tsx +++ b/site/src/pages/WorkspacesPage/filter/filter.tsx @@ -1,6 +1,7 @@ import { FC } from "react"; import Box from "@mui/material/Box"; -import { useIsWorkspaceActionsEnabled } from "components/Dashboard/DashboardProvider"; +import { useDashboard } from "components/Dashboard/DashboardProvider"; + import { Avatar, AvatarProps } from "components/Avatar/Avatar"; import { Palette, PaletteColor } from "@mui/material/styles"; import { TemplateFilterMenu, StatusFilterMenu } from "./menus"; @@ -68,7 +69,9 @@ export const WorkspacesFilter = ({ error, menus, }: WorkspaceFilterProps) => { - const actionsEnabled = useIsWorkspaceActionsEnabled(); + const { entitlements } = useDashboard(); + const actionsEnabled = + entitlements.features["advanced_template_scheduling"].enabled; const presets = actionsEnabled ? PRESET_FILTERS : PRESETS_WITH_DORMANT; return (