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/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/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 diff --git a/site/src/components/Dashboard/DashboardProvider.tsx b/site/src/components/Dashboard/DashboardProvider.tsx index e1b54165e7128..d5caa2397c0f8 100644 --- a/site/src/components/Dashboard/DashboardProvider.tsx +++ b/site/src/components/Dashboard/DashboardProvider.tsx @@ -110,13 +110,3 @@ export const useDashboard = (): DashboardProviderValue => { return context; }; - -export const useIsWorkspaceActionsEnabled = (): boolean => { - 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"); - return allowWorkspaceActions && allowAdvancedScheduling; -}; diff --git a/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx b/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx index 8dc7a289d21f9..b8749cdde9cad 100644 --- a/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx +++ b/site/src/components/WorkspaceDeletion/DormantDeletionStat.tsx @@ -14,20 +14,11 @@ interface DormantDeletionStatProps { export const DormantDeletionStat: FC = ({ workspace, }) => { - 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; } 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/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/components/WorkspaceDeletion/utils.test.ts b/site/src/components/WorkspaceDeletion/utils.test.ts index caca6c5661993..87d32de1f832e 100644 --- a/site/src/components/WorkspaceDeletion/utils.test.ts +++ b/site/src/components/WorkspaceDeletion/utils.test.ts @@ -4,53 +4,39 @@ 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, - allowAdvancedScheduling, - allowWorkspaceActions, - shouldDisplay, - ) => { + `deleting_at=%p, allowAdvancedScheduling=%p, shouldDisplay=%p`, + (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/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/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 = () => { ; const defaultArgs = { allowAdvancedScheduling: true, - allowWorkspaceActions: true, template: MockTemplate, onSubmit: action("onSubmit"), onCancel: action("cancel"), diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.tsx index bf29c42c3fbad..74730cea0179e 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePageView.tsx @@ -14,7 +14,6 @@ export interface TemplateSchedulePageViewProps { typeof TemplateScheduleForm >["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 = ({ { 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 ( diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 013f7197cd145..f9341889a9c54 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -1924,10 +1924,7 @@ export const MockEntitlementsWithScheduling: TypesGen.Entitlements = { }), }; -export const MockExperiments: TypesGen.Experiment[] = [ - "workspace_actions", - "moons", -]; +export const MockExperiments: TypesGen.Experiment[] = ["moons"]; export const MockAuditLog: TypesGen.AuditLog = { id: "fbd2116a-8961-4954-87ae-e4575bd29ce0",