diff --git a/pkgs/webview-ui/app/src/hooks/index.ts b/pkgs/webview-ui/app/src/hooks/index.ts
new file mode 100644
index 000000000..629c8e452
--- /dev/null
+++ b/pkgs/webview-ui/app/src/hooks/index.ts
@@ -0,0 +1,21 @@
+import { callApi } from "../api";
+import { setActiveURI, setClanList } from "../App";
+
+export const registerClan = async () => {
+ try {
+ const loc = await callApi("open_file", {
+ file_request: { mode: "select_folder" },
+ });
+ if (loc.status === "success" && loc.data) {
+ const data = loc.data[0];
+ setClanList((s) => {
+ const res = new Set([...s, data]);
+ return Array.from(res);
+ });
+ setActiveURI(data);
+ return data;
+ }
+ } catch (e) {
+ //
+ }
+};
diff --git a/pkgs/webview-ui/app/src/index.tsx b/pkgs/webview-ui/app/src/index.tsx
index b0d5b5f0b..e5a349ebc 100644
--- a/pkgs/webview-ui/app/src/index.tsx
+++ b/pkgs/webview-ui/app/src/index.tsx
@@ -7,15 +7,12 @@ import { QueryClient, QueryClientProvider } from "@tanstack/solid-query";
import { MachineDetails } from "./routes/machines/[name]/view";
import { Layout } from "./layout/layout";
import { MachineListView } from "./routes/machines/view";
-import { CreateClan } from "./routes/clan/view";
-import { Settings } from "./routes/settings";
-import { EditClanForm } from "./routes/clan/editClan";
+import { ClanList, CreateClan, ClanDetails } from "./routes/clans";
import { Flash } from "./routes/flash/view";
import { CreateMachine } from "./routes/machines/create";
import { HostList } from "./routes/hosts/view";
import { Welcome } from "./routes/welcome";
import { Toaster } from "solid-toast";
-import { Details } from "./routes/clan/details";
const client = new QueryClient();
@@ -74,7 +71,7 @@ export const routes: AppRoute[] = [
{
path: "/",
label: "Overview",
- component: () => ,
+ component: () => ,
},
{
path: "/create",
@@ -85,7 +82,7 @@ export const routes: AppRoute[] = [
path: "/:id",
label: "Details",
hidden: true,
- component: () => ,
+ component: () => ,
},
],
},
diff --git a/pkgs/webview-ui/app/src/layout/header.tsx b/pkgs/webview-ui/app/src/layout/header.tsx
index cb91644a5..afb39df0c 100644
--- a/pkgs/webview-ui/app/src/layout/header.tsx
+++ b/pkgs/webview-ui/app/src/layout/header.tsx
@@ -64,11 +64,18 @@ export const Header = (props: HeaderProps) => {
-
-
-
+
+ {(d) => (
+
+
+
+ )}
+
);
diff --git a/pkgs/webview-ui/app/src/routes/clan/details.tsx b/pkgs/webview-ui/app/src/routes/clan/details.tsx
deleted file mode 100644
index 748d6b0aa..000000000
--- a/pkgs/webview-ui/app/src/routes/clan/details.tsx
+++ /dev/null
@@ -1,210 +0,0 @@
-import { callApi, SuccessQuery } from "@/src/api";
-import { BackButton } from "@/src/components/BackButton";
-import { useParams } from "@solidjs/router";
-import { createQuery } from "@tanstack/solid-query";
-import { createSignal, For, Match, Switch } from "solid-js";
-import { Show } from "solid-js";
-import {
- createForm,
- FieldValues,
- getValue,
- getValues,
- setValue,
-} from "@modular-forms/solid";
-import { TextInput } from "@/src/components/TextInput";
-import toast from "solid-toast";
-
-type AdminData = SuccessQuery<"get_admin_service">["data"];
-
-interface ClanDetailsProps {
- admin: AdminData;
- base_url: string;
-}
-interface AdminSettings extends FieldValues {
- allowedKeys: { name: string; value: string }[];
-}
-
-const ClanDetails = (props: ClanDetailsProps) => {
- const items = () =>
- Object.entries(
- (props.admin?.config?.allowedKeys as Record) || {},
- );
- const [formStore, { Form, Field }] = createForm({
- initialValues: {
- allowedKeys: items().map(([name, value]) => ({ name, value })),
- },
- });
-
- const [keys, setKeys] = createSignal<1[]>(
- new Array(items().length || 1).fill(1),
- );
-
- const handleSubmit = async (values: AdminSettings) => {
- console.log("submitting", values, getValues(formStore));
-
- const r = await callApi("set_admin_service", {
- base_url: props.base_url,
- allowed_keys: values.allowedKeys.reduce(
- (acc, curr) => ({ ...acc, [curr.name]: curr.value }),
- {},
- ),
- });
- if (r.status === "success") {
- toast.success("Successfully updated admin settings");
- }
- if (r.status === "error") {
- toast.error(`Failed to update admin settings: ${r.errors[0].message}`);
- }
- };
-
- return (
-
-
Clan Admin Settings
-
-
- );
-};
-
-export const Details = () => {
- const params = useParams();
- const clan_dir = window.atob(params.id);
- const query = createQuery(() => ({
- queryKey: [clan_dir, "get_admin_service"],
- queryFn: async () => {
- const result = await callApi("get_admin_service", {
- base_url: clan_dir,
- });
- if (result.status === "error") throw new Error("Failed to fetch data");
- return result.data || null;
- },
- }));
-
- return (
-
-
- }
- >
-
-
- {(d) => }
-
-
-
-
- );
-};
diff --git a/pkgs/webview-ui/app/src/routes/clan/editClan.tsx b/pkgs/webview-ui/app/src/routes/clan/editClan.tsx
deleted file mode 100644
index fc437c409..000000000
--- a/pkgs/webview-ui/app/src/routes/clan/editClan.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-import { callApi, OperationResponse, pyApi } from "@/src/api";
-import { Accessor, Match, Show, Switch } from "solid-js";
-import {
- createForm,
- required,
- reset,
- SubmitHandler,
-} from "@modular-forms/solid";
-import toast from "solid-toast";
-import { createQuery } from "@tanstack/solid-query";
-
-type CreateForm = Meta;
-
-interface EditClanFormProps {
- directory: Accessor;
- done: () => void;
-}
-export const EditClanForm = (props: EditClanFormProps) => {
- const { directory } = props;
- const details = createQuery(() => ({
- queryKey: [directory(), "meta"],
- queryFn: async () => {
- const result = await callApi("show_clan_meta", { uri: directory() });
- if (result.status === "error") throw new Error("Failed to fetch data");
- return result.data;
- },
- }));
-
- return (
-
-
- {(data) => (
-
- )}
-
-
- );
-};
-
-interface FinalEditClanFormProps {
- initial: CreateForm;
- directory: string;
- done: () => void;
-}
-export const FinalEditClanForm = (props: FinalEditClanFormProps) => {
- const [formStore, { Form, Field }] = createForm({
- initialValues: props.initial,
- });
-
- const handleSubmit: SubmitHandler = async (values, event) => {
- await toast.promise(
- (async () => {
- await callApi("update_clan_meta", {
- options: {
- directory: props.directory,
- meta: values,
- },
- });
- })(),
- {
- loading: "Updating clan...",
- success: "Clan Successfully updated",
- error: "Failed to update clan",
- },
- );
- props.done();
- };
-
- return (
-
- );
-};
-
-type Meta = Extract<
- OperationResponse<"show_clan_meta">,
- { status: "success" }
->["data"];
diff --git a/pkgs/webview-ui/app/src/routes/clan/view.tsx b/pkgs/webview-ui/app/src/routes/clan/view.tsx
deleted file mode 100644
index 2226004c8..000000000
--- a/pkgs/webview-ui/app/src/routes/clan/view.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { ClanForm } from "./clanDetails";
-
-export const CreateClan = () => {
- return (
-
-
-
- );
-};
diff --git a/pkgs/webview-ui/app/src/routes/clan/clanDetails.tsx b/pkgs/webview-ui/app/src/routes/clans/create.tsx
similarity index 99%
rename from pkgs/webview-ui/app/src/routes/clan/clanDetails.tsx
rename to pkgs/webview-ui/app/src/routes/clans/create.tsx
index 0e33ffeb3..f47367b23 100644
--- a/pkgs/webview-ui/app/src/routes/clan/clanDetails.tsx
+++ b/pkgs/webview-ui/app/src/routes/clans/create.tsx
@@ -15,7 +15,7 @@ type CreateForm = Meta & {
template: string;
};
-export const ClanForm = () => {
+export const CreateClan = () => {
const [formStore, { Form, Field }] = createForm({
initialValues: {
name: "",
diff --git a/pkgs/webview-ui/app/src/routes/clans/details.tsx b/pkgs/webview-ui/app/src/routes/clans/details.tsx
new file mode 100644
index 000000000..67a93ad0b
--- /dev/null
+++ b/pkgs/webview-ui/app/src/routes/clans/details.tsx
@@ -0,0 +1,394 @@
+import { callApi, SuccessQuery } from "@/src/api";
+import { BackButton } from "@/src/components/BackButton";
+import { useParams } from "@solidjs/router";
+import {
+ createQuery,
+ QueryClient,
+ useQueryClient,
+} from "@tanstack/solid-query";
+import { createSignal, For, Match, Switch } from "solid-js";
+import { Show } from "solid-js";
+import {
+ createForm,
+ FieldValues,
+ getValue,
+ getValues,
+ required,
+ setValue,
+ SubmitHandler,
+} from "@modular-forms/solid";
+import { TextInput } from "@/src/components/TextInput";
+import toast from "solid-toast";
+
+interface AdminModuleFormProps {
+ admin: AdminData;
+ base_url: string;
+}
+interface AdminSettings extends FieldValues {
+ allowedKeys: { name: string; value: string }[];
+}
+
+interface EditClanFormProps {
+ initial: GeneralData;
+ directory: string;
+}
+
+const EditClanForm = (props: EditClanFormProps) => {
+ const [formStore, { Form, Field }] = createForm({
+ initialValues: props.initial,
+ });
+ const queryClient = useQueryClient();
+
+ const handleSubmit: SubmitHandler = async (values, event) => {
+ await toast.promise(
+ (async () => {
+ await callApi("update_clan_meta", {
+ options: {
+ directory: props.directory,
+ meta: values,
+ },
+ });
+ })(),
+ {
+ loading: "Updating clan...",
+ success: "Clan Successfully updated",
+ error: "Failed to update clan",
+ },
+ );
+ queryClient.invalidateQueries({
+ queryKey: [props.directory, "meta"],
+ });
+ };
+ const curr_name = () => props.initial.name;
+
+ return (
+
+ );
+};
+
+const AdminModuleForm = (props: AdminModuleFormProps) => {
+ const items = () =>
+ Object.entries(
+ (props.admin?.config?.allowedKeys as Record) || {},
+ );
+ const [formStore, { Form, Field }] = createForm({
+ initialValues: {
+ allowedKeys: items().map(([name, value]) => ({ name, value })),
+ },
+ });
+ const queryClient = useQueryClient();
+
+ const [keys, setKeys] = createSignal<1[]>(
+ new Array(items().length || 1).fill(1),
+ );
+
+ const handleSubmit = async (values: AdminSettings) => {
+ console.log("submitting", values, getValues(formStore));
+
+ const r = await callApi("set_admin_service", {
+ base_url: props.base_url,
+ allowed_keys: values.allowedKeys.reduce(
+ (acc, curr) => ({ ...acc, [curr.name]: curr.value }),
+ {},
+ ),
+ });
+ if (r.status === "success") {
+ toast.success("Successfully updated admin settings");
+ }
+ if (r.status === "error") {
+ toast.error(`Failed to update admin settings: ${r.errors[0].message}`);
+ }
+ queryClient.invalidateQueries({
+ queryKey: [props.base_url, "get_admin_service"],
+ });
+ };
+
+ return (
+
+ );
+};
+
+type GeneralData = SuccessQuery<"show_clan_meta">["data"];
+type AdminData = SuccessQuery<"get_admin_service">["data"];
+
+export const ClanDetails = () => {
+ const params = useParams();
+ const clan_dir = window.atob(params.id);
+ // Fetch general meta data
+ const clanQuery = createQuery(() => ({
+ queryKey: [clan_dir, "meta"],
+ queryFn: async () => {
+ const result = await callApi("show_clan_meta", { uri: clan_dir });
+ if (result.status === "error") throw new Error("Failed to fetch data");
+ return result.data;
+ },
+ }));
+ // Fetch admin settings
+ const adminQuery = createQuery(() => ({
+ queryKey: [clan_dir, "get_admin_service"],
+ queryFn: async () => {
+ const result = await callApi("get_admin_service", {
+ base_url: clan_dir,
+ });
+ if (result.status === "error") throw new Error("Failed to fetch data");
+ return result.data || null;
+ },
+ }));
+
+ return (
+
+
+
+
+
+ }
+ >
+
+
+ {(d) => }
+
+
+
+
+
+
+
+ }
+ >
+
+
+ {(d) => }
+
+
+
+
+ );
+};
diff --git a/pkgs/webview-ui/app/src/routes/clans/index.ts b/pkgs/webview-ui/app/src/routes/clans/index.ts
new file mode 100644
index 000000000..7c0e879c8
--- /dev/null
+++ b/pkgs/webview-ui/app/src/routes/clans/index.ts
@@ -0,0 +1,3 @@
+export * from "./list";
+export * from "./create";
+export * from "./details";
diff --git a/pkgs/webview-ui/app/src/routes/settings/index.tsx b/pkgs/webview-ui/app/src/routes/clans/list.tsx
similarity index 59%
rename from pkgs/webview-ui/app/src/routes/settings/index.tsx
rename to pkgs/webview-ui/app/src/routes/clans/list.tsx
index 629d6fff0..00b581e78 100644
--- a/pkgs/webview-ui/app/src/routes/settings/index.tsx
+++ b/pkgs/webview-ui/app/src/routes/clans/list.tsx
@@ -4,39 +4,14 @@ import { createSignal, For, Match, Setter, Show, Switch } from "solid-js";
import { createQuery } from "@tanstack/solid-query";
import { useFloating } from "@/src/floating";
import { autoUpdate, flip, hide, offset, shift } from "@floating-ui/dom";
-import { EditClanForm } from "../clan/editClan";
import { useNavigate, A } from "@solidjs/router";
-import { fileURLToPath } from "url";
+import { registerClan } from "@/src/hooks";
-export const registerClan = async () => {
- try {
- const loc = await callApi("open_file", {
- file_request: { mode: "select_folder" },
- });
- if (loc.status === "success" && loc.data) {
- const data = loc.data[0];
- setClanList((s) => {
- const res = new Set([...s, data]);
- return Array.from(res);
- });
- setActiveURI(data);
- // setRoute((r) => {
- // if (r === "welcome") return "machines";
- // return r;
- // });
- return data;
- }
- } catch (e) {
- //
- }
-};
-
-interface ClanDetailsProps {
+interface ClanItemProps {
clan_dir: string;
- setEditURI: Setter;
}
-const ClanDetails = (props: ClanDetailsProps) => {
- const { clan_dir, setEditURI } = props;
+const ClanItem = (props: ClanItemProps) => {
+ const { clan_dir } = props;
const details = createQuery(() => ({
queryKey: [clan_dir, "meta"],
@@ -46,7 +21,7 @@ const ClanDetails = (props: ClanDetailsProps) => {
return result.data;
},
}));
-
+ const navigate = useNavigate();
const [reference, setReference] = createSignal();
const [floating, setFloating] = createSignal();
@@ -87,10 +62,8 @@ const ClanDetails = (props: ClanDetailsProps) => {
@@ -157,62 +130,37 @@ const ClanDetails = (props: ClanDetailsProps) => {
);
};
-export const Settings = () => {
- const [editURI, setEditURI] = createSignal
(null);
-
+export const ClanList = () => {
const navigate = useNavigate();
return (
-
-
- {(uri) => (
- {
- setEditURI(null);
- }}
- />
- )}
-
-
-
-
-
- Registered Clans
-
-
-
-
-
-
-
-
-
-
-
-
- {(value) => (
-
- )}
-
-
+
+
+
Registered Clans
+
+
+
+
+
+
+
-
-
+
+
+
+ {(value) => }
+
+
+
);
};
diff --git a/pkgs/webview-ui/app/src/routes/welcome/index.tsx b/pkgs/webview-ui/app/src/routes/welcome/index.tsx
index f82ea5f6b..b6dc72434 100644
--- a/pkgs/webview-ui/app/src/routes/welcome/index.tsx
+++ b/pkgs/webview-ui/app/src/routes/welcome/index.tsx
@@ -1,5 +1,5 @@
-import { setActiveURI, setClanList } from "@/src/App";
-import { registerClan } from "../settings";
+import { setActiveURI } from "@/src/App";
+import { registerClan } from "@/src/hooks";
import { useNavigate } from "@solidjs/router";
export const Welcome = () => {