From e87b0bb455e4783ea663ffbff9c0bdd16e431c4a Mon Sep 17 00:00:00 2001 From: Toshiki Shimomura Date: Sat, 23 Nov 2024 00:50:22 +0900 Subject: [PATCH] fix(site): set min and max attributes for workspace number parameters (#15182) Implements #14532. This PR sets `min` and `max` attributes for workspace number parameter `` elements using [inputProps](https://mui.com/material-ui/api/text-field/#text-field-prop-inputProps). Note: When we update MUI to v6 or later, it is better to use `slotProps.htmlInput` instead. --------- Co-authored-by: Muhammad Atif Ali --- .../RichParameterInput.stories.tsx | 32 +++++++++++++++++++ .../RichParameterInput/RichParameterInput.tsx | 28 ++++++++++++++++ .../WorkspaceParametersForm.tsx | 3 ++ .../WorkspaceParametersPage.test.tsx | 4 +-- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/site/src/components/RichParameterInput/RichParameterInput.stories.tsx b/site/src/components/RichParameterInput/RichParameterInput.stories.tsx index dbeac4dbdc..3ec838272e 100644 --- a/site/src/components/RichParameterInput/RichParameterInput.stories.tsx +++ b/site/src/components/RichParameterInput/RichParameterInput.stories.tsx @@ -99,6 +99,38 @@ export const NumberType: Story = { }, }; +export const NumberTypeWithIncreasingMonotonicity: Story = { + args: { + value: 4, + id: "number_parameter", + parameter: createTemplateVersionParameter({ + name: "number_parameter", + type: "number", + description: "Numeric parameter", + default_value: "", + validation_min: 0, + validation_max: 10, + validation_monotonic: "increasing", + }), + }, +}; + +export const NumberTypeWithDecreasingMonotonicity: Story = { + args: { + value: 4, + id: "number_parameter", + parameter: createTemplateVersionParameter({ + name: "number_parameter", + type: "number", + description: "Numeric parameter", + default_value: "", + validation_min: 0, + validation_max: 10, + validation_monotonic: "decreasing", + }), + }, +}; + export const BooleanType: Story = { args: { value: "false", diff --git a/site/src/components/RichParameterInput/RichParameterInput.tsx b/site/src/components/RichParameterInput/RichParameterInput.tsx index 92c7b52893..9919fca44b 100644 --- a/site/src/components/RichParameterInput/RichParameterInput.tsx +++ b/site/src/components/RichParameterInput/RichParameterInput.tsx @@ -3,6 +3,7 @@ import ErrorOutline from "@mui/icons-material/ErrorOutline"; import Button from "@mui/material/Button"; import FormControlLabel from "@mui/material/FormControlLabel"; import FormHelperText from "@mui/material/FormHelperText"; +import type { InputBaseComponentProps } from "@mui/material/InputBase"; import Radio from "@mui/material/Radio"; import RadioGroup from "@mui/material/RadioGroup"; import TextField, { type TextFieldProps } from "@mui/material/TextField"; @@ -217,6 +218,7 @@ export const RichParameterInput: FC = ({ onChange={onChange} size={size} parameter={parameter} + parameterAutofill={parameterAutofill} /> {!parameter.ephemeral && autofillSource === "user_history" && @@ -250,6 +252,7 @@ const RichParameterField: FC = ({ disabled, onChange, parameter, + parameterAutofill, value, size, ...props @@ -375,6 +378,30 @@ const RichParameterField: FC = ({ ); } + let inputProps: InputBaseComponentProps = {}; + if (parameter.type === "number") { + switch (parameter.validation_monotonic) { + case "increasing": + inputProps = { + max: parameter.validation_max, + min: parameterAutofill?.value, + }; + break; + case "decreasing": + inputProps = { + max: parameterAutofill?.value, + min: parameter.validation_min, + }; + break; + default: + inputProps = { + max: parameter.validation_max, + min: parameter.validation_min, + }; + break; + } + } + // A text field can technically handle all cases! // As other cases become more prominent (like filtering for numbers), // we should break this out into more finely scoped input fields. @@ -389,6 +416,7 @@ const RichParameterField: FC = ({ required={parameter.required} placeholder={parameter.default_value} value={value} + inputProps={inputProps} onChange={(event) => { onChange(event.target.value); }} diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx index db0667ea8e..658b998a7b 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx @@ -112,6 +112,9 @@ export const WorkspaceParametersForm: FC = ({ ); }} parameter={parameter} + parameterAutofill={autofillParams?.find( + ({ name }) => name === parameter.name, + )} /> ) : null, )} diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.test.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.test.tsx index 4c97a40e33..667f529d9e 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.test.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.test.tsx @@ -60,7 +60,7 @@ test("Submit the workspace settings page successfully", async () => { { exact: false }, ); await user.clear(parameter2); - await user.type(parameter2, "1"); + await user.type(parameter2, "3"); await user.click( within(form).getByRole("button", { name: "Submit and restart" }), ); @@ -70,7 +70,7 @@ test("Submit the workspace settings page successfully", async () => { transition: "start", rich_parameter_values: [ { name: MockTemplateVersionParameter1.name, value: "new-value" }, - { name: MockTemplateVersionParameter2.name, value: "1" }, + { name: MockTemplateVersionParameter2.name, value: "3" }, ], }); });