Skip to content

Commit 8539692

Browse files
committed
feat: add tag select component for dynamic params
1 parent b6182fe commit 8539692

File tree

2 files changed

+54
-56
lines changed

2 files changed

+54
-56
lines changed
Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import type { Interpolation, Theme } from "@emotion/react";
21
import Chip from "@mui/material/Chip";
32
import FormHelperText from "@mui/material/FormHelperText";
4-
import type { FC } from "react";
3+
import { type FC, useId, useMemo } from "react";
54

65
export type MultiTextFieldProps = {
76
label: string;
@@ -16,12 +15,25 @@ export const MultiTextField: FC<MultiTextFieldProps> = ({
1615
values,
1716
onChange,
1817
}) => {
18+
const baseId = useId();
19+
20+
const itemIds = useMemo(() => {
21+
return Array.from(
22+
{ length: values.length },
23+
(_, index) => `${baseId}-item-${index}`,
24+
);
25+
}, [baseId, values.length]);
26+
1927
return (
2028
<div>
21-
<label css={styles.root}>
29+
<label
30+
className="flex flex-wrap min-h-10 px-1.5 py-1.5 gap-2 border border-border border-solid relative rounded-md
31+
focus-within:border-content-link focus-within:border-2 focus-within:-top-px focus-within:-left-px"
32+
>
2233
{values.map((value, index) => (
2334
<Chip
24-
key={index}
35+
key={itemIds[index]}
36+
className="rounded-md bg-surface-secondary text-content-secondary h-7"
2537
label={value}
2638
size="small"
2739
onDelete={() => {
@@ -32,7 +44,7 @@ export const MultiTextField: FC<MultiTextFieldProps> = ({
3244
<input
3345
id={id}
3446
aria-label={label}
35-
css={styles.input}
47+
className="flex-grow text-inherit p-0 border-none bg-transparent focus:outline-none"
3648
onKeyDown={(event) => {
3749
if (event.key === ",") {
3850
event.preventDefault();
@@ -64,42 +76,9 @@ export const MultiTextField: FC<MultiTextFieldProps> = ({
6476
/>
6577
</label>
6678

67-
<FormHelperText>{'Type "," to separate the values'}</FormHelperText>
79+
<FormHelperText className="text-content-secondary text-xs">
80+
{'Type "," to separate the values'}
81+
</FormHelperText>
6882
</div>
6983
);
7084
};
71-
72-
const styles = {
73-
root: (theme) => ({
74-
border: `1px solid ${theme.palette.divider}`,
75-
borderRadius: 8,
76-
minHeight: 48, // Chip height + paddings
77-
padding: "10px 14px",
78-
fontSize: 16,
79-
display: "flex",
80-
flexWrap: "wrap",
81-
gap: 8,
82-
position: "relative",
83-
margin: "8px 0 4px", // Have same margin than TextField
84-
85-
"&:has(input:focus)": {
86-
borderColor: theme.palette.primary.main,
87-
borderWidth: 2,
88-
// Compensate for the border width
89-
top: -1,
90-
left: -1,
91-
},
92-
}),
93-
94-
input: {
95-
flexGrow: 1,
96-
fontSize: "inherit",
97-
padding: 0,
98-
border: "none",
99-
background: "none",
100-
101-
"&:focus": {
102-
outline: "none",
103-
},
104-
},
105-
} satisfies Record<string, Interpolation<Theme>>;

site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
type Option,
1616
} from "components/MultiSelectCombobox/MultiSelectCombobox";
1717
import { RadioGroup, RadioGroupItem } from "components/RadioGroup/RadioGroup";
18+
import { MultiTextField } from "components/RichParameterInput/MultiTextField";
1819
import {
1920
Select,
2021
SelectContent,
@@ -198,21 +199,7 @@ const ParameterField: FC<ParameterFieldProps> = ({
198199
);
199200

200201
case "multi-select": {
201-
let values: string[] = [];
202-
203-
if (value) {
204-
try {
205-
const parsed = JSON.parse(value);
206-
if (Array.isArray(parsed)) {
207-
values = parsed;
208-
}
209-
} catch (e) {
210-
console.error(
211-
"Error parsing parameter value with form_type multi-select",
212-
e,
213-
);
214-
}
215-
}
202+
const values = parseStringArrayValue(value);
216203

217204
// Map parameter options to MultiSelectCombobox options format
218205
const options: Option[] = parameter.options.map((opt) => ({
@@ -259,6 +246,21 @@ const ParameterField: FC<ParameterFieldProps> = ({
259246
);
260247
}
261248

249+
case "tag-select": {
250+
const values = parseStringArrayValue(value);
251+
252+
return (
253+
<MultiTextField
254+
id={parameter.name}
255+
label={parameter.display_name || parameter.name}
256+
values={values}
257+
onChange={(values) => {
258+
onChange(JSON.stringify(values));
259+
}}
260+
/>
261+
);
262+
}
263+
262264
case "switch":
263265
return (
264266
<Switch
@@ -387,6 +389,23 @@ const ParameterField: FC<ParameterFieldProps> = ({
387389
}
388390
};
389391

392+
const parseStringArrayValue = (value: string): string[] => {
393+
let values: string[] = [];
394+
395+
if (value) {
396+
try {
397+
const parsed = JSON.parse(value);
398+
if (Array.isArray(parsed)) {
399+
values = parsed;
400+
}
401+
} catch (e) {
402+
console.error("Error parsing parameter of type list(string)", e);
403+
}
404+
}
405+
406+
return values;
407+
};
408+
390409
interface OptionDisplayProps {
391410
option: PreviewParameterOption;
392411
}

0 commit comments

Comments
 (0)