Skip to content

refactor: show parameter suggestions from user history below field #12340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 51 additions & 14 deletions site/src/components/RichParameterInput/RichParameterInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import TextField, { TextFieldProps } from "@mui/material/TextField";
import Tooltip from "@mui/material/Tooltip";
import Button from "@mui/material/Button";
import FormHelperText from "@mui/material/FormHelperText";
import { type Interpolation, type Theme } from "@emotion/react";
import { type FC } from "react";
import { type FC, type ReactNode, useState } from "react";
import { TemplateVersionParameter } from "api/typesGenerated";
import { MemoizedMarkdown } from "components/Markdown/Markdown";
import { Stack } from "components/Stack/Stack";
import { MultiTextField } from "./MultiTextField";
import { ExternalImage } from "components/ExternalImage/ExternalImage";
import { AutofillSource } from "utils/richParameters";
import { AutofillBuildParameter, AutofillSource } from "utils/richParameters";
import { Pill } from "components/Pill/Pill";
import ErrorOutline from "@mui/icons-material/ErrorOutline";

Expand Down Expand Up @@ -103,6 +105,15 @@ const styles = {
width: 16,
},
},
suggestion: (theme) => ({
color: theme.roles.info.fill.solid,
marginLeft: "-4px",
padding: "4px 6px",
lineHeight: "inherit",
fontSize: "inherit",
height: "unset",
minWidth: "unset",
}),
} satisfies Record<string, Interpolation<Theme>>;

