mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
chore: remove local storage based optin/optout (#18344)
This removes the opt-in and opt-out buttons for dynamic parameters on the create workspace page and the workspace parameters settings page. --------- Co-authored-by: Steven Masley <stevenmasley@gmail.com>
This commit is contained in:
@@ -249,6 +249,7 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) {
|
||||
Value: "GO",
|
||||
},
|
||||
}
|
||||
request.EnableDynamicParameters = true
|
||||
})
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, wrk.LatestBuild.ID)
|
||||
|
||||
|
||||
@@ -1011,6 +1011,8 @@ export const updateWorkspace = async (
|
||||
await page.getByTestId("workspace-update-button").click();
|
||||
await page.getByTestId("confirm-button").click();
|
||||
|
||||
await page.waitForSelector('[data-testid="dialog"]', { state: "visible" });
|
||||
|
||||
await fillParameters(page, richParameters, buildParameters);
|
||||
await page.getByRole("button", { name: /update parameters/i }).click();
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import { useQuery } from "react-query";
|
||||
|
||||
export const optOutKey = (id: string): string => `parameters.${id}.optOut`;
|
||||
|
||||
interface UseDynamicParametersOptOutOptions {
|
||||
templateId: string | undefined;
|
||||
templateUsesClassicParameters: boolean | undefined;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export const useDynamicParametersOptOut = ({
|
||||
templateId,
|
||||
templateUsesClassicParameters,
|
||||
enabled,
|
||||
}: UseDynamicParametersOptOutOptions) => {
|
||||
return useQuery({
|
||||
enabled: !!templateId && enabled,
|
||||
queryKey: ["dynamicParametersOptOut", templateId],
|
||||
queryFn: () => {
|
||||
if (!templateId) {
|
||||
// This should not happen if enabled is working correctly,
|
||||
// but as a type guard and sanity check.
|
||||
throw new Error("templateId is required");
|
||||
}
|
||||
const localStorageKey = optOutKey(templateId);
|
||||
const storedOptOutString = localStorage.getItem(localStorageKey);
|
||||
|
||||
// Since the dynamic-parameters experiment was removed, always use classic parameters
|
||||
const optedOut = true;
|
||||
|
||||
return {
|
||||
templateId,
|
||||
optedOut,
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
SettingsIcon,
|
||||
TrashIcon,
|
||||
} from "lucide-react";
|
||||
import { useDynamicParametersOptOut } from "modules/workspaces/DynamicParameter/useDynamicParametersOptOut";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
@@ -43,13 +42,6 @@ export const WorkspaceMoreActions: FC<WorkspaceMoreActionsProps> = ({
|
||||
}) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: workspace.template_id,
|
||||
templateUsesClassicParameters:
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
// Permissions
|
||||
const { data: permissions } = useQuery(workspacePermissions(workspace));
|
||||
|
||||
@@ -59,7 +51,11 @@ export const WorkspaceMoreActions: FC<WorkspaceMoreActionsProps> = ({
|
||||
// Change version
|
||||
const [changeVersionDialogOpen, setChangeVersionDialogOpen] = useState(false);
|
||||
const changeVersionMutation = useMutation(
|
||||
changeVersion(workspace, queryClient, optOutQuery.data?.optedOut === false),
|
||||
changeVersion(
|
||||
workspace,
|
||||
queryClient,
|
||||
!workspace.template_use_classic_parameter_flow,
|
||||
),
|
||||
);
|
||||
|
||||
// Delete
|
||||
@@ -151,7 +147,7 @@ export const WorkspaceMoreActions: FC<WorkspaceMoreActionsProps> = ({
|
||||
onClose={() => setIsDownloadDialogOpen(false)}
|
||||
/>
|
||||
|
||||
{optOutQuery.data?.optedOut ? (
|
||||
{workspace.template_use_classic_parameter_flow ? (
|
||||
<UpdateBuildParametersDialog
|
||||
missedParameters={
|
||||
changeVersionMutation.error instanceof MissingBuildParameters
|
||||
|
||||
@@ -6,11 +6,8 @@ import type {
|
||||
WorkspaceBuild,
|
||||
WorkspaceBuildParameter,
|
||||
} from "api/typesGenerated";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { MemoizedInlineMarkdown } from "components/Markdown/Markdown";
|
||||
import { useDynamicParametersOptOut } from "modules/workspaces/DynamicParameter/useDynamicParametersOptOut";
|
||||
import { UpdateBuildParametersDialog } from "modules/workspaces/WorkspaceMoreActions/UpdateBuildParametersDialog";
|
||||
import { UpdateBuildParametersDialogExperimental } from "modules/workspaces/WorkspaceMoreActions/UpdateBuildParametersDialogExperimental";
|
||||
import { type FC, useState } from "react";
|
||||
@@ -55,17 +52,11 @@ export const useWorkspaceUpdate = ({
|
||||
setIsConfirmingUpdate(true);
|
||||
};
|
||||
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: workspace.template_id,
|
||||
templateUsesClassicParameters:
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const confirmUpdate = (buildParameters: WorkspaceBuildParameter[] = []) => {
|
||||
updateWorkspaceMutation.mutate({
|
||||
buildParameters,
|
||||
isDynamicParametersEnabled: optOutQuery.data?.optedOut === false,
|
||||
isDynamicParametersEnabled:
|
||||
!workspace.template_use_classic_parameter_flow,
|
||||
});
|
||||
setIsConfirmingUpdate(false);
|
||||
};
|
||||
@@ -160,29 +151,13 @@ const MissingBuildParametersDialog: FC<MissingBuildParametersDialogProps> = ({
|
||||
error,
|
||||
...dialogProps
|
||||
}) => {
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: workspace.template_id,
|
||||
templateUsesClassicParameters:
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const missedParameters =
|
||||
error instanceof MissingBuildParameters ? error.parameters : [];
|
||||
const versionId =
|
||||
error instanceof MissingBuildParameters ? error.versionId : undefined;
|
||||
const isOpen = error instanceof MissingBuildParameters;
|
||||
|
||||
if (optOutQuery.isError) {
|
||||
return <ErrorAlert error={optOutQuery.error} />;
|
||||
}
|
||||
if (!optOutQuery.data) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
const shouldUseClassicDialog = optOutQuery.data?.optedOut;
|
||||
|
||||
return shouldUseClassicDialog ? (
|
||||
return workspace.template_use_classic_parameter_flow ? (
|
||||
<UpdateBuildParametersDialog
|
||||
missedParameters={missedParameters}
|
||||
open={isOpen}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { templateByName } from "api/queries/templates";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import {
|
||||
optOutKey,
|
||||
useDynamicParametersOptOut,
|
||||
} from "modules/workspaces/DynamicParameter/useDynamicParametersOptOut";
|
||||
import type { FC } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { useParams } from "react-router-dom";
|
||||
import CreateWorkspacePage from "./CreateWorkspacePage";
|
||||
import CreateWorkspacePageExperimental from "./CreateWorkspacePageExperimental";
|
||||
import { ExperimentalFormContext } from "./ExperimentalFormContext";
|
||||
|
||||
const CreateWorkspaceExperimentRouter: FC = () => {
|
||||
const { organization: organizationName = "default", template: templateName } =
|
||||
@@ -19,43 +14,21 @@ const CreateWorkspaceExperimentRouter: FC = () => {
|
||||
templateByName(organizationName, templateName),
|
||||
);
|
||||
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: templateQuery.data?.id,
|
||||
templateUsesClassicParameters:
|
||||
templateQuery.data?.use_classic_parameter_flow,
|
||||
enabled: !!templateQuery.data,
|
||||
});
|
||||
|
||||
if (templateQuery.isError) {
|
||||
return <ErrorAlert error={templateQuery.error} />;
|
||||
}
|
||||
if (optOutQuery.isError) {
|
||||
return <ErrorAlert error={optOutQuery.error} />;
|
||||
}
|
||||
if (!optOutQuery.data) {
|
||||
if (!templateQuery.data) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
const toggleOptedOut = () => {
|
||||
const key = optOutKey(optOutQuery.data?.templateId ?? "");
|
||||
const storedValue = localStorage.getItem(key);
|
||||
|
||||
const current = storedValue
|
||||
? storedValue === "true"
|
||||
: Boolean(templateQuery.data?.use_classic_parameter_flow);
|
||||
|
||||
localStorage.setItem(key, (!current).toString());
|
||||
optOutQuery.refetch();
|
||||
};
|
||||
|
||||
return (
|
||||
<ExperimentalFormContext.Provider value={{ toggleOptedOut }}>
|
||||
{optOutQuery.data.optedOut ? (
|
||||
<>
|
||||
{templateQuery.data?.use_classic_parameter_flow ? (
|
||||
<CreateWorkspacePage />
|
||||
) : (
|
||||
<CreateWorkspacePageExperimental />
|
||||
)}
|
||||
</ExperimentalFormContext.Provider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -28,14 +28,7 @@ import { Switch } from "components/Switch/Switch";
|
||||
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
|
||||
import { type FormikContextType, useFormik } from "formik";
|
||||
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
|
||||
import {
|
||||
type FC,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { type FC, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
getFormHelpers,
|
||||
nameValidator,
|
||||
@@ -51,7 +44,6 @@ import type {
|
||||
CreateWorkspaceMode,
|
||||
ExternalAuthPollingState,
|
||||
} from "./CreateWorkspacePage";
|
||||
import { ExperimentalFormContext } from "./ExperimentalFormContext";
|
||||
import { ExternalAuthButton } from "./ExternalAuthButton";
|
||||
import type { CreateWorkspacePermissions } from "./permissions";
|
||||
|
||||
@@ -106,7 +98,6 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}) => {
|
||||
const experimentalFormContext = useContext(ExperimentalFormContext);
|
||||
const [owner, setOwner] = useState(defaultOwner);
|
||||
const [suggestedName, setSuggestedName] = useState(() =>
|
||||
generateWorkspaceName(),
|
||||
@@ -220,20 +211,9 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
<Margins size="medium">
|
||||
<PageHeader
|
||||
actions={
|
||||
<>
|
||||
{experimentalFormContext && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={experimentalFormContext.toggleOptedOut}
|
||||
>
|
||||
Try out the new workspace creation flow ✨
|
||||
</Button>
|
||||
)}
|
||||
<Button size="sm" variant="outline" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
</>
|
||||
<Button size="sm" variant="outline" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Stack direction="row">
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from "components/Tooltip/Tooltip";
|
||||
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
|
||||
import { type FormikContextType, useFormik } from "formik";
|
||||
import { ArrowLeft, CircleHelp, Undo2 } from "lucide-react";
|
||||
import { ArrowLeft, CircleHelp } from "lucide-react";
|
||||
import { useSyncFormParameters } from "modules/hooks/useSyncFormParameters";
|
||||
import { Diagnostics } from "modules/workspaces/DynamicParameter/DynamicParameter";
|
||||
import {
|
||||
@@ -38,7 +38,6 @@ import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName"
|
||||
import {
|
||||
type FC,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useId,
|
||||
useRef,
|
||||
@@ -52,7 +51,6 @@ import type {
|
||||
CreateWorkspaceMode,
|
||||
ExternalAuthPollingState,
|
||||
} from "./CreateWorkspacePage";
|
||||
import { ExperimentalFormContext } from "./ExperimentalFormContext";
|
||||
import { ExternalAuthButton } from "./ExternalAuthButton";
|
||||
import type { CreateWorkspacePermissions } from "./permissions";
|
||||
|
||||
@@ -112,7 +110,6 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
owner,
|
||||
setOwner,
|
||||
}) => {
|
||||
const experimentalFormContext = useContext(ExperimentalFormContext);
|
||||
const [suggestedName, setSuggestedName] = useState(() =>
|
||||
generateWorkspaceName(),
|
||||
);
|
||||
@@ -372,16 +369,6 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
</Badge>
|
||||
)}
|
||||
</span>
|
||||
{experimentalFormContext && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={experimentalFormContext.toggleOptedOut}
|
||||
>
|
||||
<Undo2 />
|
||||
Classic workspace creation
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<span className="flex flex-row items-center gap-2">
|
||||
<h1 className="text-3xl font-semibold m-0">New workspace</h1>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { createContext } from "react";
|
||||
|
||||
export const ExperimentalFormContext = createContext<
|
||||
{ toggleOptedOut: () => void } | undefined
|
||||
>(undefined);
|
||||
@@ -305,7 +305,7 @@ describe("WorkspacePage", () => {
|
||||
|
||||
// Check if the update was called using the values from the form
|
||||
await waitFor(() => {
|
||||
expect(API.updateWorkspace).toBeCalledWith(
|
||||
expect(API.updateWorkspace).toHaveBeenCalledWith(
|
||||
MockOutdatedWorkspace,
|
||||
[
|
||||
{
|
||||
|
||||
+3
-36
@@ -1,11 +1,4 @@
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import {
|
||||
optOutKey,
|
||||
useDynamicParametersOptOut,
|
||||
} from "modules/workspaces/DynamicParameter/useDynamicParametersOptOut";
|
||||
import type { FC } from "react";
|
||||
import { ExperimentalFormContext } from "../../CreateWorkspacePage/ExperimentalFormContext";
|
||||
import { useWorkspaceSettings } from "../WorkspaceSettingsLayout";
|
||||
import WorkspaceParametersPage from "./WorkspaceParametersPage";
|
||||
import WorkspaceParametersPageExperimental from "./WorkspaceParametersPageExperimental";
|
||||
@@ -13,40 +6,14 @@ import WorkspaceParametersPageExperimental from "./WorkspaceParametersPageExperi
|
||||
const WorkspaceParametersExperimentRouter: FC = () => {
|
||||
const workspace = useWorkspaceSettings();
|
||||
|
||||
const optOutQuery = useDynamicParametersOptOut({
|
||||
templateId: workspace.template_id,
|
||||
templateUsesClassicParameters:
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
if (optOutQuery.isError) {
|
||||
return <ErrorAlert error={optOutQuery.error} />;
|
||||
}
|
||||
if (!optOutQuery.data) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
const toggleOptedOut = () => {
|
||||
const key = optOutKey(optOutQuery.data.templateId);
|
||||
const storedValue = localStorage.getItem(key);
|
||||
|
||||
const current = storedValue
|
||||
? storedValue === "true"
|
||||
: Boolean(workspace.template_use_classic_parameter_flow);
|
||||
|
||||
localStorage.setItem(key, (!current).toString());
|
||||
optOutQuery.refetch();
|
||||
};
|
||||
|
||||
return (
|
||||
<ExperimentalFormContext.Provider value={{ toggleOptedOut }}>
|
||||
{optOutQuery.data.optedOut ? (
|
||||
<>
|
||||
{workspace.template_use_classic_parameter_flow ? (
|
||||
<WorkspaceParametersPage />
|
||||
) : (
|
||||
<WorkspaceParametersPageExperimental />
|
||||
)}
|
||||
</ExperimentalFormContext.Provider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+1
-13
@@ -4,11 +4,10 @@ import { isApiValidationError } from "api/errors";
|
||||
import { checkAuthorization } from "api/queries/authCheck";
|
||||
import type { Workspace, WorkspaceBuildParameter } from "api/typesGenerated";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Button as ShadcnButton } from "components/Button/Button";
|
||||
import { EmptyState } from "components/EmptyState/EmptyState";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { ExternalLinkIcon } from "lucide-react";
|
||||
import { type FC, useContext } from "react";
|
||||
import type { FC } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useMutation, useQuery } from "react-query";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -18,7 +17,6 @@ import {
|
||||
type WorkspacePermissions,
|
||||
workspaceChecks,
|
||||
} from "../../../modules/workspaces/permissions";
|
||||
import { ExperimentalFormContext } from "../../CreateWorkspacePage/ExperimentalFormContext";
|
||||
import { useWorkspaceSettings } from "../WorkspaceSettingsLayout";
|
||||
import {
|
||||
WorkspaceParametersForm,
|
||||
@@ -113,21 +111,11 @@ export const WorkspaceParametersPageView: FC<
|
||||
isSubmitting,
|
||||
onCancel,
|
||||
}) => {
|
||||
const experimentalFormContext = useContext(ExperimentalFormContext);
|
||||
return (
|
||||
<div className="flex flex-col gap-10">
|
||||
<header className="flex flex-col items-start gap-2">
|
||||
<span className="flex flex-row justify-between w-full items-center gap-2">
|
||||
<h1 className="text-3xl m-0">Workspace parameters</h1>
|
||||
{experimentalFormContext && (
|
||||
<ShadcnButton
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={experimentalFormContext.toggleOptedOut}
|
||||
>
|
||||
Try out the new workspace parameters ✨
|
||||
</ShadcnButton>
|
||||
)}
|
||||
</span>
|
||||
</header>
|
||||
|
||||
|
||||
+2
-15
@@ -7,7 +7,6 @@ import type {
|
||||
WorkspaceBuildParameter,
|
||||
} from "api/typesGenerated";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Button } from "components/Button/Button";
|
||||
import { EmptyState } from "components/EmptyState/EmptyState";
|
||||
import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge";
|
||||
import { Link } from "components/Link/Link";
|
||||
@@ -19,9 +18,9 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "components/Tooltip/Tooltip";
|
||||
import { useEffectEvent } from "hooks/hookPolyfills";
|
||||
import { CircleHelp, Undo2 } from "lucide-react";
|
||||
import { CircleHelp } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import { useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useMutation, useQuery } from "react-query";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
@@ -32,14 +31,12 @@ import {
|
||||
type WorkspacePermissions,
|
||||
workspaceChecks,
|
||||
} from "../../../modules/workspaces/permissions";
|
||||
import { ExperimentalFormContext } from "../../CreateWorkspacePage/ExperimentalFormContext";
|
||||
import { useWorkspaceSettings } from "../WorkspaceSettingsLayout";
|
||||
import { WorkspaceParametersPageViewExperimental } from "./WorkspaceParametersPageViewExperimental";
|
||||
|
||||
const WorkspaceParametersPageExperimental: FC = () => {
|
||||
const workspace = useWorkspaceSettings();
|
||||
const navigate = useNavigate();
|
||||
const experimentalFormContext = useContext(ExperimentalFormContext);
|
||||
const [searchParams] = useSearchParams();
|
||||
const templateVersionId = searchParams.get("templateVersionId") ?? undefined;
|
||||
|
||||
@@ -236,16 +233,6 @@ const WorkspaceParametersPageExperimental: FC = () => {
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</span>
|
||||
{experimentalFormContext && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={experimentalFormContext.toggleOptedOut}
|
||||
>
|
||||
<Undo2 />
|
||||
Classic workspace parameters
|
||||
</Button>
|
||||
)}
|
||||
</span>
|
||||
<FeatureStageBadge
|
||||
contentType={"early_access"}
|
||||
|
||||
Reference in New Issue
Block a user