Skip to content

Commit 13f88f8

Browse files
committed
feat: users form implementation
1 parent 7976aa7 commit 13f88f8

File tree

6 files changed

+244
-102
lines changed

6 files changed

+244
-102
lines changed

src/client/App.tsx

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ import type {
3636
PreviewOutput,
3737
WorkspaceOwner,
3838
} from "@/gen/types";
39-
import { mockUsers } from "@/owner";
39+
import { baseMockUser, mockUsers } from "@/owner";
4040
import { rpc } from "@/utils/rpc";
4141
import {
4242
getDynamicParametersOutput,
4343
initWasm,
4444
type WasmLoadState,
4545
} from "@/utils/wasm";
4646
import { useDebouncedValue } from "./hooks/debounce";
47+
import { downloadData } from "./utils";
4748

4849
export const App = () => {
4950
useBeforeUnload(
@@ -67,28 +68,14 @@ export const App = () => {
6768
>({});
6869
const [output, setOutput] = useState<PreviewOutput | null>(null);
6970
const [parameters, setParameters] = useState<ParameterWithSource[]>([]);
70-
const [owner, setOwner] = useState<WorkspaceOwner>(mockUsers.admin);
7171

72-
const onDownloadOutput = () => {
73-
const blob = new Blob([JSON.stringify(output, null, 2)], {
74-
type: "application/json",
75-
});
72+
const [owner, setOwner] = useState<WorkspaceOwner>(
73+
mockUsers[0] ?? baseMockUser,
74+
);
75+
const [owners, setOwners] = useState<WorkspaceOwner[]>(mockUsers);
7676

77-
const url = URL.createObjectURL(blob);
78-
79-
const link = document.createElement("a");
80-
link.href = url;
81-
link.download = "output.json";
82-
document.body.appendChild(link);
83-
link.click();
84-
document.body.removeChild(link);
85-
86-
// Give the click event enough time to fire and then revoke the URL.
87-
// This method of doing it doesn't seem great but I'm not sure if there is a
88-
// better way.
89-
setTimeout(() => {
90-
URL.revokeObjectURL(url);
91-
}, 100);
77+
const onDownloadOutput = () => {
78+
downloadData(output, "output.json");
9279
};
9380

9481
const onReset = () => {
@@ -203,7 +190,12 @@ export const App = () => {
203190

204191
<ResizablePanelGroup direction={"horizontal"}>
205192
{/* EDITOR */}
206-
<Editor code={code} setCode={setCode} />
193+
<Editor
194+
code={code}
195+
setCode={setCode}
196+
owners={owners}
197+
setOwners={setOwners}
198+
/>
207199

208200
<ResizableHandle className="bg-surface-quaternary" />
209201

@@ -217,6 +209,8 @@ export const App = () => {
217209
setParameterValues={setParameterValues}
218210
parameters={parameters}
219211
onReset={onReset}
212+
selectedOwner={owner}
213+
owners={owners}
220214
setOwner={(owner) => {
221215
onReset();
222216
setOwner(owner);

src/client/Preview.tsx

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
import ReactJsonView from "@microlink/react-json-view";
2+
import * as Dialog from "@radix-ui/react-dialog";
3+
import {
4+
ActivityIcon,
5+
BugIcon,
6+
DownloadIcon,
7+
ExternalLinkIcon,
8+
LoaderIcon,
9+
PlayIcon,
10+
ScrollTextIcon,
11+
SearchCodeIcon,
12+
XIcon,
13+
} from "lucide-react";
14+
import { AnimatePresence, motion } from "motion/react";
15+
import React, {
16+
type FC,
17+
type PropsWithChildren,
18+
useMemo,
19+
useState,
20+
} from "react";
21+
import { useSearchParams } from "react-router";
122
import { Button } from "@/client/components/Button";
223
import {
324
DynamicParameter,
@@ -17,33 +38,15 @@ import {
1738
} from "@/client/components/Select";
1839
import * as Tabs from "@/client/components/Tabs";
1940
import { useTheme } from "@/client/contexts/theme";
20-
import { outputToDiagnostics, type Diagnostic } from "@/client/diagnostics";
41+
import { type Diagnostic, outputToDiagnostics } from "@/client/diagnostics";
2142
import type {
2243
ParameterWithSource,
2344
ParserLog,
2445
PreviewOutput,
2546
WorkspaceOwner,
2647
} from "@/gen/types";
27-
import { mockUsers } from "@/owner";
2848
import { cn } from "@/utils/cn";
2949
import type { WasmLoadState } from "@/utils/wasm";
30-
import ReactJsonView from "@microlink/react-json-view";
31-
import * as Dialog from "@radix-ui/react-dialog";
32-
import {
33-
ActivityIcon,
34-
BugIcon,
35-
DownloadIcon,
36-
ExternalLinkIcon,
37-
LoaderIcon,
38-
PlayIcon,
39-
ScrollTextIcon,
40-
SearchCodeIcon,
41-
XIcon,
42-
} from "lucide-react";
43-
import { AnimatePresence, motion } from "motion/react";
44-
import React from "react";
45-
import { type FC, type PropsWithChildren, useMemo, useState } from "react";
46-
import { useSearchParams } from "react-router";
4750

4851
type PreviewProps = {
4952
wasmLoadState: WasmLoadState;
@@ -56,6 +59,8 @@ type PreviewProps = {
5659
>;
5760
parameters: ParameterWithSource[];
5861
onReset: () => void;
62+
selectedOwner: WorkspaceOwner;
63+
owners: WorkspaceOwner[];
5964
setOwner: (owner: WorkspaceOwner) => void;
6065
};
6166

@@ -67,6 +72,8 @@ export const Preview: FC<PreviewProps> = ({
6772
setParameterValues,
6873
parameters,
6974
onReset,
75+
selectedOwner,
76+
owners,
7077
setOwner,
7178
}) => {
7279
const [params] = useSearchParams();
@@ -183,7 +190,11 @@ export const Preview: FC<PreviewProps> = ({
183190
) : null}
184191
</AnimatePresence>
185192
</div>
186-
<UserSelect setOwner={setOwner} />
193+
<UserSelect
194+
setOwner={setOwner}
195+
owners={owners}
196+
selectedOwner={selectedOwner}
197+
/>
187198
</div>
188199
}
189200
{parameters.length === 0 ? (
@@ -551,26 +562,43 @@ const FormElement: FC<FormElementProps> = React.memo(
551562
FormElement.displayName = "FormElement";
552563

553564
type UserSelectProps = {
565+
selectedOwner: WorkspaceOwner;
566+
owners: WorkspaceOwner[];
554567
setOwner: (owner: WorkspaceOwner) => void;
555568
};
556-
const UserSelect: FC<UserSelectProps> = ({ setOwner }) => {
569+
const UserSelect: FC<UserSelectProps> = ({
570+
selectedOwner,
571+
owners,
572+
setOwner,
573+
}) => {
574+
const selectedMissing = !owners.some(
575+
(owner) => selectedOwner.id === owner.id,
576+
);
577+
557578
return (
558579
<Select
559-
defaultValue="admin"
580+
value={selectedOwner.id}
560581
onValueChange={(value) => {
561-
const users: Record<string, WorkspaceOwner | undefined> = mockUsers;
562-
setOwner(users[value] ?? mockUsers.admin);
582+
const owner = owners.find((owner) => owner.id === value);
583+
if (owner) {
584+
setOwner(owner);
585+
}
563586
}}
564587
>
565588
<SelectTrigger className="w-fit min-w-40">
566589
<SelectValue />
567590
</SelectTrigger>
568591
<SelectContent>
569-
<SelectItem value="admin">Administrator</SelectItem>
570-
<SelectItem value="developer">Developer</SelectItem>
571-
<SelectItem value="contractor">Contractor</SelectItem>
572-
<SelectItem value="eu-developer">EU Developer</SelectItem>
573-
<SelectItem value="sales">Sales</SelectItem>
592+
{selectedMissing ? (
593+
<SelectItem value={selectedOwner.id}>
594+
{selectedOwner.full_name || selectedOwner.name}
595+
</SelectItem>
596+
) : null}
597+
{owners.map((owner, index) => (
598+
<SelectItem value={owner.id} key={index}>
599+
{owner.full_name || owner.name}
600+
</SelectItem>
601+
))}
574602
</SelectContent>
575603
</Select>
576604
);
@@ -690,6 +718,7 @@ const ViewOutput: FC<ViewOutputProps> = ({ parameters }) => {
690718
return true;
691719
}
692720

721+
// biome-ignore lint/correctness/useHookAtTopLevel: It's not a hook
693722
const schema = useValidationSchemaForDynamicParameters([p]);
694723
schema.validateSync([{ name: p.name, value: p.value.value }]);
695724

src/client/editor/Editor.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,22 @@ import { useEditor } from "@/client/contexts/editor";
2626
import { useTheme } from "@/client/contexts/theme";
2727
import { Users } from "@/client/editor/Users";
2828
import { multiSelect, radio, switchInput, textInput } from "@/client/snippets";
29-
import type { ParameterFormType } from "@/gen/types";
29+
import type { ParameterFormType, WorkspaceOwner } from "@/gen/types";
3030
import { cn } from "@/utils/cn";
3131

3232
type EditorProps = {
3333
code: string;
3434
setCode: React.Dispatch<React.SetStateAction<string>>;
35+
owners: WorkspaceOwner[];
36+
setOwners: (owners: WorkspaceOwner[]) => void;
3537
};
3638

37-
export const Editor: FC<EditorProps> = ({ code, setCode }) => {
39+
export const Editor: FC<EditorProps> = ({
40+
code,
41+
setCode,
42+
owners,
43+
setOwners,
44+
}) => {
3845
const { appliedTheme } = useTheme();
3946
const editorRef = useEditor();
4047

@@ -43,7 +50,7 @@ export const Editor: FC<EditorProps> = ({ code, setCode }) => {
4350
undefined,
4451
);
4552

46-
const [tab, setTab] = useState(() => "users");
53+
const [tab, setTab] = useState(() => "code");
4754

4855
const onCopy = () => {
4956
navigator.clipboard.writeText(code);
@@ -175,7 +182,7 @@ export const Editor: FC<EditorProps> = ({ code, setCode }) => {
175182
</Tabs.Content>
176183

177184
<Tabs.Content value="users" asChild={true}>
178-
<Users />
185+
<Users setUsers={setOwners} users={owners} />
179186
</Tabs.Content>
180187
</ResizablePanel>
181188
</Tabs.Root>

0 commit comments

Comments
 (0)