UI: AdminSettings page

This commit is contained in:
Johannes Kirschbauer
2024-09-02 15:08:36 +02:00
parent 3b526955a2
commit 5cfa72edcc
3 changed files with 102 additions and 22 deletions

View File

@@ -3,7 +3,7 @@ import logging
from dataclasses import dataclass, field
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Any
from typing import Any, Literal
from clan_cli.clan_uri import FlakeId
from clan_cli.cmd import run_no_stdout
@@ -64,13 +64,24 @@ class Machine:
self.deployment["targetHost"] = value
@property
def secret_facts_module(self) -> str:
def secret_facts_module(
self,
) -> Literal[
"clan_cli.facts.secret_modules.sops",
"clan_cli.facts.secret_modules.vm",
"clan_cli.facts.secret_modules.password_store",
]:
return self.deployment["facts"]["secretModule"]
@property
def public_facts_module(self) -> str:
def public_facts_module(
self,
) -> Literal[
"clan_cli.facts.public_modules.in_repo", "clan_cli.facts.public_modules.vm"
]:
return self.deployment["facts"]["publicModule"]
# WIP: Vars module is not ready yet.
@property
def secret_vars_module(self) -> str:
return self.deployment["vars"]["secretModule"]

View File

@@ -2,34 +2,105 @@ import { callApi, SuccessData } from "@/src/api";
import { BackButton } from "@/src/components/BackButton";
import { useParams } from "@solidjs/router";
import { createQuery } from "@tanstack/solid-query";
import { createEffect, For, Match, Switch } from "solid-js";
import { createEffect, createSignal, For, Match, Switch } from "solid-js";
import { Show } from "solid-js";
import { DiskView } from "../disk/view";
import { Accessor } from "solid-js";
import {
createForm,
FieldArray,
FieldValues,
getValue,
getValues,
insert,
setValue,
} from "@modular-forms/solid";
import { TextInput } from "@/src/components/TextInput";
type AdminData = SuccessData<"get_admin_service">["data"];
interface ClanDetailsProps {
admin: AdminData;
}
interface AdminSettings extends FieldValues {
allowedKeys: { name: string; value: string }[];
}
const ClanDetails = (props: ClanDetailsProps) => {
const items = () =>
Object.entries<string>(
(props.admin?.config?.allowedKeys as Record<string, string>) || {},
);
const [formStore, { Form, Field }] = createForm<AdminSettings>({
initialValues: {
allowedKeys: items().map(([name, value]) => ({ name, value })),
},
});
const [keys, setKeys] = createSignal<1[]>(new Array(items().length).fill(1));
const handleSubmit = async (values: AdminSettings) => {
console.log("submitting", values, getValues(formStore));
};
return (
<div>
<h1>Clan Details </h1>
<For each={items()}>
{([name, key]) => (
<div>
<span>{name}</span>
<span>{key}</span>
</div>
)}
</For>
<span class="text-xl text-primary">Clan Settings</span>
<br></br>
<span class="text-lg text-neutral">
Each of the following keys can be used to authenticate on any machine
</span>
<Form onSubmit={handleSubmit}>
<div class="grid grid-cols-12 gap-2">
<For each={keys()}>
{(name, idx) => (
<>
<Field name={`allowedKeys.${idx()}.name`}>
{(field, props) => (
<TextInput
formStore={formStore}
inputProps={props}
label={`allowedKeys.${idx()}.name-` + items().length}
value={field.value ?? ""}
error={field.error}
class="col-span-4"
required
/>
)}
</Field>
<Field name={`allowedKeys.${idx()}.value`}>
{(field, props) => (
<TextInput
formStore={formStore}
inputProps={props}
label="Value"
value={field.value ?? ""}
error={field.error}
class="col-span-7"
required
/>
)}
</Field>
<button class="btn btn-ghost col-span-1 self-end">
<span class="material-icons">delete</span>
</button>
</>
)}
</For>
</div>
<div class="flex w-full my-2 gap-2">
<button
class="btn btn-ghost btn-square"
onClick={(e) => {
e.preventDefault();
setKeys((c) => [...c, 1]);
console.log(keys());
}}
>
<span class="material-icons">add</span>
</button>
<button class="btn">Submit</button>
</div>
</Form>
</div>
);
};
@@ -60,7 +131,6 @@ export const Details = () => {
{(d) => <ClanDetails admin={query.data} />}
</Match>
</Switch>
{clan_dir}
</Show>
</div>
);

View File

@@ -57,10 +57,12 @@ export const Flash = () => {
});
const addWifiNetwork = () => {
const updatedNetworks = [...wifiNetworks(), { ssid: "", password: "" }];
setWifiNetworks(updatedNetworks);
setPasswordVisibility([...passwordVisibility(), false]);
setValue(formStore, "wifi", updatedNetworks);
setWifiNetworks((c) => {
const res = [...c, { ssid: "", password: "" }];
setValue(formStore, "wifi", res);
return res;
});
setPasswordVisibility((c) => [...c, false]);
};
const removeWifiNetwork = (index: number) => {
@@ -153,10 +155,7 @@ export const Flash = () => {
language: values.language,
keymap: values.keymap,
ssh_keys_path: values.sshKeys.map((file) => file.name),
wifi_settings: values.wifi.map((network) => ({
ssid: network.ssid,
password: network.password,
})),
wifi_settings: values.wifi,
},
dry_run: false,
write_efi_boot_entries: false,