export interface ParameterLabelProps {
Expand Down Expand Up @@ -169,17 +180,26 @@ export type RichParameterInputProps = Omit<
"size" | "onChange"
> & {
parameter: TemplateVersionParameter;
autofillSource?: AutofillSource;
parameterAutofill?: AutofillBuildParameter;
onChange: (value: string) => void;
size?: Size;
};

const autofillDescription: Partial<Record<AutofillSource, ReactNode>> = {
url: " from the URL.",
};

export const RichParameterInput: FC<RichParameterInputProps> = ({
parameter,
size = "medium",
autofillSource,
parameter,
parameterAutofill,
onChange,
...fieldProps
}) => {
const autofillSource = parameterAutofill?.source;
const autofillValue = parameterAutofill?.value;
const [hideSuggestion, setHideSuggestion] = useState(false);

return (
<Stack
direction="column"
Expand All @@ -189,16 +209,33 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
>
<ParameterLabel parameter={parameter} />
<div css={{ display: "flex", flexDirection: "column" }}>
<RichParameterField {...fieldProps} size={size} parameter={parameter} />
{autofillSource && autofillSource !== "active_build" && (
<RichParameterField
{...fieldProps}
onChange={onChange}
size={size}
parameter={parameter}
/>
{!parameter.ephemeral &&
autofillSource === "user_history" &&
autofillValue &&
!hideSuggestion && (
<FormHelperText>
<Button
variant="text"
css={styles.suggestion}
onClick={() => {
onChange(autofillValue);
setHideSuggestion(true);
}}
>
{autofillValue}
</Button>{" "}
was recently used for this parameter.
</FormHelperText>
)}
{autofillSource && autofillDescription[autofillSource] && (
<div css={{ marginTop: 4, fontSize: 12 }}>
🪄 Autofilled:{" "}
{
{
["url"]: "value supplied by URL.",
["user_history"]: "recently used value.",
}[autofillSource]
}
🪄 Autofilled {autofillDescription[autofillSource]}
</div>
)}
</div>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,14 @@ export const Parameters: Story = {
autofillParameters: [
{
name: "first_parameter",
value: "It works!",
value: "Cool suggestion",
source: "user_history",
},
{
name: "third_parameter",
value: "aaaa",
source: "url",
},
],
},
};
Expand Down
26 changes: 12 additions & 14 deletions site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import {
} from "components/Form/Form";
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
import {
AutofillBuildParameter,
AutofillSource,
type AutofillBuildParameter,
getInitialRichParameterValues,
useValidationSchemaForRichParameters,
} from "utils/richParameters";
Expand All @@ -39,11 +38,11 @@ import {
import { Pill } from "components/Pill/Pill";
import { RichParameterInput } from "components/RichParameterInput/RichParameterInput";
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
import {
import type {
CreateWorkspaceMode,
ExternalAuthPollingState,
} from "./CreateWorkspacePage";
import { CreateWSPermissions } from "./permissions";
import type { CreateWSPermissions } from "./permissions";

export const Language = {
duplicationWarning:
Expand Down Expand Up @@ -137,15 +136,13 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
error,
);

const autofillSources = useMemo(() => {
return autofillParameters.reduce(
(acc, param) => {
acc[param.name] = param.source;
return acc;
},
{} as Record<string, AutofillSource>,
);
}, [autofillParameters]);
const autofillByName = useMemo(
() =>
Object.fromEntries(
autofillParameters.map((param) => [param.name, param]),
),
[autofillParameters],
);

const hasAllRequiredExternalAuth = externalAuth.every(
(auth) => auth.optional || auth.authenticated,
Expand Down Expand Up @@ -301,9 +298,9 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
value,
});
}}
autofillSource={autofillSources[parameter.name]}
key={parameter.name}
parameter={parameter}
parameterAutofill={autofillByName[parameter.name]}
disabled={isDisabled}
/>
);
Expand All @@ -330,6 +327,7 @@ const styles = {
lineHeight: "inherit",
fontSize: "inherit",
height: "unset",
minWidth: "unset",
}),
hasDescription: {
paddingBottom: 16,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { getWorkspaceParameters, postWorkspaceBuild } from "api/api";
import Button from "@mui/material/Button";
import OpenInNewOutlined from "@mui/icons-material/OpenInNewOutlined";
import { Helmet } from "react-helmet-async";
import { getWorkspaceParameters, postWorkspaceBuild } from "api/api";
import { EmptyState } from "components/EmptyState/EmptyState";
import { pageTitle } from "utils/page";
import {
WorkspacePermissions,
Expand All @@ -11,20 +14,16 @@ import { templateByName } from "api/queries/templates";
import { useMutation, useQuery } from "react-query";
import { Loader } from "components/Loader/Loader";
import {
WorkspaceParametersFormValues,
type WorkspaceParametersFormValues,
WorkspaceParametersForm,
} from "./WorkspaceParametersForm";
import { useNavigate } from "react-router-dom";
import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader";
import { type FC } from "react";
import { isApiValidationError } from "api/errors";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import { Workspace, WorkspaceBuildParameter } from "api/typesGenerated";
import { EmptyState } from "components/EmptyState/EmptyState";
import Button from "@mui/material/Button";
import OpenInNewOutlined from "@mui/icons-material/OpenInNewOutlined";
import type { Workspace, WorkspaceBuildParameter } from "api/typesGenerated";
import { docs } from "utils/docs";
import { AutofillBuildParameter } from "utils/richParameters";

const WorkspaceParametersPage: FC = () => {
const workspace = useWorkspaceSettings();
Expand Down Expand Up @@ -127,12 +126,10 @@ export const WorkspaceParametersPageView: FC<
<WorkspaceParametersForm
workspace={workspace}
canChangeVersions={canChangeVersions}
autofillParams={data.buildParameters.map(
(p): AutofillBuildParameter => ({
...p,
source: "active_build",
}),
)}
autofillParams={data.buildParameters.map((p) => ({
...p,
source: "active_build",
}))}
templateVersionRichParameters={data.templateVersionRichParameters}
error={submitError}
isSubmitting={isSubmitting}
Expand Down
4 changes: 2 additions & 2 deletions site/src/utils/richParameters.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TemplateVersionParameter } from "api/typesGenerated";
import type { TemplateVersionParameter } from "api/typesGenerated";
import { getInitialRichParameterValues } from "./richParameters";

test("getInitialRichParameterValues return default value when default build parameter is not valid", () => {
Expand Down Expand Up @@ -46,7 +46,7 @@ test("getInitialRichParameterValues return default value when default build para
const cpuParameter = templateParameters[0];
const [cpuParameterInitialValue] = getInitialRichParameterValues(
templateParameters,
[{ name: cpuParameter.name, value: "100", source: "user_history" }],
[{ name: cpuParameter.name, value: "100", source: "url" }],
);

expect(cpuParameterInitialValue.value).toBe(cpuParameter.default_value);
Expand Down
4 changes: 3 additions & 1 deletion site/src/utils/richParameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export const getInitialRichParameterValues = (
return {
name: parameter.name,
value:
autofillParam && isValidValue(parameter, autofillParam)
autofillParam &&
isValidValue(parameter, autofillParam) &&
autofillParam.source !== "user_history"
? autofillParam.value
: parameter.default_value,
};
Expand Down