Create machine: init view with api
This commit is contained in:
@@ -1,13 +1,17 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from ..api import API
|
from ..api import API
|
||||||
from ..clan_uri import FlakeId
|
from ..clan_uri import FlakeId
|
||||||
from ..errors import ClanError
|
from ..errors import ClanError
|
||||||
from ..git import commit_file
|
from ..inventory import (
|
||||||
from ..inventory import Machine, MachineDeploy, get_path, load_inventory, save_inventory
|
Machine,
|
||||||
|
MachineDeploy,
|
||||||
|
load_inventory_eval,
|
||||||
|
load_inventory_json,
|
||||||
|
save_inventory,
|
||||||
|
)
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
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"
|
"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})
|
inventory.machines.update({machine.name: machine})
|
||||||
save_inventory(inventory, flake.path, f"Create machine {machine.name}")
|
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:
|
def create_command(args: argparse.Namespace) -> None:
|
||||||
create_machine(
|
create_machine(
|
||||||
|
|||||||
4
pkgs/webview-ui/.gitignore
vendored
4
pkgs/webview-ui/.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
api
|
api
|
||||||
|
|
||||||
|
.vite
|
||||||
@@ -8,6 +8,7 @@ import { Flash } from "./routes/flash/view";
|
|||||||
import { Settings } from "./routes/settings";
|
import { Settings } from "./routes/settings";
|
||||||
import { Welcome } from "./routes/welcome";
|
import { Welcome } from "./routes/welcome";
|
||||||
import { Deploy } from "./routes/deploy";
|
import { Deploy } from "./routes/deploy";
|
||||||
|
import { CreateMachine } from "./routes/machines/create";
|
||||||
|
|
||||||
export type Route = keyof typeof routes;
|
export type Route = keyof typeof routes;
|
||||||
|
|
||||||
@@ -22,6 +23,11 @@ export const routes = {
|
|||||||
label: "Machines",
|
label: "Machines",
|
||||||
icon: "devices_other",
|
icon: "devices_other",
|
||||||
},
|
},
|
||||||
|
"machines/add": {
|
||||||
|
child: CreateMachine,
|
||||||
|
label: "create Machine",
|
||||||
|
icon: "add",
|
||||||
|
},
|
||||||
hosts: {
|
hosts: {
|
||||||
child: HostList,
|
child: HostList,
|
||||||
label: "hosts",
|
label: "hosts",
|
||||||
|
|||||||
@@ -67,6 +67,17 @@ function createFunctions<K extends OperationNames>(
|
|||||||
dispatch: (args: OperationArgs<K>) => void;
|
dispatch: (args: OperationArgs<K>) => void;
|
||||||
receive: (fn: (response: OperationResponse<K>) => void, id: string) => void;
|
receive: (fn: (response: OperationResponse<K>) => void, id: string) => void;
|
||||||
} {
|
} {
|
||||||
|
window.clan[operationName] = (s: string) => {
|
||||||
|
const f = (response: OperationResponse<K>) => {
|
||||||
|
// Get the correct receiver function for the op_key
|
||||||
|
const receiver = registry[operationName][response.op_key];
|
||||||
|
if (receiver) {
|
||||||
|
receiver(response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deserialize(f)(s);
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dispatch: (args: OperationArgs<K>) => {
|
dispatch: (args: OperationArgs<K>) => {
|
||||||
// Send the data to the gtk app
|
// Send the data to the gtk app
|
||||||
@@ -78,15 +89,6 @@ function createFunctions<K extends OperationNames>(
|
|||||||
receive: (fn: (response: OperationResponse<K>) => void, id: string) => {
|
receive: (fn: (response: OperationResponse<K>) => void, id: string) => {
|
||||||
// @ts-expect-error: This should work although typescript doesn't let us write
|
// @ts-expect-error: This should work although typescript doesn't let us write
|
||||||
registry[operationName][id] = fn;
|
registry[operationName][id] = fn;
|
||||||
|
|
||||||
window.clan[operationName] = (s: string) => {
|
|
||||||
const f = (response: OperationResponse<K>) => {
|
|
||||||
if (response.op_key === id) {
|
|
||||||
registry[operationName][id](response);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
deserialize(f)(s);
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
|
||||||
html {
|
html {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|||||||
124
pkgs/webview-ui/app/src/routes/machines/create.tsx
Normal file
124
pkgs/webview-ui/app/src/routes/machines/create.tsx
Normal file
@@ -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<CreateMachineForm>({});
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div class="px-1">
|
||||||
|
Create new Machine
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
|
<Field
|
||||||
|
name="machine.name"
|
||||||
|
validate={[required("This field is required")]}
|
||||||
|
>
|
||||||
|
{(field, props) => (
|
||||||
|
<>
|
||||||
|
<label class="input input-bordered flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="grow"
|
||||||
|
placeholder="name"
|
||||||
|
required
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div class="label">
|
||||||
|
{field.error && (
|
||||||
|
<span class="label-text-alt font-bold text-error">
|
||||||
|
{field.error}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
<Field name="machine.description">
|
||||||
|
{(field, props) => (
|
||||||
|
<>
|
||||||
|
<label class="input input-bordered flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="grow"
|
||||||
|
placeholder="description"
|
||||||
|
required
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div class="label">
|
||||||
|
{field.error && (
|
||||||
|
<span class="label-text-alt font-bold text-error">
|
||||||
|
{field.error}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
<Field name="machine.deploy.targetHost">
|
||||||
|
{(field, props) => (
|
||||||
|
<>
|
||||||
|
<label class="input input-bordered flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="grow"
|
||||||
|
placeholder="root@flash-installer.local"
|
||||||
|
required
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text-alt text-neutral">
|
||||||
|
Must be set before deployment for the following tasks:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span>Detect hardware config</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span>Detect disk layout</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span>Remote installation</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
{field.error && (
|
||||||
|
<span class="label-text-alt font-bold text-error">
|
||||||
|
{field.error}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
<button class="btn btn-error float-right" type="submit">
|
||||||
|
<span class="material-icons">add</span>Create
|
||||||
|
</button>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
createSignal,
|
createSignal,
|
||||||
type Component,
|
type Component,
|
||||||
} from "solid-js";
|
} 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 { OperationResponse, callApi, pyApi } from "@/src/api";
|
||||||
import toast from "solid-toast";
|
import toast from "solid-toast";
|
||||||
import { MachineListItem } from "@/src/components/MachineListItem";
|
import { MachineListItem } from "@/src/components/MachineListItem";
|
||||||
@@ -86,6 +86,11 @@ export const MachineListView: Component = () => {
|
|||||||
<span class="material-icons ">refresh</span>
|
<span class="material-icons ">refresh</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tooltip tooltip-bottom" data-tip="Create machine">
|
||||||
|
<button class="btn btn-ghost" onClick={() => setRoute("machines/add")}>
|
||||||
|
<span class="material-icons ">add</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
{/* <Show when={services()}>
|
{/* <Show when={services()}>
|
||||||
{(services) => (
|
{(services) => (
|
||||||
<For each={Object.values(services())}>
|
<For each={Object.values(services())}>
|
||||||
|
|||||||
Reference in New Issue
Block a user