From da25afd97806749c25e0a5ea985ef9af2f22455a Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Mon, 2 Sep 2024 15:06:55 +0200 Subject: [PATCH 1/2] API: init iwd clanModule inventory --- clanModules/iwd/roles/default.nix | 1 + pkgs/clan-cli/clan_cli/inventory/classes.py | 38 +++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 clanModules/iwd/roles/default.nix diff --git a/clanModules/iwd/roles/default.nix b/clanModules/iwd/roles/default.nix new file mode 100644 index 000000000..ffcd4415b --- /dev/null +++ b/clanModules/iwd/roles/default.nix @@ -0,0 +1 @@ +{ } diff --git a/pkgs/clan-cli/clan_cli/inventory/classes.py b/pkgs/clan-cli/clan_cli/inventory/classes.py index 11cf6daee..c0c31e9ae 100644 --- a/pkgs/clan-cli/clan_cli/inventory/classes.py +++ b/pkgs/clan-cli/clan_cli/inventory/classes.py @@ -117,6 +117,43 @@ class ServiceBorgbackup: machines: dict[str, ServiceBorgbackupMachine] = field(default_factory = dict) +@dataclass +class IwdConfigNetwork: + ssid: str + + +@dataclass +class IwdConfig: + networks: dict[str, IwdConfigNetwork] = field(default_factory = dict) + + +@dataclass +class ServiceIwdMachine: + config: IwdConfig = field(default_factory = IwdConfig) + imports: list[str] = field(default_factory = list) + + +@dataclass +class ServiceIwdRoleDefault: + config: IwdConfig = field(default_factory = IwdConfig) + imports: list[str] = field(default_factory = list) + machines: list[str] = field(default_factory = list) + tags: list[str] = field(default_factory = list) + + +@dataclass +class ServiceIwdRole: + default: ServiceIwdRoleDefault + + +@dataclass +class ServiceIwd: + meta: ServiceMeta + roles: ServiceIwdRole + config: IwdConfig = field(default_factory = IwdConfig) + machines: dict[str, ServiceIwdMachine] = field(default_factory = dict) + + @dataclass class PackagesConfig: packages: list[str] = field(default_factory = list) @@ -185,6 +222,7 @@ class ServiceSingleDisk: class Service: admin: dict[str, ServiceAdmin] = field(default_factory = dict) borgbackup: dict[str, ServiceBorgbackup] = field(default_factory = dict) + iwd: dict[str, ServiceIwd] = field(default_factory = dict) packages: dict[str, ServicePackage] = field(default_factory = dict) single_disk: dict[str, ServiceSingleDisk] = field(default_factory = dict, metadata = {"alias": "single-disk"}) From c2d088b2456e1943112a2f4348dbc2f0c30a2caf Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Mon, 2 Sep 2024 15:08:36 +0200 Subject: [PATCH 2/2] UI: AdminSettings page --- pkgs/clan-cli/clan_cli/machines/machines.py | 17 +++- .../app/src/routes/clan/details.tsx | 92 ++++++++++++++++--- pkgs/webview-ui/app/src/routes/flash/view.tsx | 15 ++- 3 files changed, 102 insertions(+), 22 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/machines/machines.py b/pkgs/clan-cli/clan_cli/machines/machines.py index 78ecfd99e..0ddd60187 100644 --- a/pkgs/clan-cli/clan_cli/machines/machines.py +++ b/pkgs/clan-cli/clan_cli/machines/machines.py @@ -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"] diff --git a/pkgs/webview-ui/app/src/routes/clan/details.tsx b/pkgs/webview-ui/app/src/routes/clan/details.tsx index 27ac2f542..21048d329 100644 --- a/pkgs/webview-ui/app/src/routes/clan/details.tsx +++ b/pkgs/webview-ui/app/src/routes/clan/details.tsx @@ -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( (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).fill(1)); + + const handleSubmit = async (values: AdminSettings) => { + console.log("submitting", values, getValues(formStore)); + }; return (
-

Clan Details

- - {([name, key]) => ( -
- {name} - {key} -
- )} -
+ Clan Settings +

+ + Each of the following keys can be used to authenticate on any machine + +
+
+ + {(name, idx) => ( + <> + + {(field, props) => ( + + )} + + + {(field, props) => ( + + )} + + + + )} + +
+
+ + +
+
); }; @@ -60,7 +131,6 @@ export const Details = () => { {(d) => } - {clan_dir} ); diff --git a/pkgs/webview-ui/app/src/routes/flash/view.tsx b/pkgs/webview-ui/app/src/routes/flash/view.tsx index b62cfc51f..26cbd9ab2 100644 --- a/pkgs/webview-ui/app/src/routes/flash/view.tsx +++ b/pkgs/webview-ui/app/src/routes/flash/view.tsx @@ -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,