Skip to content

Commit 9de069f

Browse files
committed
get mvp working
1 parent 77d27cd commit 9de069f

File tree

5 files changed

+171
-109
lines changed

5 files changed

+171
-109
lines changed

site/src/components/Form/Form.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export const VerticalForm: FC<HTMLProps<HTMLFormElement>> = ({
7070
export const FormSection: FC<
7171
PropsWithChildren & {
7272
title: string | JSX.Element;
73-
description: string | JSX.Element;
73+
description: string | JSX.Element | undefined;
7474
classes?: {
7575
root?: string;
7676
sectionInfo?: string;
@@ -125,7 +125,9 @@ export const FormSection: FC<
125125
{alpha && <AlphaBadge />}
126126
{deprecated && <DeprecatedBadge />}
127127
</h2>
128-
<div css={styles.formSectionInfoDescription}>{description}</div>
128+
{description && (
129+
<div css={styles.formSectionInfoDescription}>{description}</div>
130+
)}
129131
</div>
130132

131133
{children}

site/src/pages/HealthPage/ProvisionerDaemonsPage.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ const parseBool = (s: string): { valid: boolean; value: boolean } => {
187187
interface ProvisionerTagProps {
188188
k: string;
189189
v: string;
190-
onDelete?: () => void;
190+
onDelete?: (key: string) => void;
191191
}
192192

193193
export const ProvisionerTag : FC<ProvisionerTagProps> = ({ k, v, onDelete}) => {
@@ -198,7 +198,9 @@ export const ProvisionerTag : FC<ProvisionerTagProps> = ({ k, v, onDelete}) => {
198198
{onDelete ? (
199199
<>
200200
{kv}
201-
<IconButton aria-label="delete" size="small" color="secondary">
201+
<IconButton aria-label="delete" size="small" color="secondary" onClick={() => {
202+
onDelete(k)
203+
}}>
202204
<CloseIcon fontSize="inherit" css={{
203205
width: 14,
204206
height: 14,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
2+
import { Stack } from 'components/Stack/Stack';
3+
import { TopbarButton } from 'components/FullPageLayout/Topbar';
4+
import {
5+
Popover,
6+
PopoverContent,
7+
PopoverTrigger,
8+
} from "components/Popover/Popover";
9+
import { ProvisionerTag } from 'pages/HealthPage/ProvisionerDaemonsPage';
10+
import { type FC} from 'react';
11+
import useTheme from '@mui/system/useTheme';
12+
import { useFormik } from 'formik';
13+
import * as Yup from "yup";
14+
import { getFormHelpers, onChangeTrimmed } from 'utils/formUtils';
15+
import { FormFields, FormSection, VerticalForm } from 'components/Form/Form';
16+
import TextField from '@mui/material/TextField';
17+
import Button from '@mui/material/Button';
18+
import ExpandMoreOutlined from '@mui/icons-material/ExpandMoreOutlined';
19+
import AddIcon from '@mui/icons-material/Add';
20+
21+
const initialValues = {
22+
key: "",
23+
value: "",
24+
};
25+
26+
const validationSchema = Yup.object({
27+
key: Yup.string().required("Required").notOneOf(["owner"], "Cannot override owner tag"),
28+
value: Yup.string().required("Required").when("key", ([key], schema) => {
29+
if (key === "scope") {
30+
return schema.oneOf(["organization", "scope"], "Scope value must be 'organization' or 'user'");
31+
}
32+
33+
return schema;
34+
})
35+
});
36+
37+
interface ProviderTagsPopoverProps {
38+
tags: Record <string, string>;
39+
onSubmit: (values: typeof initialValues) => void;
40+
onDelete: (key: string) => void;
41+
}
42+
43+
export const ProviderTagsPopover: FC<ProviderTagsPopoverProps> = ({ tags, onSubmit, onDelete }) => {
44+
const theme = useTheme();
45+
46+
const form = useFormik({
47+
initialValues,
48+
validationSchema,
49+
onSubmit: (values) => {
50+
onSubmit(values);
51+
form.resetForm();
52+
},
53+
});
54+
const getFieldHelpers = getFormHelpers(form);
55+
56+
return (
57+
<Popover isDefaultOpen={false}>
58+
<PopoverTrigger>
59+
<TopbarButton
60+
data-testid="build-parameters-button"
61+
color="neutral"
62+
css={{ paddingLeft: 0, paddingRight: 0, minWidth: "28px !important" }}
63+
>
64+
<ExpandMoreOutlined css={{ fontSize: 14 }} />
65+
</TopbarButton>
66+
</PopoverTrigger>
67+
<PopoverContent
68+
horizontal="right"
69+
css={{ ".MuiPaper-root": { width: 300 } }}
70+
>
71+
<div
72+
css={{
73+
color: theme.palette.text.secondary,
74+
padding: 20,
75+
borderBottom: `1px solid ${theme.palette.divider}`,
76+
}}
77+
>
78+
<VerticalForm onSubmit={form.handleSubmit}>
79+
80+
<Stack>
81+
<FormSection title="Provisioner Tags" description="Tags are a way to control which provisoner daemons process which build jobs. To learn more read the docs. "/>
82+
{Object.keys(tags).length > 0 && (
83+
<Stack direction="row" spacing={1} wrap="wrap">
84+
{Object.keys(tags).filter((key) => {
85+
// filter out owner since you cannot override it
86+
return key !== "owner"
87+
}).map((k) =>
88+
<>
89+
{k === "scope" ? (
90+
<ProvisionerTag key={k} k={k} v={tags[k]}/>
91+
) : (
92+
<ProvisionerTag key={k} k={k} v={tags[k]} onDelete={onDelete}/>
93+
)}
94+
</>
95+
)}
96+
</Stack>
97+
)}
98+
99+
100+
<FormFields>
101+
<Stack direction="row">
102+
<TextField
103+
{...getFieldHelpers("key")}
104+
size="small"
105+
onChange={onChangeTrimmed(form)}
106+
label="Key"
107+
/>
108+
<TextField
109+
{...getFieldHelpers("value")}
110+
size="small"
111+
onChange={onChangeTrimmed(form)}
112+
label="Value"
113+
/>
114+
<Button
115+
variant="contained"
116+
color="secondary"
117+
type="submit"
118+
disabled={!form.dirty || !form.isValid}
119+
>
120+
<AddIcon/>
121+
</Button>
122+
</Stack>
123+
</FormFields>
124+
</Stack>
125+
</VerticalForm>
126+
</div>
127+
</PopoverContent>
128+
</Popover>
129+
);
130+
};

site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx

+20-104
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,7 @@ import {
5454
} from "components/FullPageLayout/Topbar";
5555
import { Sidebar } from "components/FullPageLayout/Sidebar";
5656
import ButtonGroup from "@mui/material/ButtonGroup";
57-
import {
58-
Popover,
59-
PopoverContent,
60-
PopoverTrigger,
61-
} from "components/Popover/Popover";
62-
import { HelpTooltipTitle, HelpTooltipText, } from "components/HelpTooltip/HelpTooltip";
63-
import ExpandMoreOutlined from "@mui/icons-material/ExpandMoreOutlined";
64-
import { ProvisionerTag } from "pages/HealthPage/ProvisionerDaemonsPage";
65-
import { Stack } from "components/Stack/Stack";
66-
import { additionalTags } from "utils/provisionertags";
67-
import TextField from "@mui/material/TextField";
68-
import AddIcon from '@mui/icons-material/Add';
57+
import { ProviderTagsPopover } from "./ProvisionerTagsPopover";
6958

7059
type Tab = "logs" | "resources" | undefined; // Undefined is to hide the tab
7160

@@ -91,6 +80,8 @@ export interface TemplateVersionEditorProps {
9180
onSubmitMissingVariableValues: (values: VariableValue[]) => void;
9281
onCancelSubmitMissingVariableValues: () => void;
9382
defaultTab?: Tab;
83+
provisionerTags: Record<string, string>;
84+
onUpdateProvisionerTags: (tags: Record<string, string>) => void;
9485
}
9586

9687
const findInitialFile = (fileTree: FileTree): string | undefined => {
@@ -127,6 +118,8 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
127118
onSubmitMissingVariableValues,
128119
onCancelSubmitMissingVariableValues,
129120
defaultTab,
121+
provisionerTags,
122+
onUpdateProvisionerTags,
130123
}) => {
131124
const theme = useTheme();
132125
const [selectedTab, setSelectedTab] = useState<Tab>(defaultTab);
@@ -194,18 +187,6 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
194187
}
195188
}, [buildLogs]);
196189

197-
const disabled = false;
198-
const [extraTags, setExtraTags] = useState(additionalTags(templateVersion.job.tags));
199-
const [keyInput, setKeyInput] = useState("");
200-
const [valueInput, setValueInput] = useState("");
201-
// extraTags = {
202-
// "key1": "value1",
203-
// "1": "2",
204-
// "3": "true",
205-
// "5": "6",
206-
// "seven": "0",
207-
// } as Record<string,string>;
208-
209190
return (
210191
<>
211192
<div css={{ height: "100%", display: "flex", flexDirection: "column" }}>
@@ -269,7 +250,7 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
269250
borderLeft: "1px solid #FFF",
270251
},
271252
}}
272-
disabled={disabled}
253+
disabled={disablePreview}
273254
>
274255
<TopbarButton
275256
startIcon={
@@ -285,85 +266,20 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
285266
>
286267
Build
287268
</TopbarButton>
288-
<Popover isDefaultOpen={false}>
289-
<PopoverTrigger>
290-
<TopbarButton
291-
data-testid="build-parameters-button"
292-
disabled={disabled}
293-
color="neutral"
294-
css={{ paddingLeft: 0, paddingRight: 0, minWidth: "28px !important" }}
295-
>
296-
<ExpandMoreOutlined css={{ fontSize: 14 }} />
297-
</TopbarButton>
298-
</PopoverTrigger>
299-
<PopoverContent
300-
horizontal="right"
301-
css={{ ".MuiPaper-root": { width: 300 } }}
302-
>
303-
<div
304-
css={{
305-
color: theme.palette.text.secondary,
306-
padding: 20,
307-
borderBottom: `1px solid ${theme.palette.divider}`,
308-
}}
309-
>
310-
<HelpTooltipTitle>Provisioner Tags</HelpTooltipTitle>
311-
<HelpTooltipText>
312-
<Stack>
313-
{Object.keys(extraTags).length > 0 ? (
314-
<Stack direction="row" spacing={1} wrap="wrap">
315-
{Object.keys(extraTags).map((k) =>
316-
<ProvisionerTag key={k} k={k} v={extraTags[k]} onDelete={() => {
317-
return
318-
}}/>
319-
)}
320-
</Stack>
321-
) : ("No tags")}
322-
323-
<Stack direction="row">
324-
<TextField
325-
size="small"
326-
name="key-input"
327-
autoComplete="off"
328-
id="key-input"
329-
value={keyInput}
330-
onChange={(event) => {
331-
setKeyInput(event.target.value);
332-
}}
333-
label="Key"
334-
/>
335-
<TextField
336-
size="small"
337-
name="value-input"
338-
autoComplete="off"
339-
id="value-input"
340-
value={valueInput}
341-
onChange={(event) => {
342-
setValueInput(event.target.value);
343-
}}
344-
label="Value"
345-
/>
346-
<Button
347-
onClick={() => {
348-
if (keyInput && valueInput) {
349-
const newTags = {...extraTags};
350-
newTags[keyInput] = valueInput;
351-
setExtraTags(newTags);
352-
setKeyInput("");
353-
setValueInput("");
354-
}
355-
}}
356-
variant="contained"
357-
color="secondary"
358-
>
359-
<AddIcon/>
360-
</Button>
361-
</Stack>
362-
</Stack>
363-
</HelpTooltipText>
364-
</div>
365-
</PopoverContent>
366-
</Popover>
269+
<ProviderTagsPopover
270+
tags={provisionerTags}
271+
onSubmit={({ key, value }) => {
272+
onUpdateProvisionerTags({
273+
...provisionerTags,
274+
[key]: value,
275+
});
276+
}}
277+
onDelete={(key) => {
278+
const newTags = { ...provisionerTags };
279+
delete newTags[key];
280+
onUpdateProvisionerTags(newTags);
281+
}}
282+
/>
367283
</ButtonGroup>
368284

369285
<TopbarButton

site/src/pages/TemplateVersionEditorPage/TemplateVersionEditorPage.tsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ export const TemplateVersionEditorPage: FC = () => {
102102
queryClient.setQueryData(templateVersionOptions.queryKey, newVersion);
103103
};
104104

105+
// Provisioner Tags
106+
const [provisionerTags, setProvisionerTags] = useState<Record<string, string>>({});
107+
useEffect(() => {
108+
if (templateVersionQuery.data?.job.tags) {
109+
setProvisionerTags(templateVersionQuery.data.job.tags);
110+
}
111+
}, [templateVersionQuery.data?.job.tags]);
112+
105113
return (
106114
<>
107115
<Helmet>
@@ -127,7 +135,7 @@ export const TemplateVersionEditorPage: FC = () => {
127135
const newVersion = await createTemplateVersionMutation.mutateAsync({
128136
provisioner: "terraform",
129137
storage_method: "file",
130-
tags: templateVersionQuery.data.job.tags,
138+
tags: provisionerTags,
131139
template_id: templateQuery.data.id,
132140
file_id: serverFile.hash,
133141
});
@@ -210,6 +218,10 @@ export const TemplateVersionEditorPage: FC = () => {
210218
onCancelSubmitMissingVariableValues={() => {
211219
setIsMissingVariablesDialogOpen(false);
212220
}}
221+
provisionerTags={provisionerTags}
222+
onUpdateProvisionerTags={(tags) => {
223+
setProvisionerTags(tags);
224+
}}
213225
/>
214226
) : (
215227
<FullScreenLoader />

0 commit comments

Comments
 (0)