feat(site): Support list(string) rich parameter field (#6653)

This commit is contained in:
Bruno Quaresma
2023-03-17 15:53:11 -03:00
committed by GitHub
parent 090e37fc46
commit ca067cf004
5 changed files with 157 additions and 0 deletions
@@ -0,0 +1,16 @@
import { Story } from "@storybook/react"
import { useState } from "react"
import { MultiTextField, MultiTextFieldProps } from "./MultiTextField"
export default {
title: "components/MultiTextField",
component: MultiTextField,
}
const Template: Story<MultiTextFieldProps> = (args) => {
const [values, setValues] = useState(args.values ?? ["foo", "bar"])
return <MultiTextField {...args} values={values} onChange={setValues} />
}
export const Example = Template.bind({})
Example.args = {}
@@ -0,0 +1,95 @@
import Chip from "@material-ui/core/Chip"
import { makeStyles } from "@material-ui/core/styles"
import { FC } from "react"
export type MultiTextFieldProps = {
label: string
values: string[]
onChange: (values: string[]) => void
}
export const MultiTextField: FC<MultiTextFieldProps> = ({
label,
values,
onChange,
}) => {
const styles = useStyles()
return (
<label className={styles.root}>
{values.map((value, index) => (
<Chip
key={index}
label={value}
size="small"
onDelete={() => {
onChange(values.filter((oldValue) => oldValue !== value))
}}
/>
))}
<input
aria-label={label}
className={styles.input}
onKeyDown={(event) => {
if (event.key === ",") {
event.preventDefault()
const newValue = event.currentTarget.value
onChange([...values, newValue])
event.currentTarget.value = ""
return
}
if (event.key === "Backspace" && event.currentTarget.value === "") {
event.preventDefault()
const lastValue = values[values.length - 1]
onChange(values.slice(0, -1))
event.currentTarget.value = lastValue
return
}
}}
onBlur={(event) => {
if (event.currentTarget.value !== "") {
const newValue = event.currentTarget.value
onChange([...values, newValue])
event.currentTarget.value = ""
}
}}
/>
</label>
)
}
const useStyles = makeStyles((theme) => ({
root: {
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadius,
minHeight: theme.spacing(5),
padding: theme.spacing(1.25, 1.75),
fontSize: theme.spacing(2),
display: "flex",
flexWrap: "wrap",
gap: theme.spacing(1),
position: "relative",
margin: theme.spacing(1, 0, 0.5), // Have same margin than TextField
"&:has(input:focus)": {
borderColor: theme.palette.primary.main,
borderWidth: 2,
// Compensate for the border width
top: -1,
left: -1,
},
},
input: {
flexGrow: 1,
fontSize: "inherit",
padding: 0,
border: "none",
background: "none",
"&:focus": {
outline: "none",
},
},
}))
@@ -31,6 +31,7 @@ const createTemplateVersionParameter = (
validation_max: 0,
validation_monotonic: "increasing",
description_plaintext: "",
required: true,
...partial,
}
}
@@ -99,6 +100,17 @@ OptionsType.args = {
}),
}
export const ListStringType = Template.bind({})
ListStringType.args = {
initialValue: JSON.stringify(["first", "second", "third"]),
id: "list_string_parameter",
parameter: createTemplateVersionParameter({
name: "list_string_parameter",
type: "list(string)",
description: "List string parameter",
}),
}
export const IconLabel = Template.bind({})
IconLabel.args = {
initialValue: "initial-value",
@@ -8,6 +8,7 @@ import { FC, useState } from "react"
import { TemplateVersionParameter } from "../../api/typesGenerated"
import { colors } from "theme/colors"
import { MemoizedMarkdown } from "components/Markdown/Markdown"
import { MultiTextField } from "components/MultiTextField/MultiTextField"
const isBoolean = (parameter: TemplateVersionParameter) => {
return parameter.type === "bool"
@@ -154,6 +155,34 @@ const RichParameterField: React.FC<RichParameterInputProps> = ({
)
}
if (parameter.type === "list(string)") {
let values: string[] = []
if (parameterValue) {
try {
values = JSON.parse(parameterValue) as string[]
} catch (e) {
console.error("Error parsing list(string) parameter", e)
}
}
return (
<MultiTextField
label={props.label as string}
values={values}
onChange={(values) => {
try {
const value = JSON.stringify(values)
setParameterValue(value)
onChange(value)
} catch (e) {
console.error("Error on change of list(string) parameter", e)
}
}}
/>
)
}
// 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.
+5
View File
@@ -229,5 +229,10 @@ export const getOverrides = ({
borderRadius: 999,
},
},
MuiChip: {
root: {
backgroundColor: colors.gray[12],
},
},
}
}