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
`<input>` 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 <atif@coder.com>
This commit is contained in:
Toshiki Shimomura
2024-11-23 00:50:22 +09:00
committed by GitHub
parent e3cc3be718
commit e87b0bb455
4 changed files with 65 additions and 2 deletions

View File

@ -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",

View File

@ -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<RichParameterInputProps> = ({
onChange={onChange}
size={size}
parameter={parameter}
parameterAutofill={parameterAutofill}
/>
{!parameter.ephemeral &&
autofillSource === "user_history" &&
@ -250,6 +252,7 @@ const RichParameterField: FC<RichParameterInputProps> = ({
disabled,
onChange,
parameter,
parameterAutofill,
value,
size,
...props
@ -375,6 +378,30 @@ const RichParameterField: FC<RichParameterInputProps> = ({
);
}
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<RichParameterInputProps> = ({
required={parameter.required}
placeholder={parameter.default_value}
value={value}
inputProps={inputProps}
onChange={(event) => {
onChange(event.target.value);
}}

View File

@ -112,6 +112,9 @@ export const WorkspaceParametersForm: FC<WorkspaceParameterFormProps> = ({
);
}}
parameter={parameter}
parameterAutofill={autofillParams?.find(
({ name }) => name === parameter.name,
)}
/>
) : null,
)}

View File

@ -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" },
],
});
});