diff --git a/pkgs/clan-cli/clan_cli/machines/create.py b/pkgs/clan-cli/clan_cli/machines/create.py index 0f5df27ee..062d7bfd0 100644 --- a/pkgs/clan-cli/clan_cli/machines/create.py +++ b/pkgs/clan-cli/clan_cli/machines/create.py @@ -1,13 +1,17 @@ import argparse import logging import re -from pathlib import Path from ..api import API from ..clan_uri import FlakeId from ..errors import ClanError -from ..git import commit_file -from ..inventory import Machine, MachineDeploy, get_path, load_inventory, save_inventory +from ..inventory import ( + Machine, + MachineDeploy, + load_inventory_eval, + load_inventory_json, + save_inventory, +) log = logging.getLogger(__name__) @@ -20,12 +24,15 @@ def create_machine(flake: FlakeId, machine: Machine) -> None: "Machine name must be a valid hostname", location="Create Machine" ) - inventory = load_inventory(flake.path) + inventory = load_inventory_json(flake.path) + full_inventory = load_inventory_eval(flake.path) + + if machine.name in full_inventory.machines.keys(): + raise ClanError(f"Machine with the name {machine.name} already exists") + inventory.machines.update({machine.name: machine}) save_inventory(inventory, flake.path, f"Create machine {machine.name}") - commit_file(get_path(flake.path), Path(flake.path)) - def create_command(args: argparse.Namespace) -> None: create_machine( diff --git a/pkgs/webview-ui/.gitignore b/pkgs/webview-ui/.gitignore index 9e5bfb42d..590601772 100644 --- a/pkgs/webview-ui/.gitignore +++ b/pkgs/webview-ui/.gitignore @@ -1 +1,3 @@ -api \ No newline at end of file +api + +.vite \ No newline at end of file diff --git a/pkgs/webview-ui/app/src/Routes.tsx b/pkgs/webview-ui/app/src/Routes.tsx index 51f0c01d6..aceef3271 100644 --- a/pkgs/webview-ui/app/src/Routes.tsx +++ b/pkgs/webview-ui/app/src/Routes.tsx @@ -8,6 +8,7 @@ import { Flash } from "./routes/flash/view"; import { Settings } from "./routes/settings"; import { Welcome } from "./routes/welcome"; import { Deploy } from "./routes/deploy"; +import { CreateMachine } from "./routes/machines/create"; export type Route = keyof typeof routes; @@ -22,6 +23,11 @@ export const routes = { label: "Machines", icon: "devices_other", }, + "machines/add": { + child: CreateMachine, + label: "create Machine", + icon: "add", + }, hosts: { child: HostList, label: "hosts", diff --git a/pkgs/webview-ui/app/src/api.ts b/pkgs/webview-ui/app/src/api.ts index 602ef26c8..bcb1689cf 100644 --- a/pkgs/webview-ui/app/src/api.ts +++ b/pkgs/webview-ui/app/src/api.ts @@ -67,6 +67,17 @@ function createFunctions( dispatch: (args: OperationArgs) => void; receive: (fn: (response: OperationResponse) => void, id: string) => void; } { + window.clan[operationName] = (s: string) => { + const f = (response: OperationResponse) => { + // Get the correct receiver function for the op_key + const receiver = registry[operationName][response.op_key]; + if (receiver) { + receiver(response); + } + }; + deserialize(f)(s); + }; + return { dispatch: (args: OperationArgs) => { // Send the data to the gtk app @@ -78,15 +89,6 @@ function createFunctions( receive: (fn: (response: OperationResponse) => void, id: string) => { // @ts-expect-error: This should work although typescript doesn't let us write registry[operationName][id] = fn; - - window.clan[operationName] = (s: string) => { - const f = (response: OperationResponse) => { - if (response.op_key === id) { - registry[operationName][id](response); - } - }; - deserialize(f)(s); - }; }, }; } diff --git a/pkgs/webview-ui/app/src/index.css b/pkgs/webview-ui/app/src/index.css index 169082015..bbde75111 100644 --- a/pkgs/webview-ui/app/src/index.css +++ b/pkgs/webview-ui/app/src/index.css @@ -4,7 +4,6 @@ @tailwind components; @tailwind utilities; - html { overflow-x: hidden; overflow-y: scroll; diff --git a/pkgs/webview-ui/app/src/routes/machines/create.tsx b/pkgs/webview-ui/app/src/routes/machines/create.tsx new file mode 100644 index 000000000..0a379c0b1 --- /dev/null +++ b/pkgs/webview-ui/app/src/routes/machines/create.tsx @@ -0,0 +1,124 @@ +import { callApi, OperationArgs, pyApi } from "@/src/api"; +import { activeURI } from "@/src/App"; +import { createForm, required } from "@modular-forms/solid"; +import toast from "solid-toast"; + +type CreateMachineForm = OperationArgs<"create_machine">; + +export function CreateMachine() { + const [formStore, { Form, Field }] = createForm({}); + + const handleSubmit = async (values: CreateMachineForm) => { + const active_dir = activeURI(); + if (!active_dir) { + toast.error("Open a clan to create the machine in"); + return; + } + + callApi("create_machine", { + flake: { + loc: active_dir, + }, + machine: { + name: "jon", + deploy: { + targetHost: null, + }, + }, + }); + console.log("submit", values); + }; + return ( +
+ Create new Machine +
+ + {(field, props) => ( + <> + +
+ {field.error && ( + + {field.error} + + )} +
+ + )} +
+ + {(field, props) => ( + <> + +
+ {field.error && ( + + {field.error} + + )} +
+ + )} +
+ + {(field, props) => ( + <> + +
+ + Must be set before deployment for the following tasks: +
    +
  • + Detect hardware config +
  • +
  • + Detect disk layout +
  • +
  • + Remote installation +
  • +
+
+ {field.error && ( + + {field.error} + + )} +
+ + )} +
+ +
+
+ ); +} diff --git a/pkgs/webview-ui/app/src/routes/machines/view.tsx b/pkgs/webview-ui/app/src/routes/machines/view.tsx index 969033ddc..441fe755e 100644 --- a/pkgs/webview-ui/app/src/routes/machines/view.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/view.tsx @@ -7,7 +7,7 @@ import { createSignal, type Component, } from "solid-js"; -import { activeURI, route, setActiveURI } from "@/src/App"; +import { activeURI, route, setActiveURI, setRoute } from "@/src/App"; import { OperationResponse, callApi, pyApi } from "@/src/api"; import toast from "solid-toast"; import { MachineListItem } from "@/src/components/MachineListItem"; @@ -86,6 +86,11 @@ export const MachineListView: Component = () => { refresh +
+ +
{/* {(services) => (