diff --git a/pkgs/clan-cli/clan_cli/machines/__init__.py b/pkgs/clan-cli/clan_cli/machines/__init__.py index 815629499..449f6903e 100644 --- a/pkgs/clan-cli/clan_cli/machines/__init__.py +++ b/pkgs/clan-cli/clan_cli/machines/__init__.py @@ -5,6 +5,7 @@ from .create import register_create_parser from .delete import register_delete_parser from .install import register_install_parser from .list import register_list_parser +from .show import register_show_parser from .update import register_update_parser @@ -62,6 +63,17 @@ Examples: ) register_list_parser(list_parser) + show_parser = subparser.add_parser( + "show", + help="Show a machine", + epilog=( + """ +This subcommand shows the details of a machine managed by this clan like icon, description, etc +""" + ), + ) + register_show_parser(show_parser) + install_parser = subparser.add_parser( "install", help="Install a machine", diff --git a/pkgs/clan-cli/clan_cli/machines/list.py b/pkgs/clan-cli/clan_cli/machines/list.py index 7964e1208..56ae1c765 100644 --- a/pkgs/clan-cli/clan_cli/machines/list.py +++ b/pkgs/clan-cli/clan_cli/machines/list.py @@ -1,5 +1,4 @@ import argparse -import dataclasses import json import logging from pathlib import Path @@ -12,24 +11,15 @@ from ..nix import nix_config, nix_eval log = logging.getLogger(__name__) -@dataclasses.dataclass -class MachineInfo: - machine_name: str - machine_description: str | None - machine_icon: str | None - - @API.register -def list_machines(flake_url: str | Path, debug: bool) -> dict[str, MachineInfo]: +def list_machines(flake_url: str | Path, debug: bool) -> list[str]: config = nix_config() system = config["system"] cmd = nix_eval( [ f"{flake_url}#clanInternals.machines.{system}", "--apply", - """builtins.mapAttrs (name: attrs: { - inherit (attrs.config.clanCore) machineDescription machineIcon machineName; -})""", + "builtins.attrNames", "--json", ] ) @@ -37,27 +27,13 @@ def list_machines(flake_url: str | Path, debug: bool) -> dict[str, MachineInfo]: proc = run_no_stdout(cmd) res = proc.stdout.strip() - machines_dict = json.loads(res) - - return { - k: MachineInfo( - machine_name=v.get("machineName"), - machine_description=v.get("machineDescription", None), - machine_icon=v.get("machineIcon", None), - ) - for k, v in machines_dict.items() - } + return json.loads(res) def list_command(args: argparse.Namespace) -> None: flake_path = Path(args.flake).resolve() - print("Listing all machines:\n") - print("Source: ", flake_path) - print("-" * 40) - for name, machine in list_machines(flake_path, args.debug).items(): - description = machine.machine_description or "[no description]" - print(f"{name}\n: {description}\n") - print("-" * 40) + for name in list_machines(flake_path, args.debug): + print(name) def register_list_parser(parser: argparse.ArgumentParser) -> None: diff --git a/pkgs/clan-cli/clan_cli/machines/show.py b/pkgs/clan-cli/clan_cli/machines/show.py new file mode 100644 index 000000000..51561caa5 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/machines/show.py @@ -0,0 +1,58 @@ +import argparse +import dataclasses +import json +import logging +from pathlib import Path + +from clan_cli.api import API + +from ..cmd import run_no_stdout +from ..nix import nix_config, nix_eval +from .types import machine_name_type + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class MachineInfo: + machine_name: str + machine_description: str | None + machine_icon: str | None + + +@API.register +def show_machine(flake_url: str | Path, machine_name: str, debug: bool) -> MachineInfo: + config = nix_config() + system = config["system"] + cmd = nix_eval( + [ + f"{flake_url}#clanInternals.machines.{system}.{machine_name}", + "--apply", + "machine: { inherit (machine.config.clanCore) machineDescription machineIcon machineName; }", + "--json", + ] + ) + proc = run_no_stdout(cmd) + res = proc.stdout.strip() + machine = json.loads(res) + + return MachineInfo( + machine_name=machine.get("machineName"), + machine_description=machine.get("machineDescription", None), + machine_icon=machine.get("machineIcon", None), + ) + + +def show_command(args: argparse.Namespace) -> None: + flake_path = Path(args.flake).resolve() + machine = show_machine(flake_path, args.machine, args.debug) + print(f"Name: {machine.machine_name}") + print(f"Description: {machine.machine_description or ''}") + print(f"Icon: {machine.machine_icon or ''}") + + +def register_show_parser(parser: argparse.ArgumentParser) -> None: + parser.set_defaults(func=show_command) + parser.add_argument( + "machine", help="the name of the machine", type=machine_name_type + ) diff --git a/pkgs/clan-cli/clan_cli/secrets/machines.py b/pkgs/clan-cli/clan_cli/secrets/machines.py index f84b89a8a..0a57d860c 100644 --- a/pkgs/clan-cli/clan_cli/secrets/machines.py +++ b/pkgs/clan-cli/clan_cli/secrets/machines.py @@ -176,7 +176,7 @@ def register_machines_parser(parser: argparse.ArgumentParser) -> None: "remove-secret", help="remove a group's access to a secret" ) remove_secret_parser.add_argument( - "machine", help="the name of the group", type=machine_name_type + "machine", help="the name of the machine", type=machine_name_type ) remove_secret_parser.add_argument( "secret", help="the name of the secret", type=secret_name_type diff --git a/pkgs/clan-cli/tests/test_machines_cli.py b/pkgs/clan-cli/tests/test_machines_cli.py index 3a25e7ae4..c4e483d42 100644 --- a/pkgs/clan-cli/tests/test_machines_cli.py +++ b/pkgs/clan-cli/tests/test_machines_cli.py @@ -21,6 +21,13 @@ def test_machine_subcommands( assert "vm1" in out.out assert "vm2" in out.out + capsys.readouterr() + cli.run(["machines", "show", "--flake", str(test_flake_with_core.path), "machine1"]) + out = capsys.readouterr() + assert "machine1" in out.out + assert "Description" in out.out + print(out) + cli.run( ["machines", "delete", "--flake", str(test_flake_with_core.path), "machine1"] ) diff --git a/pkgs/webview-ui/app/src/Config.tsx b/pkgs/webview-ui/app/src/Config.tsx index 21bfcb4fa..e737c1338 100644 --- a/pkgs/webview-ui/app/src/Config.tsx +++ b/pkgs/webview-ui/app/src/Config.tsx @@ -10,7 +10,7 @@ import { OperationResponse, pyApi } from "./message"; export const makeCountContext = () => { const [machines, setMachines] = createSignal< OperationResponse<"list_machines"> - >({}); + >([]); const [loading, setLoading] = createSignal(false); pyApi.list_machines.receive((machines) => { @@ -41,7 +41,7 @@ export const CountContext = createContext([ loading: () => false, // eslint-disable-next-line - machines: () => ({}), + machines: () => ([]), }, { // eslint-disable-next-line diff --git a/pkgs/webview-ui/app/src/routes/machines/view.tsx b/pkgs/webview-ui/app/src/routes/machines/view.tsx index 049933dc2..dff0e5dc3 100644 --- a/pkgs/webview-ui/app/src/routes/machines/view.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/view.tsx @@ -5,8 +5,6 @@ import { route } from "@/src/App"; export const MachineListView: Component = () => { const [{ machines, loading }, { getMachines }] = useCountContext(); - const list = () => Object.values(machines()); - createEffect(() => { if (route() === "machines") getMachines(); }); @@ -34,12 +32,12 @@ export const MachineListView: Component = () => { - + No machines found
    - + {(entry) => (
  • @@ -50,7 +48,8 @@ export const MachineListView: Component = () => {
    -

    {entry.machine_name}

    +

    {entry}

    + {/*

    { > {entry.machine_description || "No description"}

    + */}