Skip to content

Commit 9eb5646

Browse files
committed
Merge branch 'main' into brett/custom-users-tab
2 parents 874d5c4 + 177d1a8 commit 9eb5646

File tree

4 files changed

+243
-71
lines changed

4 files changed

+243
-71
lines changed

src/client/App.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,16 @@ export const App = () => {
177177
rel="noreferrer"
178178
className="font-light text-content-secondary text-sm hover:text-content-primary"
179179
>
180+
<span className="sr-only"> (link opens in new tab)</span>
180181
Coder
181182
</a>
182183
<a
183-
href="https://coder.com"
184+
href="https://coder.com/docs/admin/templates/extending-templates/parameters"
184185
target="_blank"
185186
rel="noreferrer"
186187
className="font-light text-content-secondary text-sm hover:text-content-primary"
187188
>
189+
<span className="sr-only"> (link opens in new tab)</span>
188190
Docs
189191
</a>
190192
<ExampleSelector />
@@ -193,7 +195,6 @@ export const App = () => {
193195
</nav>
194196

195197
<ResizablePanelGroup direction={"horizontal"}>
196-
{/* EDITOR */}
197198
<Editor
198199
code={code}
199200
setCode={setCode}
@@ -332,6 +333,7 @@ const ExampleSelector: FC = () => {
332333
return (
333334
<DropdownMenuItem key={slug} asChild={true}>
334335
<a href={href} target="_blank" rel="noreferrer">
336+
<span className="sr-only"> (link opens in new tab)</span>
335337
<ExternalLinkIcon />
336338
{title}
337339
</a>

src/client/Preview.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,12 @@ const PreviewEmptyState = () => {
250250
</p>
251251
</div>
252252
<a
253-
href="#todo"
253+
href="https://coder.com/docs/admin/templates/extending-templates/parameters"
254+
target="_blank"
255+
rel="noreferrer"
254256
className="flex items-center gap-0.5 text-content-link text-sm"
255257
>
258+
<span className="sr-only"> (link opens in new tab)</span>
256259
Read the docs
257260
<span className="inline">
258261
<ExternalLinkIcon width={16} />

src/client/editor/Editor.tsx

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,10 @@ import {
44
ChevronDownIcon,
55
CopyIcon,
66
FileJsonIcon,
7-
RadioIcon,
8-
SquareMousePointerIcon,
9-
TextCursorInputIcon,
10-
ToggleLeftIcon,
117
UsersIcon,
128
ZapIcon,
139
} from "lucide-react";
14-
import { type FC, useEffect, useRef, useState } from "react";
10+
import { type FC, useEffect, useState } from "react";
1511
import { Button } from "@/client/components/Button";
1612
import {
1713
DropdownMenu,
@@ -25,8 +21,8 @@ import * as Tabs from "@/client/components/Tabs";
2521
import { useEditor } from "@/client/contexts/editor";
2622
import { useTheme } from "@/client/contexts/theme";
2723
import { Users } from "@/client/editor/Users";
28-
import { multiSelect, radio, switchInput, textInput } from "@/client/snippets";
29-
import type { ParameterFormType } from "@/gen/types";
24+
import { type SnippetFunc, snippets } from "@/client/snippets";
25+
import type { ParameterWithSource } from "@/gen/types";
3026
import type { User } from "@/user";
3127
import { cn } from "@/utils/cn";
3228

@@ -35,53 +31,47 @@ type EditorProps = {
3531
setCode: React.Dispatch<React.SetStateAction<string>>;
3632
users: User[];
3733
setUsers: (owners: User[]) => void;
34+
parameters: ParameterWithSource[];
3835
};
3936

4037
export const Editor: FC<EditorProps> = ({
4138
code,
4239
setCode,
43-
users: owners,
44-
setUsers: setOwners,
40+
users,
41+
setUsers,
42+
parameters,
4543
}) => {
4644
const { appliedTheme } = useTheme();
4745
const editorRef = useEditor();
4846

49-
const [codeCopied, setCodeCopied] = useState(() => false);
50-
const copyTimeoutId = useRef<ReturnType<typeof setTimeout> | undefined>(
51-
undefined,
52-
);
53-
5447
const [tab, setTab] = useState(() => "code");
5548

49+
const [codeCopied, setCodeCopied] = useState(() => false);
50+
5651
const onCopy = () => {
5752
navigator.clipboard.writeText(code);
5853
setCodeCopied(() => true);
5954
};
6055

61-
const onAddSnippet = (formType: ParameterFormType) => {
62-
if (formType === "input") {
63-
setCode(`${code.trimEnd()}\n\n${textInput}\n`);
64-
} else if (formType === "radio") {
65-
setCode(`${code.trimEnd()}\n\n${radio}\n`);
66-
} else if (formType === "multi-select") {
67-
setCode(`${code.trimEnd()}\n\n${multiSelect}\n`);
68-
} else if (formType === "switch") {
69-
setCode(`${code.trimEnd()}\n\n${switchInput}\n`);
70-
}
56+
const onAddSnippet = (name: string, snippet: SnippetFunc) => {
57+
const nameCount = parameters.filter((p) => p.name.startsWith(name)).length;
58+
59+
const nextInOrder = 1 + Math.max(0, ...parameters.map((p) => p.order));
60+
const newName = nameCount > 0 ? `${name}-${nameCount}` : name;
61+
const newSnippet = snippet(newName, nextInOrder);
62+
setCode(`${code.trimEnd()}\n\n${newSnippet}\n`);
7163
};
7264

7365
useEffect(() => {
7466
if (!codeCopied) {
7567
return;
7668
}
7769

78-
clearTimeout(copyTimeoutId.current);
79-
80-
copyTimeoutId.current = setTimeout(() => {
70+
const copyTimeoutId = setTimeout(() => {
8171
setCodeCopied(() => false);
8272
}, 1000);
8373

84-
return () => clearTimeout(copyTimeoutId.current);
74+
return () => clearTimeout(copyTimeoutId);
8575
}, [codeCopied]);
8676

8777
return (
@@ -110,23 +100,17 @@ export const Editor: FC<EditorProps> = ({
110100

111101
<DropdownMenuPortal>
112102
<DropdownMenuContent align="start">
113-
<DropdownMenuItem onClick={() => onAddSnippet("input")}>
114-
<TextCursorInputIcon width={24} height={24} />
115-
Text input
116-
</DropdownMenuItem>
117-
<DropdownMenuItem
118-
onClick={() => onAddSnippet("multi-select")}
119-
>
120-
<SquareMousePointerIcon width={24} height={24} />
121-
Multi-select
122-
</DropdownMenuItem>
123-
<DropdownMenuItem onClick={() => onAddSnippet("radio")}>
124-
<RadioIcon width={24} height={24} />
125-
Radio
126-
</DropdownMenuItem>
127-
<DropdownMenuItem onClick={() => onAddSnippet("switch")}>
128-
<ToggleLeftIcon width={24} height={24} /> Switches
129-
</DropdownMenuItem>
103+
{snippets.map(
104+
({ name, label, icon: Icon, snippet }, index) => (
105+
<DropdownMenuItem
106+
key={index}
107+
onClick={() => onAddSnippet(name, snippet)}
108+
>
109+
<Icon size={24} />
110+
{label}
111+
</DropdownMenuItem>
112+
),
113+
)}
130114
</DropdownMenuContent>
131115
</DropdownMenuPortal>
132116
</DropdownMenu>
@@ -183,7 +167,7 @@ export const Editor: FC<EditorProps> = ({
183167
</Tabs.Content>
184168

185169
<Tabs.Content value="users" asChild={true}>
186-
<Users setUsers={setOwners} users={owners} />
170+
<Users setUsers={setUsers} users={users} />
187171
</Tabs.Content>
188172
</ResizablePanel>
189173
</Tabs.Root>

0 commit comments

Comments
 (0)