mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
feat: add beta labels for dynamic params (#17985)
<img width="820" alt="Screenshot 2025-05-23 at 18 48 56" src="https://github.com/user-attachments/assets/5b781501-3817-4be1-8143-f03f8cb88901" /> <img width="790" alt="Screenshot 2025-05-23 at 18 48 32" src="https://github.com/user-attachments/assets/541ad77e-fd37-4f52-ae2c-7b1f698c23fc" />
This commit is contained in:
@@ -18,6 +18,7 @@ export const featureStageBadgeTypes = {
|
||||
type FeatureStageBadgeProps = Readonly<
|
||||
Omit<HTMLAttributes<HTMLSpanElement>, "children"> & {
|
||||
contentType: keyof typeof featureStageBadgeTypes;
|
||||
labelText?: string;
|
||||
size?: "sm" | "md" | "lg";
|
||||
showTooltip?: boolean;
|
||||
}
|
||||
@@ -25,6 +26,7 @@ type FeatureStageBadgeProps = Readonly<
|
||||
|
||||
export const FeatureStageBadge: FC<FeatureStageBadgeProps> = ({
|
||||
contentType,
|
||||
labelText = "",
|
||||
size = "md",
|
||||
showTooltip = true, // This is a temporary until the deprecated popover is removed
|
||||
...delegatedProps
|
||||
@@ -43,7 +45,8 @@ export const FeatureStageBadge: FC<FeatureStageBadgeProps> = ({
|
||||
{...delegatedProps}
|
||||
>
|
||||
<span style={visuallyHidden}> (This is a</span>
|
||||
<span css={styles.badgeLabel}>
|
||||
<span className="first-letter:uppercase">
|
||||
{labelText && `${labelText} `}
|
||||
{featureStageBadgeTypes[contentType]}
|
||||
</span>
|
||||
<span style={visuallyHidden}> feature)</span>
|
||||
@@ -105,13 +108,6 @@ const styles = {
|
||||
backgroundColor: theme.branding.featureStage.hover.background,
|
||||
}),
|
||||
|
||||
badgeLabel: {
|
||||
// Have to set display mode to anything other than inline, or else the
|
||||
// CSS capitalization algorithm won't capitalize the element
|
||||
display: "inline-block",
|
||||
textTransform: "capitalize",
|
||||
},
|
||||
|
||||
badgeLargeText: {
|
||||
fontSize: "1rem",
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Button } from "components/Button/Button";
|
||||
import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge";
|
||||
import { Input } from "components/Input/Input";
|
||||
import { Label } from "components/Label/Label";
|
||||
import { Link } from "components/Link/Link";
|
||||
import { Pill } from "components/Pill/Pill";
|
||||
import {
|
||||
Select,
|
||||
@@ -17,9 +18,21 @@ import {
|
||||
} from "components/Select/Select";
|
||||
import { Spinner } from "components/Spinner/Spinner";
|
||||
import { Switch } from "components/Switch/Switch";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "components/Tooltip/Tooltip";
|
||||
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
|
||||
import { type FormikContextType, useFormik } from "formik";
|
||||
import { ArrowLeft, CircleAlert, TriangleAlert } from "lucide-react";
|
||||
import {
|
||||
ArrowLeft,
|
||||
CircleAlert,
|
||||
CircleHelp,
|
||||
TriangleAlert,
|
||||
Undo2,
|
||||
} from "lucide-react";
|
||||
import { useSyncFormParameters } from "modules/hooks/useSyncFormParameters";
|
||||
import {
|
||||
DynamicParameter,
|
||||
@@ -36,6 +49,7 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { docs } from "utils/docs";
|
||||
import { nameValidator } from "utils/formUtils";
|
||||
import type { AutofillBuildParameter } from "utils/richParameters";
|
||||
import * as Yup from "yup";
|
||||
@@ -337,7 +351,7 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-6 max-w-screen-md mx-auto">
|
||||
<header className="flex flex-col items-start gap-2 mt-10">
|
||||
<header className="flex flex-col items-start gap-3 mt-10">
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar
|
||||
variant="icon"
|
||||
@@ -351,17 +365,45 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
: template.name}
|
||||
</p>
|
||||
</div>
|
||||
<h1 className="text-3xl font-semibold m-0">New workspace</h1>
|
||||
<span className="flex flex-row items-center gap-2">
|
||||
<h1 className="text-3xl font-semibold m-0">New workspace</h1>
|
||||
<FeatureStageBadge
|
||||
className="mt-1"
|
||||
contentType={"beta"}
|
||||
labelText="Dynamic parameters"
|
||||
/>
|
||||
<TooltipProvider delayDuration={100}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<CircleHelp className="size-icon-xs text-content-secondary" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="max-w-xs text-sm">
|
||||
Dynamic Parameters enhances Coder's existing parameter system
|
||||
with real-time validation, conditional parameter behavior, and
|
||||
richer input types.
|
||||
<br />
|
||||
<Link
|
||||
href={docs(
|
||||
"/admin/templates/extending-templates/parameters#enable-dynamic-parameters-early-access",
|
||||
)}
|
||||
>
|
||||
View docs
|
||||
</Link>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</span>
|
||||
|
||||
{template.deprecated && <Pill type="warning">Deprecated</Pill>}
|
||||
|
||||
{experimentalFormContext && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
onClick={experimentalFormContext.toggleOptedOut}
|
||||
>
|
||||
Go back to the classic workspace creation flow
|
||||
<Undo2 />
|
||||
Use the classic workspace creation flow
|
||||
</Button>
|
||||
)}
|
||||
</header>
|
||||
@@ -501,6 +543,13 @@ export const CreateWorkspacePageViewExperimental: FC<
|
||||
<p className="text-sm text-content-secondary m-0">
|
||||
These are the settings used by your template. Immutable
|
||||
parameters cannot be modified once the workspace is created.
|
||||
<Link
|
||||
href={docs(
|
||||
"/admin/templates/extending-templates/parameters#enable-dynamic-parameters-early-access",
|
||||
)}
|
||||
>
|
||||
View docs
|
||||
</Link>
|
||||
</p>
|
||||
</hgroup>
|
||||
{diagnostics.length > 0 && (
|
||||
|
||||
+35
-3
@@ -12,7 +12,14 @@ import { EmptyState } from "components/EmptyState/EmptyState";
|
||||
import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge";
|
||||
import { Link } from "components/Link/Link";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "components/Tooltip/Tooltip";
|
||||
import { useEffectEvent } from "hooks/hookPolyfills";
|
||||
import { CircleHelp, Undo2 } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import {
|
||||
useCallback,
|
||||
@@ -161,7 +168,7 @@ const WorkspaceParametersPageExperimental: FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 max-w-screen-md mx-auto">
|
||||
<div className="flex flex-col gap-6 max-w-screen-md">
|
||||
<Helmet>
|
||||
<title>{pageTitle(workspace.name, "Parameters")}</title>
|
||||
</Helmet>
|
||||
@@ -169,7 +176,31 @@ const WorkspaceParametersPageExperimental: FC = () => {
|
||||
<header className="flex flex-col items-start gap-2">
|
||||
<span className="flex flex-row items-center gap-2">
|
||||
<h1 className="text-3xl m-0">Workspace parameters</h1>
|
||||
<FeatureStageBadge contentType={"beta"} />
|
||||
<FeatureStageBadge
|
||||
className="mt-1"
|
||||
contentType={"beta"}
|
||||
labelText="Dynamic parameters"
|
||||
/>
|
||||
<TooltipProvider delayDuration={100}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<CircleHelp className="size-icon-xs text-content-secondary" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="max-w-xs text-sm">
|
||||
Dynamic Parameters enhances Coder's existing parameter system
|
||||
with real-time validation, conditional parameter behavior, and
|
||||
richer input types.
|
||||
<br />
|
||||
<Link
|
||||
href={docs(
|
||||
"/admin/templates/extending-templates/parameters#enable-dynamic-parameters-early-access",
|
||||
)}
|
||||
>
|
||||
View docs
|
||||
</Link>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</span>
|
||||
{experimentalFormContext && (
|
||||
<Button
|
||||
@@ -177,7 +208,8 @@ const WorkspaceParametersPageExperimental: FC = () => {
|
||||
variant="outline"
|
||||
onClick={experimentalFormContext.toggleOptedOut}
|
||||
>
|
||||
Go back to the classic workspace parameters view
|
||||
<Undo2 />
|
||||
Use the classic workspace parameters
|
||||
</Button>
|
||||
)}
|
||||
</header>
|
||||
|
||||
+9
@@ -5,6 +5,7 @@ import type {
|
||||
} from "api/typesGenerated";
|
||||
import { Alert } from "components/Alert/Alert";
|
||||
import { Button } from "components/Button/Button";
|
||||
import { Link } from "components/Link/Link";
|
||||
import { Spinner } from "components/Spinner/Spinner";
|
||||
import { useFormik } from "formik";
|
||||
import { useSyncFormParameters } from "modules/hooks/useSyncFormParameters";
|
||||
@@ -14,6 +15,7 @@ import {
|
||||
useValidationSchemaForDynamicParameters,
|
||||
} from "modules/workspaces/DynamicParameter/DynamicParameter";
|
||||
import type { FC } from "react";
|
||||
import { docs } from "utils/docs";
|
||||
export type WorkspaceParametersPageViewExperimentalProps = {
|
||||
workspace: Workspace;
|
||||
parameters: PreviewParameter[];
|
||||
@@ -139,6 +141,13 @@ export const WorkspaceParametersPageViewExperimental: FC<
|
||||
<p className="text-sm text-content-secondary m-0">
|
||||
These are the settings used by your template. Immutable
|
||||
parameters cannot be modified once the workspace is created.
|
||||
<Link
|
||||
href={docs(
|
||||
"/admin/templates/extending-templates/parameters#enable-dynamic-parameters-early-access",
|
||||
)}
|
||||
>
|
||||
View docs
|
||||
</Link>
|
||||
</p>
|
||||
</hgroup>
|
||||
{standardParameters.map((parameter, index) => {
|
||||
|
||||
Reference in New Issue
Block a user