mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
feat: add opt-out option to new parameters form (#17456)
Closes https://github.com/coder/preview/issues/62
This commit is contained in:
@@ -1,18 +1,76 @@
|
||||
import { templateByName } from "api/queries/templates";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import type { FC } from "react";
|
||||
import { type FC, createContext } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { useParams } from "react-router-dom";
|
||||
import CreateWorkspacePage from "./CreateWorkspacePage";
|
||||
import CreateWorkspacePageExperimental from "./CreateWorkspacePageExperimental";
|
||||
|
||||
const CreateWorkspaceExperimentRouter: FC = () => {
|
||||
const { experiments } = useDashboard();
|
||||
|
||||
const dynamicParametersEnabled = experiments.includes("dynamic-parameters");
|
||||
|
||||
const { organization: organizationName = "default", template: templateName } =
|
||||
useParams() as { organization?: string; template: string };
|
||||
const templateQuery = useQuery(
|
||||
dynamicParametersEnabled
|
||||
? templateByName(organizationName, templateName)
|
||||
: { enabled: false },
|
||||
);
|
||||
|
||||
const optOutQuery = useQuery(
|
||||
templateQuery.data
|
||||
? {
|
||||
queryKey: [
|
||||
organizationName,
|
||||
"template",
|
||||
templateQuery.data.id,
|
||||
"optOut",
|
||||
],
|
||||
queryFn: () => ({
|
||||
templateId: templateQuery.data.id,
|
||||
optedOut:
|
||||
localStorage.getItem(optOutKey(templateQuery.data.id)) === "true",
|
||||
}),
|
||||
}
|
||||
: { enabled: false },
|
||||
);
|
||||
|
||||
if (dynamicParametersEnabled) {
|
||||
return <CreateWorkspacePageExperimental />;
|
||||
if (optOutQuery.isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
if (!optOutQuery.data) {
|
||||
return <ErrorAlert error={optOutQuery.error} />;
|
||||
}
|
||||
|
||||
const toggleOptedOut = () => {
|
||||
const key = optOutKey(optOutQuery.data.templateId);
|
||||
const current = localStorage.getItem(key) === "true";
|
||||
localStorage.setItem(key, (!current).toString());
|
||||
optOutQuery.refetch();
|
||||
};
|
||||
|
||||
return (
|
||||
<ExperimentalFormContext.Provider value={{ toggleOptedOut }}>
|
||||
{optOutQuery.data.optedOut ? (
|
||||
<CreateWorkspacePage />
|
||||
) : (
|
||||
<CreateWorkspacePageExperimental />
|
||||
)}
|
||||
</ExperimentalFormContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
return <CreateWorkspacePage />;
|
||||
};
|
||||
|
||||
export default CreateWorkspaceExperimentRouter;
|
||||
|
||||
const optOutKey = (id: string) => `parameters.${id}.optOut`;
|
||||
|
||||
export const ExperimentalFormContext = createContext<
|
||||
{ toggleOptedOut: () => void } | undefined
|
||||
>(undefined);
|
||||
|
||||
@@ -69,10 +69,11 @@ const CreateWorkspacePageExperimental: FC = () => {
|
||||
const templateQuery = useQuery(
|
||||
templateByName(organizationName, templateName),
|
||||
);
|
||||
const templateVersionPresetsQuery = useQuery({
|
||||
...templateVersionPresets(templateQuery.data?.active_version_id ?? ""),
|
||||
enabled: templateQuery.data !== undefined,
|
||||
});
|
||||
const templateVersionPresetsQuery = useQuery(
|
||||
templateQuery.data
|
||||
? templateVersionPresets(templateQuery.data.active_version_id)
|
||||
: { enabled: false },
|
||||
);
|
||||
const permissionsQuery = useQuery(
|
||||
templateQuery.data
|
||||
? checkAuthorization({
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { Interpolation, Theme } from "@emotion/react";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import FormHelperText from "@mui/material/FormHelperText";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import type * as TypesGen from "api/typesGenerated";
|
||||
@@ -29,7 +28,14 @@ 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, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
type FC,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
getFormHelpers,
|
||||
nameValidator,
|
||||
@@ -41,12 +47,14 @@ import {
|
||||
useValidationSchemaForRichParameters,
|
||||
} from "utils/richParameters";
|
||||
import * as Yup from "yup";
|
||||
import { ExperimentalFormContext } from "./CreateWorkspaceExperimentRouter";
|
||||
import type {
|
||||
CreateWorkspaceMode,
|
||||
ExternalAuthPollingState,
|
||||
} from "./CreateWorkspacePage";
|
||||
import { ExternalAuthButton } from "./ExternalAuthButton";
|
||||
import type { CreateWorkspacePermissions } from "./permissions";
|
||||
|
||||
export const Language = {
|
||||
duplicationWarning:
|
||||
"Duplicating a workspace only copies its parameters. No state from the old workspace is copied over.",
|
||||
@@ -98,6 +106,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}) => {
|
||||
const experimentalFormContext = useContext(ExperimentalFormContext);
|
||||
const [owner, setOwner] = useState(defaultOwner);
|
||||
const [suggestedName, setSuggestedName] = useState(() =>
|
||||
generateWorkspaceName(),
|
||||
@@ -211,9 +220,20 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
<Margins size="medium">
|
||||
<PageHeader
|
||||
actions={
|
||||
<Button size="sm" variant="outline" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
<>
|
||||
{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>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Stack direction="row">
|
||||
|
||||
@@ -22,10 +22,18 @@ import {
|
||||
useValidationSchemaForDynamicParameters,
|
||||
} from "modules/workspaces/DynamicParameter/DynamicParameter";
|
||||
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
|
||||
import { type FC, useCallback, useEffect, useId, useState } from "react";
|
||||
import {
|
||||
type FC,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useId,
|
||||
useState,
|
||||
} from "react";
|
||||
import { getFormHelpers, nameValidator } from "utils/formUtils";
|
||||
import type { AutofillBuildParameter } from "utils/richParameters";
|
||||
import * as Yup from "yup";
|
||||
import { ExperimentalFormContext } from "./CreateWorkspaceExperimentRouter";
|
||||
import type {
|
||||
CreateWorkspaceMode,
|
||||
ExternalAuthPollingState,
|
||||
@@ -89,6 +97,7 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
owner,
|
||||
setOwner,
|
||||
}) => {
|
||||
const experimentalFormContext = useContext(ExperimentalFormContext);
|
||||
const [suggestedName, setSuggestedName] = useState(() =>
|
||||
generateWorkspaceName(),
|
||||
);
|
||||
@@ -251,7 +260,7 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-6 max-w-screen-sm mx-auto">
|
||||
<header className="flex flex-col gap-2 mt-10">
|
||||
<header className="flex flex-col items-start gap-2 mt-10">
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar
|
||||
variant="icon"
|
||||
@@ -268,6 +277,16 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
<h1 className="text-3xl font-semibold m-0">New workspace</h1>
|
||||
|
||||
{template.deprecated && <Pill type="warning">Deprecated</Pill>}
|
||||
|
||||
{experimentalFormContext && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="subtle"
|
||||
onClick={experimentalFormContext.toggleOptedOut}
|
||||
>
|
||||
Go back to the classic workspace creation flow
|
||||
</Button>
|
||||
)}
|
||||
</header>
|
||||
|
||||
<form
|
||||
|
||||
Reference in New Issue
Block a user