UI/Modules: individual roles members

This commit is contained in:
Johannes Kirschbauer
2024-11-19 13:47:43 +01:00
committed by hsjobeki
parent bb6abd44aa
commit 176b07d6d1
7 changed files with 209 additions and 32 deletions

View File

@@ -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 (
<div class="p-1">
<BackButton />
<div class="p-2">
<h3 class="text-2xl">{params.id}</h3>
<Switch>
<Match when={modulesQuery.data?.find((i) => i[0] === params.id)}>
{(d) => <AddModule data={d()[1]} id={d()[0]} />}
</Match>
</Switch>
</div>
</div>
);
};
interface AddModuleProps {
data: ModuleInfo;
id: string;
}
export const AddModule = (props: AddModuleProps) => {
const tags = tagsQuery(activeURI());
const machines = machinesQuery(activeURI());
return (
<div>
<div>Add to your clan</div>
<Switch fallback="loading">
<Match when={tags.data}>
{(tags) => (
<For each={props.data.roles}>
{(role) => (
<>
<div class="text-neutral-600">{role}s</div>
<RoleForm
avilableTags={tags()}
availableMachines={machines.data || []}
/>
</>
)}
</For>
)}
</Match>
</Switch>
</div>
);
};
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<RoleFormData>({
// initialValues: {
// machines: ["hugo", "bruno"],
// tags: ["network", "backup"],
// },
});
const handleSubmit: SubmitHandler<RoleFormData> = (values) => {
console.log(values);
};
return (
<Form onSubmit={handleSubmit}>
<Field name="machines" type="string[]">
{(field, fieldProps) => (
<SelectInput
error={field.error}
label={"Machines"}
value={field.value || []}
options={props.availableMachines.map((o) => ({
value: o,
label: o,
}))}
multiple
selectProps={fieldProps}
/>
)}
</Field>
<Field name="tags" type="string[]">
{(field, fieldProps) => (
<SelectInput
error={field.error}
label={"Tags"}
value={field.value || []}
options={props.avilableTags.map((o) => ({
value: o,
label: o,
}))}
multiple
selectProps={fieldProps}
/>
)}
</Field>
</Form>
);
};

View File

@@ -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 (
<div class="flex w-full flex-col gap-2">
<article class="prose">{props.data.description}</article>
@@ -89,37 +116,11 @@ const Details = (props: DetailsProps) => {
<SolidMarkdown>{props.data.readme}</SolidMarkdown>
</div>
<div class="my-2 flex w-full gap-2">
<button
class="btn btn-primary"
onClick={async () => {
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`,
});
}}
>
<button class="btn btn-primary" onClick={add}>
<span class="material-icons ">add</span>
Add to Clan
</button>
{/* Add -> Select (required) roles, assign Machine */}
</div>
<ModuleForm id={props.id} />
</div>

View File

@@ -18,11 +18,12 @@ const ModuleListItem = (props: { name: string; info: ModuleInfo }) => {
<div class="join">more</div>
</div>
<A href={`/modules/${name}`}>
<A href={`/modules/details/${name}`}>
<div class="stat-value underline">{name}</div>
</A>
<div>{info.description}</div>
<div>{JSON.stringify(info.constraints)}</div>
</div>
);
};