chore: remove workspace_actions experiment (#10030)

This commit is contained in:
Jon Ayers
2023-10-05 14:18:35 -05:00
committed by GitHub
parent 3c87c4df1b
commit eb4826a11f
22 changed files with 35 additions and 130 deletions
-10
View File
@@ -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 {
-12
View File
@@ -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 ||
-2
View File
@@ -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",
-2
View File
@@ -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",
-3
View File
@@ -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"
-1
View File
@@ -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` |
+1 -3
View File
@@ -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
@@ -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;
};
@@ -14,20 +14,11 @@ interface DormantDeletionStatProps {
export const DormantDeletionStat: FC<DormantDeletionStatProps> = ({
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;
}
@@ -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 <StyledSpan role="status">Impending deletion</StyledSpan>;
@@ -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
@@ -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,
);
},
);
});
@@ -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 (
@@ -30,13 +30,7 @@ const meta: Meta<typeof GeneralSettingsPageView> = {
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,
},
@@ -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<UpdateTemplateMeta>;
@@ -62,7 +61,6 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
onCancel,
error,
allowAdvancedScheduling,
allowWorkspaceActions,
allowAutostopRequirement,
isSubmitting,
initialTouched,
@@ -459,7 +457,7 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
</Stack>
</Stack>
</FormSection>
{allowAdvancedScheduling && allowWorkspaceActions && (
{allowAdvancedScheduling && (
<>
<FormSection
title="Failure Cleanup"
@@ -123,9 +123,6 @@ describe("TemplateSchedulePage", () => {
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 () => {
@@ -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 = () => {
</Helmet>
<TemplateSchedulePageView
allowAdvancedScheduling={allowAdvancedScheduling}
allowWorkspaceActions={allowWorkspaceActions}
allowAutostopRequirement={allowAutostopRequirement}
isSubmitting={isSubmitting}
template={template}
@@ -31,7 +31,6 @@ type Story = StoryObj<typeof TemplateSchedulePageView>;
const defaultArgs = {
allowAdvancedScheduling: true,
allowWorkspaceActions: true,
template: MockTemplate,
onSubmit: action("onSubmit"),
onCancel: action("cancel"),
@@ -14,7 +14,6 @@ export interface TemplateSchedulePageViewProps {
typeof TemplateScheduleForm
>["initialTouched"];
allowAdvancedScheduling: boolean;
allowWorkspaceActions: boolean;
allowAutostopRequirement: boolean;
}
@@ -24,7 +23,6 @@ export const TemplateSchedulePageView: FC<TemplateSchedulePageViewProps> = ({
onSubmit,
isSubmitting,
allowAdvancedScheduling,
allowWorkspaceActions,
allowAutostopRequirement,
submitError,
initialTouched,
@@ -39,7 +37,6 @@ export const TemplateSchedulePageView: FC<TemplateSchedulePageViewProps> = ({
<TemplateScheduleForm
allowAdvancedScheduling={allowAdvancedScheduling}
allowWorkspaceActions={allowWorkspaceActions}
allowAutostopRequirement={allowAutostopRequirement}
initialTouched={initialTouched}
isSubmitting={isSubmitting}
@@ -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<Workspace[]>([]);
const [isDeletingAll, setIsDeletingAll] = useState(false);
const [urlSearchParams] = searchParamsResult;
const { entitlements } = useDashboard();
const canCheckWorkspaces =
entitlements.features["workspace_batch_actions"].enabled;
@@ -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 (
+1 -4
View File
@@ -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",