From f08aae04d3bad4628f91a42f70ac69834b4640f5 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 19 Nov 2024 13:47:43 +0100 Subject: [PATCH] UI/Modules: individual roles members --- .../webview-ui/app/src/Form/fields/Select.tsx | 11 +- pkgs/webview-ui/app/src/index.tsx | 9 +- pkgs/webview-ui/app/src/queries/index.ts | 41 +++++++ .../webview-ui/app/src/routes/modules/add.tsx | 116 ++++++++++++++++++ .../app/src/routes/modules/details.tsx | 59 ++++----- .../app/src/routes/modules/list.tsx | 3 +- pkgs/webview-ui/app/tailwind.config.ts | 2 + 7 files changed, 209 insertions(+), 32 deletions(-) create mode 100644 pkgs/webview-ui/app/src/routes/modules/add.tsx diff --git a/pkgs/webview-ui/app/src/Form/fields/Select.tsx b/pkgs/webview-ui/app/src/Form/fields/Select.tsx index 5b0dd31d7..9afa52b6c 100644 --- a/pkgs/webview-ui/app/src/Form/fields/Select.tsx +++ b/pkgs/webview-ui/app/src/Form/fields/Select.tsx @@ -126,7 +126,16 @@ export function SelectInput(props: SelectInputpProps) { type="button" class="select select-bordered flex items-center gap-2" ref={setReference} - popovertarget={_id} + formnovalidate + onClick={() => { + const popover = document.getElementById(_id); + if (popover) { + popover.togglePopover(); // Show or hide the popover + } + }} + // TODO: Use native popover once Webkti supports it within
+ // popovertarget={_id} + // popovertargetaction="toggle" > {props.adornment?.content} diff --git a/pkgs/webview-ui/app/src/index.tsx b/pkgs/webview-ui/app/src/index.tsx index 9a9635578..bdd3e969b 100644 --- a/pkgs/webview-ui/app/src/index.tsx +++ b/pkgs/webview-ui/app/src/index.tsx @@ -17,6 +17,7 @@ import { Welcome } from "./routes/welcome"; import { Toaster } from "solid-toast"; import { ModuleList } from "./routes/modules/list"; import { ModuleDetails } from "./routes/modules/details"; +import { ModuleDetails as AddModule } from "./routes/modules/add"; export const client = new QueryClient(); @@ -101,11 +102,17 @@ export const routes: AppRoute[] = [ component: () => , }, { - path: "/:id", + path: "details/:id", label: "Details", hidden: true, component: () => , }, + { + path: "/add/:id", + label: "Details", + hidden: true, + component: () => , + }, ], }, { diff --git a/pkgs/webview-ui/app/src/queries/index.ts b/pkgs/webview-ui/app/src/queries/index.ts index 9579a47d1..e7f0e8909 100644 --- a/pkgs/webview-ui/app/src/queries/index.ts +++ b/pkgs/webview-ui/app/src/queries/index.ts @@ -34,3 +34,44 @@ export const createModulesQuery = ( return []; }, })); + +export const tagsQuery = (uri: string | null) => + createQuery(() => ({ + queryKey: [uri, "tags"], + placeholderData: [], + queryFn: async () => { + if (!uri) return []; + + const response = await callApi("get_inventory", { + base_path: uri, + }); + if (response.status === "error") { + toast.error("Failed to fetch data"); + } else { + const machines = response.data.machines || {}; + const tags = Object.values(machines).flatMap((m) => m.tags || []); + return tags; + } + return []; + }, + })); + +export const machinesQuery = (uri: string | null) => + createQuery(() => ({ + queryKey: [uri, "machines"], + placeholderData: [], + queryFn: async () => { + if (!uri) return []; + + const response = await callApi("get_inventory", { + base_path: uri, + }); + if (response.status === "error") { + toast.error("Failed to fetch data"); + } else { + const machines = response.data.machines || {}; + return Object.keys(machines); + } + return []; + }, + })); diff --git a/pkgs/webview-ui/app/src/routes/modules/add.tsx b/pkgs/webview-ui/app/src/routes/modules/add.tsx new file mode 100644 index 000000000..f21f4aae4 --- /dev/null +++ b/pkgs/webview-ui/app/src/routes/modules/add.tsx @@ -0,0 +1,116 @@ +import { activeURI } from "@/src/App"; +import { BackButton } from "@/src/components/BackButton"; +import { createModulesQuery, machinesQuery, tagsQuery } from "@/src/queries"; +import { useParams } from "@solidjs/router"; +import { For, Match, Switch } from "solid-js"; +import { ModuleInfo } from "./list"; +import { createForm, FieldValues, SubmitHandler } from "@modular-forms/solid"; +import { SelectInput } from "@/src/Form/fields/Select"; + +export const ModuleDetails = () => { + const params = useParams(); + const modulesQuery = createModulesQuery(activeURI()); + + return ( +
+ +
+

{params.id}

+ + i[0] === params.id)}> + {(d) => } + + +
+
+ ); +}; + +interface AddModuleProps { + data: ModuleInfo; + id: string; +} + +export const AddModule = (props: AddModuleProps) => { + const tags = tagsQuery(activeURI()); + const machines = machinesQuery(activeURI()); + return ( +
+
Add to your clan
+ + + {(tags) => ( + + {(role) => ( + <> +
{role}s
+ + + )} +
+ )} +
+
+
+ ); +}; + +interface RoleFormData extends FieldValues { + machines: string[]; + tags: string[]; + test: string; +} + +interface RoleFormProps { + avilableTags: string[]; + availableMachines: string[]; +} +const RoleForm = (props: RoleFormProps) => { + const [formStore, { Field, Form }] = createForm({ + // initialValues: { + // machines: ["hugo", "bruno"], + // tags: ["network", "backup"], + // }, + }); + + const handleSubmit: SubmitHandler = (values) => { + console.log(values); + }; + return ( + + + {(field, fieldProps) => ( + ({ + value: o, + label: o, + }))} + multiple + selectProps={fieldProps} + /> + )} + + + {(field, fieldProps) => ( + ({ + value: o, + label: o, + }))} + multiple + selectProps={fieldProps} + /> + )} + + + ); +}; diff --git a/pkgs/webview-ui/app/src/routes/modules/details.tsx b/pkgs/webview-ui/app/src/routes/modules/details.tsx index 1161eb4ff..7db0cc290 100644 --- a/pkgs/webview-ui/app/src/routes/modules/details.tsx +++ b/pkgs/webview-ui/app/src/routes/modules/details.tsx @@ -2,7 +2,7 @@ import { callApi } from "@/src/api"; import { activeURI } from "@/src/App"; import { BackButton } from "@/src/components/BackButton"; import { createModulesQuery } from "@/src/queries"; -import { useParams } from "@solidjs/router"; +import { useParams, useNavigate } from "@solidjs/router"; import { createEffect, createSignal, @@ -70,6 +70,33 @@ interface DetailsProps { id: string; } const Details = (props: DetailsProps) => { + const navigate = useNavigate(); + const add = async () => { + navigate(`/modules/add/${props.id}`); + // const uri = activeURI(); + // if (!uri) return; + // const res = await callApi("get_inventory", { base_path: uri }); + // if (res.status === "error") { + // toast.error("Failed to fetch inventory"); + // return; + // } + // const inventory = res.data; + // const newInventory = deepMerge(inventory, { + // services: { + // [props.id]: { + // default: { + // enabled: false, + // }, + // }, + // }, + // }); + + // callApi("set_inventory", { + // flake_dir: uri, + // inventory: newInventory, + // message: `Add module: ${props.id} in 'default' instance`, + // }); + }; return (
{props.data.description}
@@ -89,37 +116,11 @@ const Details = (props: DetailsProps) => { {props.data.readme}
- + {/* Add -> Select (required) roles, assign Machine */}
diff --git a/pkgs/webview-ui/app/src/routes/modules/list.tsx b/pkgs/webview-ui/app/src/routes/modules/list.tsx index 3b38df0d2..5bf699cdb 100644 --- a/pkgs/webview-ui/app/src/routes/modules/list.tsx +++ b/pkgs/webview-ui/app/src/routes/modules/list.tsx @@ -18,11 +18,12 @@ const ModuleListItem = (props: { name: string; info: ModuleInfo }) => {
more
- +
{name}
{info.description}
+
{JSON.stringify(info.constraints)}
); }; diff --git a/pkgs/webview-ui/app/tailwind.config.ts b/pkgs/webview-ui/app/tailwind.config.ts index 21012b7cb..df95870f5 100644 --- a/pkgs/webview-ui/app/tailwind.config.ts +++ b/pkgs/webview-ui/app/tailwind.config.ts @@ -1,6 +1,8 @@ import typography from "@tailwindcss/typography"; import daisyui from "daisyui"; import core from "./tailwind/core-plugin"; +// @ts-expect-error: Doesn't have types +import { parseColor } from "tailwindcss/lib/util/color"; /** @type {import('tailwindcss').Config} */ const config = {