From 8539692e32bc54a29d99d3fc44ee5b6d45a19f63 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Thu, 8 May 2025 11:39:08 +0000 Subject: [PATCH 1/4] feat: add tag select component for dynamic params --- .../RichParameterInput/MultiTextField.tsx | 61 ++++++------------- .../DynamicParameter/DynamicParameter.tsx | 49 ++++++++++----- 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/site/src/components/RichParameterInput/MultiTextField.tsx b/site/src/components/RichParameterInput/MultiTextField.tsx index aed995299dbf3..9704804cee169 100644 --- a/site/src/components/RichParameterInput/MultiTextField.tsx +++ b/site/src/components/RichParameterInput/MultiTextField.tsx @@ -1,7 +1,6 @@ -import type { Interpolation, Theme } from "@emotion/react"; import Chip from "@mui/material/Chip"; import FormHelperText from "@mui/material/FormHelperText"; -import type { FC } from "react"; +import { type FC, useId, useMemo } from "react"; export type MultiTextFieldProps = { label: string; @@ -16,12 +15,25 @@ export const MultiTextField: FC = ({ values, onChange, }) => { + const baseId = useId(); + + const itemIds = useMemo(() => { + return Array.from( + { length: values.length }, + (_, index) => `${baseId}-item-${index}`, + ); + }, [baseId, values.length]); + return (
-
); }; - -const styles = { - root: (theme) => ({ - border: `1px solid ${theme.palette.divider}`, - borderRadius: 8, - minHeight: 48, // Chip height + paddings - padding: "10px 14px", - fontSize: 16, - display: "flex", - flexWrap: "wrap", - gap: 8, - position: "relative", - margin: "8px 0 4px", // 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", - }, - }, -} satisfies Record>; diff --git a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx index 9ec69158c4e84..2fd8d48a4e6f6 100644 --- a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx +++ b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx @@ -15,6 +15,7 @@ import { type Option, } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { RadioGroup, RadioGroupItem } from "components/RadioGroup/RadioGroup"; +import { MultiTextField } from "components/RichParameterInput/MultiTextField"; import { Select, SelectContent, @@ -198,21 +199,7 @@ const ParameterField: FC = ({ ); case "multi-select": { - let values: string[] = []; - - if (value) { - try { - const parsed = JSON.parse(value); - if (Array.isArray(parsed)) { - values = parsed; - } - } catch (e) { - console.error( - "Error parsing parameter value with form_type multi-select", - e, - ); - } - } + const values = parseStringArrayValue(value); // Map parameter options to MultiSelectCombobox options format const options: Option[] = parameter.options.map((opt) => ({ @@ -259,6 +246,21 @@ const ParameterField: FC = ({ ); } + case "tag-select": { + const values = parseStringArrayValue(value); + + return ( + { + onChange(JSON.stringify(values)); + }} + /> + ); + } + case "switch": return ( = ({ } }; +const parseStringArrayValue = (value: string): string[] => { + let values: string[] = []; + + if (value) { + try { + const parsed = JSON.parse(value); + if (Array.isArray(parsed)) { + values = parsed; + } + } catch (e) { + console.error("Error parsing parameter of type list(string)", e); + } + } + + return values; +}; + interface OptionDisplayProps { option: PreviewParameterOption; } From 3b430bcf762c5d8bb1f3dddb86b4290234497926 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Thu, 8 May 2025 11:44:18 +0000 Subject: [PATCH 2/4] chore: rename MultiTextField to TagInput --- site/src/components/RichParameterInput/RichParameterInput.tsx | 4 ++-- .../MultiTextField.tsx => TagInput/TagInput.tsx} | 4 ++-- .../modules/workspaces/DynamicParameter/DynamicParameter.tsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename site/src/components/{RichParameterInput/MultiTextField.tsx => TagInput/TagInput.tsx} (95%) diff --git a/site/src/components/RichParameterInput/RichParameterInput.tsx b/site/src/components/RichParameterInput/RichParameterInput.tsx index beaff8ca2772e..84fe47bbbfee3 100644 --- a/site/src/components/RichParameterInput/RichParameterInput.tsx +++ b/site/src/components/RichParameterInput/RichParameterInput.tsx @@ -19,7 +19,7 @@ import type { AutofillBuildParameter, AutofillSource, } from "utils/richParameters"; -import { MultiTextField } from "./MultiTextField"; +import { TagInput } from "../TagInput/TagInput"; const isBoolean = (parameter: TemplateVersionParameter) => { return parameter.type === "bool"; @@ -372,7 +372,7 @@ const RichParameterField: FC = ({ } return ( - void; }; -export const MultiTextField: FC = ({ +export const TagInput: FC = ({ label, id, values, diff --git a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx index 2fd8d48a4e6f6..dd1f52d73b07d 100644 --- a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx +++ b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx @@ -15,7 +15,6 @@ import { type Option, } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { RadioGroup, RadioGroupItem } from "components/RadioGroup/RadioGroup"; -import { MultiTextField } from "components/RichParameterInput/MultiTextField"; import { Select, SelectContent, @@ -25,6 +24,7 @@ import { } from "components/Select/Select"; import { Slider } from "components/Slider/Slider"; import { Switch } from "components/Switch/Switch"; +import { TagInput } from "components/TagInput/TagInput"; import { Textarea } from "components/Textarea/Textarea"; import { Tooltip, @@ -250,7 +250,7 @@ const ParameterField: FC = ({ const values = parseStringArrayValue(value); return ( - Date: Thu, 8 May 2025 11:52:36 +0000 Subject: [PATCH 3/4] chore: add TagInput stories --- .../components/TagInput/TagInput.stories.tsx | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 site/src/components/TagInput/TagInput.stories.tsx diff --git a/site/src/components/TagInput/TagInput.stories.tsx b/site/src/components/TagInput/TagInput.stories.tsx new file mode 100644 index 0000000000000..7b5e8285b8d64 --- /dev/null +++ b/site/src/components/TagInput/TagInput.stories.tsx @@ -0,0 +1,56 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { TagInput } from "./TagInput"; + +const meta: Meta = { + title: "components/TagInput", + component: TagInput, + decorators: [(Story) =>
{Story()}
], +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + values: [], + }, +}; + +export const WithEmptyTags: Story = { + args: { + values: ["", "", ""], + }, +}; + +export const WithLongTags: Story = { + args: { + values: ["this-is-a-very-long-long-long-tag-that-might-wrap", "another-long-tag-example", "short"], + }, +}; + +export const WithManyTags: Story = { + args: { + values: [ + "tag1", + "tag2", + "tag3", + "tag4", + "tag5", + "tag6", + "tag7", + "tag8", + "tag9", + "tag10", + "tag11", + "tag12", + "tag13", + "tag14", + "tag15", + "tag16", + "tag17", + "tag18", + "tag19", + "tag20", + ], + }, +}; From 7648fb6deb809ffdbc5fb4053e22714881790e0c Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Thu, 8 May 2025 12:01:33 +0000 Subject: [PATCH 4/4] fix: format --- .../components/TagInput/TagInput.stories.tsx | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/site/src/components/TagInput/TagInput.stories.tsx b/site/src/components/TagInput/TagInput.stories.tsx index 7b5e8285b8d64..5b1a9f8b14229 100644 --- a/site/src/components/TagInput/TagInput.stories.tsx +++ b/site/src/components/TagInput/TagInput.stories.tsx @@ -2,55 +2,59 @@ import type { Meta, StoryObj } from "@storybook/react"; import { TagInput } from "./TagInput"; const meta: Meta = { - title: "components/TagInput", - component: TagInput, - decorators: [(Story) =>
{Story()}
], + title: "components/TagInput", + component: TagInput, + decorators: [(Story) =>
{Story()}
], }; export default meta; type Story = StoryObj; export const Default: Story = { - args: { - values: [], - }, + args: { + values: [], + }, }; export const WithEmptyTags: Story = { - args: { - values: ["", "", ""], - }, + args: { + values: ["", "", ""], + }, }; export const WithLongTags: Story = { - args: { - values: ["this-is-a-very-long-long-long-tag-that-might-wrap", "another-long-tag-example", "short"], - }, + args: { + values: [ + "this-is-a-very-long-long-long-tag-that-might-wrap", + "another-long-tag-example", + "short", + ], + }, }; export const WithManyTags: Story = { - args: { - values: [ - "tag1", - "tag2", - "tag3", - "tag4", - "tag5", - "tag6", - "tag7", - "tag8", - "tag9", - "tag10", - "tag11", - "tag12", - "tag13", - "tag14", - "tag15", - "tag16", - "tag17", - "tag18", - "tag19", - "tag20", - ], - }, + args: { + values: [ + "tag1", + "tag2", + "tag3", + "tag4", + "tag5", + "tag6", + "tag7", + "tag8", + "tag9", + "tag10", + "tag11", + "tag12", + "tag13", + "tag14", + "tag15", + "tag16", + "tag17", + "tag18", + "tag19", + "tag20", + ], + }, }; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy