UI: migrate admin service api bindings
This commit is contained in:
@@ -1,40 +1,101 @@
|
|||||||
import { callApi, ClanService, ServiceNames, Services } from ".";
|
import { QueryClient } from "@tanstack/solid-query";
|
||||||
import { Schema as Inventory } from "@/api/Inventory";
|
import { callApi, ClanServiceInstance, ServiceNames, Services } from ".";
|
||||||
|
|
||||||
export async function get_inventory(base_path: string) {
|
export async function get_inventory(client: QueryClient, base_path: string) {
|
||||||
const r = await callApi("get_inventory", {
|
const data = await client.ensureQueryData({
|
||||||
base_path,
|
queryKey: [base_path, "inventory"],
|
||||||
|
queryFn: () => {
|
||||||
|
console.log("Refreshing inventory");
|
||||||
|
return callApi("get_inventory", { base_path });
|
||||||
|
},
|
||||||
|
revalidateIfStale: true,
|
||||||
|
staleTime: 60 * 1000,
|
||||||
});
|
});
|
||||||
if (r.status == "error") {
|
|
||||||
throw new Error("Failed to get inventory");
|
return data;
|
||||||
}
|
|
||||||
const inventory: Inventory = r.data;
|
|
||||||
return inventory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const single_instance_name = <T extends keyof Services>(
|
export const generate_instance_name = <T extends keyof Services>(
|
||||||
machine_name: string,
|
machine_name: string,
|
||||||
service_name: T,
|
service_name: T,
|
||||||
) => `${machine_name}_${service_name}_0` as const;
|
) => [machine_name, service_name, 1].filter(Boolean).join("_");
|
||||||
|
|
||||||
function get_service<T extends ServiceNames>(base_path: string, service: T) {
|
export const get_first_instance_name = async <T extends keyof Services>(
|
||||||
return callApi("get_inventory", { base_path }).then((r) => {
|
client: QueryClient,
|
||||||
if (r.status == "error") {
|
base_path: string,
|
||||||
return null;
|
service_name: T,
|
||||||
}
|
): Promise<string | null> => {
|
||||||
const inventory: Inventory = r.data;
|
const r = await get_inventory(client, base_path);
|
||||||
|
if (r.status === "success") {
|
||||||
|
const service = r.data.services?.[service_name];
|
||||||
|
if (!service) return null;
|
||||||
|
return Object.keys(service)[0] || null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
const serviceInstance = inventory.services?.[service];
|
async function get_service<T extends ServiceNames>(
|
||||||
return serviceInstance;
|
client: QueryClient,
|
||||||
});
|
base_path: string,
|
||||||
|
service_name: T,
|
||||||
|
) {
|
||||||
|
const r = await get_inventory(client, base_path);
|
||||||
|
if (r.status === "success") {
|
||||||
|
const service = r.data.services?.[service_name];
|
||||||
|
return service as Services[T];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_single_service<T extends keyof Services>(
|
export async function get_single_service<T extends keyof Services>(
|
||||||
|
client: QueryClient,
|
||||||
|
base_path: string,
|
||||||
|
service_name: T,
|
||||||
|
) {
|
||||||
|
const instance_key = await get_first_instance_name(
|
||||||
|
client,
|
||||||
|
base_path,
|
||||||
|
service_name,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!instance_key) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const service: Services[T] | null = await get_service(
|
||||||
|
client,
|
||||||
|
base_path,
|
||||||
|
service_name,
|
||||||
|
);
|
||||||
|
if (service) {
|
||||||
|
const clanServiceInstance = service[instance_key];
|
||||||
|
return clanServiceInstance || {};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function set_single_service<T extends keyof Services>(
|
||||||
|
client: QueryClient,
|
||||||
base_path: string,
|
base_path: string,
|
||||||
machine_name: string,
|
machine_name: string,
|
||||||
service_name: T,
|
service_name: T,
|
||||||
|
service_config: ClanServiceInstance<T>,
|
||||||
) {
|
) {
|
||||||
const instance_key = single_instance_name(machine_name, service_name);
|
const instance_key =
|
||||||
const service = await get_service(base_path, "admin");
|
(await get_first_instance_name(client, base_path, service_name)) ||
|
||||||
return service?.[instance_key];
|
generate_instance_name(machine_name, service_name);
|
||||||
|
const r = await get_inventory(client, base_path);
|
||||||
|
if (r.status === "success") {
|
||||||
|
const inventory = r.data;
|
||||||
|
inventory.services = inventory.services || {};
|
||||||
|
inventory.services[service_name] = inventory.services[service_name] || {};
|
||||||
|
// @ts-expect-error: This doesn't check
|
||||||
|
inventory.services[service_name][instance_key] = service_config;
|
||||||
|
console.log("saving inventory", inventory);
|
||||||
|
return callApi("set_inventory", {
|
||||||
|
inventory,
|
||||||
|
message: `update_single_service ${service_name}`,
|
||||||
|
flake_dir: base_path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { HostList } from "./routes/hosts/view";
|
|||||||
import { Welcome } from "./routes/welcome";
|
import { Welcome } from "./routes/welcome";
|
||||||
import { Toaster } from "solid-toast";
|
import { Toaster } from "solid-toast";
|
||||||
|
|
||||||
const client = new QueryClient();
|
export const client = new QueryClient();
|
||||||
|
|
||||||
const root = document.getElementById("app");
|
const root = document.getElementById("app");
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
} from "@modular-forms/solid";
|
} from "@modular-forms/solid";
|
||||||
import { TextInput } from "@/src/components/TextInput";
|
import { TextInput } from "@/src/components/TextInput";
|
||||||
import toast from "solid-toast";
|
import toast from "solid-toast";
|
||||||
import { get_single_service } from "@/src/api/inventory";
|
import { get_single_service, set_single_service } from "@/src/api/inventory";
|
||||||
|
|
||||||
interface AdminModuleFormProps {
|
interface AdminModuleFormProps {
|
||||||
admin: AdminData;
|
admin: AdminData;
|
||||||
@@ -190,20 +190,34 @@ const AdminModuleForm = (props: AdminModuleFormProps) => {
|
|||||||
const handleSubmit = async (values: AdminSettings) => {
|
const handleSubmit = async (values: AdminSettings) => {
|
||||||
console.log("submitting", values, getValues(formStore));
|
console.log("submitting", values, getValues(formStore));
|
||||||
|
|
||||||
// const r = await callApi("set_admin_service", {
|
const r = await set_single_service(
|
||||||
// base_url: props.base_url,
|
queryClient,
|
||||||
// allowed_keys: values.allowedKeys.reduce(
|
props.base_url,
|
||||||
// (acc, curr) => ({ ...acc, [curr.name]: curr.value }),
|
"",
|
||||||
// {}
|
"admin",
|
||||||
// ),
|
{
|
||||||
// });
|
meta: {
|
||||||
// if (r.status === "success") {
|
name: "admin",
|
||||||
// toast.success("Successfully updated admin settings");
|
},
|
||||||
// }
|
roles: {
|
||||||
// if (r.status === "error") {
|
default: {
|
||||||
// toast.error(`Failed to update admin settings: ${r.errors[0].message}`);
|
tags: ["all"],
|
||||||
toast.error(`Failed to update admin settings: feature disabled`);
|
},
|
||||||
// }
|
},
|
||||||
|
config: {
|
||||||
|
allowedKeys: 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({
|
queryClient.invalidateQueries({
|
||||||
queryKey: [props.base_url, "get_admin_service"],
|
queryKey: [props.base_url, "get_admin_service"],
|
||||||
});
|
});
|
||||||
@@ -340,10 +354,11 @@ type AdminData = ClanServiceInstance<"admin">;
|
|||||||
|
|
||||||
export const ClanDetails = () => {
|
export const ClanDetails = () => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const clan_dir = window.atob(params.id);
|
const clan_dir = window.atob(params.id);
|
||||||
// Fetch general meta data
|
// Fetch general meta data
|
||||||
const clanQuery = createQuery(() => ({
|
const clanQuery = createQuery(() => ({
|
||||||
queryKey: [clan_dir, "meta"],
|
queryKey: [clan_dir, "inventory", "meta"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const result = await callApi("show_clan_meta", { uri: clan_dir });
|
const result = await callApi("show_clan_meta", { uri: clan_dir });
|
||||||
if (result.status === "error") throw new Error("Failed to fetch data");
|
if (result.status === "error") throw new Error("Failed to fetch data");
|
||||||
@@ -352,11 +367,11 @@ export const ClanDetails = () => {
|
|||||||
}));
|
}));
|
||||||
// Fetch admin settings
|
// Fetch admin settings
|
||||||
const adminQuery = createQuery(() => ({
|
const adminQuery = createQuery(() => ({
|
||||||
queryKey: [clan_dir, "get_admin_service"],
|
queryKey: [clan_dir, "inventory", "services", "admin"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const result = await get_single_service(clan_dir, "", "admin");
|
const result = await get_single_service(queryClient, clan_dir, "admin");
|
||||||
if (!result) throw new Error("Failed to fetch data");
|
if (!result) throw new Error("Failed to fetch data");
|
||||||
return result || null;
|
return result;
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -371,7 +386,7 @@ export const ClanDetails = () => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Switch>
|
<Switch fallback={<>General data not available</>}>
|
||||||
<Match when={clanQuery.data}>
|
<Match when={clanQuery.data}>
|
||||||
{(d) => <EditClanForm initial={d()} directory={clan_dir} />}
|
{(d) => <EditClanForm initial={d()} directory={clan_dir} />}
|
||||||
</Match>
|
</Match>
|
||||||
@@ -386,7 +401,7 @@ export const ClanDetails = () => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Switch>
|
<Switch fallback={<>Admin data not available</>}>
|
||||||
<Match when={adminQuery.data}>
|
<Match when={adminQuery.data}>
|
||||||
{(d) => <AdminModuleForm admin={d()} base_url={clan_dir} />}
|
{(d) => <AdminModuleForm admin={d()} base_url={clan_dir} />}
|
||||||
</Match>
|
</Match>
|
||||||
|
|||||||
Reference in New Issue
Block a user