diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1d316a3f..262c7705 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,18 +7,6 @@ on: - master jobs: - # - name: run nix-eval-jobs - # run: nix run nixpkgs#nix-eval-jobs -- --gc-roots-dir gcroots --flake .#all-download-images | tee jobs.json - # - name: convert jobs json - # run: nix run nixpkgs#jq -- -r 'select(.system == "x86_64-linux") | .attr + " " + .drvPath + " " + .name' < jobs.json > jobs - # - name: build jobs - # run: | - # mkdir -p results - # while read -r attr drvPath name; do - # nix build "$drvPath^*" --out-link "results/$attr-$name" --print-build-logs - # done < jobs - # - name: check if nix-eval-jobs produced errors - # run: jq -e 'select(.error)' < jobs.json && exit 1 || true build-iso: runs-on: ubuntu-latest steps: diff --git a/controller/default.nix b/controller/default.nix index 3d7cc774..c6567645 100644 --- a/controller/default.nix +++ b/controller/default.nix @@ -1,4 +1,8 @@ -{ poetry2nix, git, makeWrapper, lib +{ poetry2nix +, git +, nixpkgs-fmt +, makeWrapper +, lib , }: poetry2nix.mkPoetryApplication { @@ -11,6 +15,6 @@ poetry2nix.mkPoetryApplication { nativeBuildInputs = [ makeWrapper ]; postInstall = '' wrapProgram $out/bin/thymis-controller \ - --prefix PATH : ${lib.makeBinPath [ git ]} + --prefix PATH : ${lib.makeBinPath [ git nixpkgs-fmt ]} ''; } diff --git a/controller/thymis_controller/crud/project.py b/controller/thymis_controller/crud/project.py index 79310d26..36e1fbe1 100644 --- a/controller/thymis_controller/crud/project.py +++ b/controller/thymis_controller/crud/project.py @@ -1,5 +1,4 @@ import json -from pydoc import locate from pathlib import Path from thymis_controller.models.state import State import os @@ -17,6 +16,7 @@ def initialize(self): # TODO git reop init - git config user and email state = State( version="0.0.1", + repositories={}, tags=[], devices=[], ) @@ -25,7 +25,9 @@ def initialize(self): def load_state_from_file(self): with open(Path(self.path) / "state.json", "r", encoding="utf-8") as f: state_dict = json.load(f) - return State.load_from_dict(state_dict) + state = State.load_from_dict(state_dict) + state.set_repositories_in_python_path(self.path) + return state def update_state(self, state): old_state = self.load_state_from_file() diff --git a/controller/thymis_controller/migration/migrate.py b/controller/thymis_controller/migration/migrate.py index 1da573bf..e01a6e26 100644 --- a/controller/thymis_controller/migration/migrate.py +++ b/controller/thymis_controller/migration/migrate.py @@ -1,9 +1,13 @@ from packaging import version from thymis_controller.migration.to_0_0_2 import to_0_0_2 +from thymis_controller.migration.to_0_0_3 import to_0_0_3 +from thymis_controller.migration.to_0_0_4 import to_0_0_4 KNOWN_VERSIONS = [ "0.0.1", "0.0.2", + "0.0.3", + "0.0.4", ] # TODO: remove this, replace with dynamic versioning @@ -13,4 +17,10 @@ def migrate(state: dict): if version.parse(state["version"]) == version.parse("0.0.1"): state = to_0_0_2(state) + if version.parse(state["version"]) == version.parse("0.0.2"): + state = to_0_0_3(state) + + if version.parse(state["version"]) == version.parse("0.0.3"): + state = to_0_0_4(state) + return state diff --git a/controller/thymis_controller/migration/to_0_0_3.py b/controller/thymis_controller/migration/to_0_0_3.py new file mode 100644 index 00000000..19799fe9 --- /dev/null +++ b/controller/thymis_controller/migration/to_0_0_3.py @@ -0,0 +1,5 @@ +def to_0_0_3(state: dict): + state["version"] = "0.0.3" + state["repositories"] = {} + + return state diff --git a/controller/thymis_controller/migration/to_0_0_4.py b/controller/thymis_controller/migration/to_0_0_4.py new file mode 100644 index 00000000..535a951f --- /dev/null +++ b/controller/thymis_controller/migration/to_0_0_4.py @@ -0,0 +1,7 @@ +def to_0_0_4(state: dict): + state["version"] = "0.0.4" + + for repo in state["repositories"]: + state["repositories"][repo]["inputs_follows"] = {} + + return state diff --git a/controller/thymis_controller/models/__init__.py b/controller/thymis_controller/models/__init__.py index b10f0d0f..6bef85c6 100644 --- a/controller/thymis_controller/models/__init__.py +++ b/controller/thymis_controller/models/__init__.py @@ -3,4 +3,5 @@ from .modules import ALL_MODULES from .tag import Tag from .device import Device +from .repo import Repo from .state import State diff --git a/controller/thymis_controller/models/flake.nix.j2 b/controller/thymis_controller/models/flake.nix.j2 index 676bdf7e..6352abb9 100644 --- a/controller/thymis_controller/models/flake.nix.j2 +++ b/controller/thymis_controller/models/flake.nix.j2 @@ -2,82 +2,82 @@ description = "Thymis"; inputs = { - thymis.url = "github:thymis-io/thymis"; - # nixpkgs.url = "nixpkgs/nixos-23.05"; - nixpkgs.follows = "thymis/nixpkgs"; - home-manager.url = "github:nix-community/home-manager/release-23.11"; - home-manager.inputs.nixpkgs.follows = "nixpkgs"; - nixos-generators.url = "github:nix-community/nixos-generators"; - nixos-generators.inputs.nixpkgs.follows = "nixpkgs"; - nixos-hardware.url = "github:NixOS/nixos-hardware"; - flake-utils.url = "github:numtide/flake-utils"; - poetry2nix = { - url = "github:nix-community/poetry2nix/1.42.1"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.flake-utils.follows = "flake-utils"; - }; - }; + {% for name, repository in repositories.items() %} + {{ name }} = { + {% if repository.url %} + url = "{{ repository.url }}"; + {% endif %}{% if repository.follows %} + follows = "{{ repository.follows }}"; + {% endif %}{% if repository.input_follows %} + {% for input_name, input_repository in repository.input_follows.items() %} + inputs.{{ input_name }}.follows = "{{ input_repository }}"; + {% endfor %}{% endif %} + };{% endfor %} + }; - outputs = inputs@{ self, nixpkgs, home-manager, poetry2nix, flake-utils, thymis, ... }: - let - eachSystem = nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" ]; - state-json = builtins.fromJSON (builtins.readFile ./state.json); - device-to-nixosConfigurations = d: + outputs = + inputs@{ self + #{% for name, repository in repositories.items() %} + , {{ name + }} + {% endfor %} + , ... + }: let - # device-modules are all files in ./hosts/ that end with .nix - device-modules = nixpkgs.lib.mapAttrsToList - (path: type: ./hosts/${d.identifier}/${path}) - (nixpkgs.lib.filterAttrs - (f: t: t == "regular" && nixpkgs.lib.hasSuffix ".nix" (builtins.toString f)) - ( - builtins.readDir ./hosts/${d.identifier} - )); - # for all tags, get them. For each tag, all files in ./tags/ that end with .nix - tag-modules = builtins.concatMap - (tag: nixpkgs.lib.mapAttrsToList - (path: type: ./tags/${tag}/${path}) - (nixpkgs.lib.filterAttrs - (f: t: t == "regular" && nixpkgs.lib.hasSuffix ".nix" (builtins.toString f)) - ( - builtins.readDir ./tags/${tag} - )) - ) - d.tags; - in - # { - # modules = builtins.concatLists [ - # device-modules - # tag-modules - # ]; - # }; - { - name = d.identifier; - value = nixpkgs.lib.nixosSystem { - modules = device-modules - ++ tag-modules - ++ [ - thymis.nixosModules.thymis - ]; - specialArgs = { - inherit inputs; + eachSystem = nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" ]; + state-json = builtins.fromJSON (builtins.readFile ./state.json); + device-to-nixosConfigurations = d: + let + # device-modules are all files in ./hosts/ that end with .nix + device-modules = nixpkgs.lib.mapAttrsToList + (path: type: ./hosts/${d.identifier}/${path}) + (nixpkgs.lib.filterAttrs + (f: t: t == "regular" && nixpkgs.lib.hasSuffix ".nix" (builtins.toString f)) + ( + builtins.readDir ./hosts/${d.identifier} + )); + # for all tags, get them. For each tag, all files in ./tags/ that end with .nix + tag-modules = builtins.concatMap + (tag: nixpkgs.lib.mapAttrsToList + (path: type: ./tags/${tag}/${path}) + (nixpkgs.lib.filterAttrs + (f: t: t == "regular" && nixpkgs.lib.hasSuffix ".nix" (builtins.toString f)) + ( + builtins.readDir ./tags/${tag} + )) + ) + d.tags; + in + { + name = d.identifier; + value = nixpkgs.lib.nixosSystem { + modules = device-modules + ++ tag-modules + ++ [ + thymis.nixosModules.thymis + ]; + specialArgs = { + inherit inputs; + }; + }; }; - }; - }; - in - rec { - nixosConfigurations = builtins.listToAttrs - (builtins.map device-to-nixosConfigurations state-json.devices); - packages = eachSystem (system: - let - pkgs = import nixpkgs { inherit system; }; + nixosConfigurations = builtins.listToAttrs + (builtins.map device-to-nixosConfigurations state-json.devices); in { - thymis = pkgs.writeText "thymis.json" - (builtins.toJSON ( - builtins.mapAttrs - (name: nixosCfg: nixosCfg.config.system.build.toplevel) - nixosConfigurations - )); - }); - }; -} + nixosConfigurations = nixosConfigurations; + packages = eachSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + thymis = pkgs.writeText "thymis.json" + (builtins.toJSON ( + builtins.mapAttrs + (name: nixosCfg: nixosCfg.config.system.build.toplevel) + nixosConfigurations + )); + }); + inputs = inputs; + }; + } diff --git a/controller/thymis_controller/models/modules/__init__.py b/controller/thymis_controller/models/modules/__init__.py index 52cbc14b..9aa700cf 100644 --- a/controller/thymis_controller/models/modules/__init__.py +++ b/controller/thymis_controller/models/modules/__init__.py @@ -17,3 +17,5 @@ NodeRedModule(), MqttxModule(), ] + +ALL_MODULES_START = ALL_MODULES.copy() diff --git a/controller/thymis_controller/models/repo.py b/controller/thymis_controller/models/repo.py new file mode 100644 index 00000000..56900904 --- /dev/null +++ b/controller/thymis_controller/models/repo.py @@ -0,0 +1,74 @@ +from typing import Dict, List, Optional +from pydantic import BaseModel +import sys +import os +import pkgutil +import importlib +from .module import Module +import thymis_controller.models.modules + + +from thymis_controller.nix import get_input_out_path + + +class Repo(BaseModel): + url: Optional[str] = None + follows: Optional[str] = None + inputs_follows: Dict[str, str] = {} + + +startup_python_path = sys.path.copy() +lockfile = None + + +def load_repositories(flake_path: os.PathLike, repositories: Dict[str, Repo]): + # only run if lockfile changed + global lockfile + # lockfile sits at path/flake.lock + lockfile_path = os.path.join(flake_path, "flake.lock") + with open(lockfile_path, "r") as f: + new_lockfile = f.read() + if new_lockfile == lockfile: + return + lockfile = new_lockfile + # for each repository: get_input_out_path from the flake.nix in the path + input_out_paths = {} + for name, repo in repositories.items(): + if not repo.url: + continue + path = get_input_out_path(flake_path, name) + if path is None: + continue + # check wether path / README.md exists and contains the string "contains thymis modules" + if not os.path.exists(os.path.join(path, "README.md")): + print(f"Repository {name} does not contain a README.md") + print(f"Skipping {name}") + continue + with open(os.path.join(path, "README.md"), "r") as f: + if "contains thymis modules" not in f.read(): + print(f"Repository {name} contains no thymis modules") + print(f"Skipping {name}") + continue + input_out_paths[name] = path + # add the paths to sys.path + sys.path = startup_python_path.copy() + # for path in input_out_paths.values(): + modules_found = [] + for name, path in input_out_paths.items(): + print(f"Adding {name} at {path} to sys.path") + sys.path.append(path) + # print modules in path + # print(list(pkgutil.iter_modules([path]))) + for module in pkgutil.walk_packages([path]): + imported_module = importlib.import_module(module.name) + for cls in imported_module.__dict__.values(): + if not isinstance(cls, type): + continue + if issubclass(cls, Module) and cls != Module: + module_obj = cls() + modules_found.append(module_obj) + print(f"Found module {module_obj.type}") + thymis_controller.models.modules.ALL_MODULES = ( + thymis_controller.models.modules.ALL_MODULES_START + ) + thymis_controller.models.modules.ALL_MODULES.extend(modules_found) diff --git a/controller/thymis_controller/models/state.py b/controller/thymis_controller/models/state.py index 0243100b..46fa4728 100644 --- a/controller/thymis_controller/models/state.py +++ b/controller/thymis_controller/models/state.py @@ -1,5 +1,5 @@ import asyncio -from typing import List, Optional +from typing import Dict, List, Optional from pydantic import BaseModel, SerializeAsAny from thymis_controller import models import os @@ -9,6 +9,11 @@ from thymis_controller.migration.migrate import migrate from thymis_controller.models.modules import ALL_MODULES import subprocess +import shutil +import sys +import importlib + +from thymis_controller.models.repo import load_repositories REPO_PATH = os.getenv("REPO_PATH") @@ -44,8 +49,15 @@ async def terminate_other_procs(): other_procs.clear() +needed_repositories = { + "thymis": models.Repo(url="github:thymis-io/thymis"), + "nixpkgs": models.Repo(follows="thymis/nixpkgs"), +} + + class State(BaseModel): version: str + repositories: Dict[str, models.Repo] tags: List[models.Tag] devices: List[models.Device] @@ -56,8 +68,17 @@ class State(BaseModel): def write_nix(self, path: os.PathLike): path = pathlib.Path(path) # write a flake.nix + repositories = needed_repositories | self.repositories with open(path / "flake.nix", "w+") as f: - f.write(env.get_template("flake.nix.j2").render(state=self)) + f.write(env.get_template("flake.nix.j2").render(repositories=repositories)) + # Check for nixpkgs-fmt binary + formatter_avail = shutil.which("nixpkgs-fmt") + if formatter_avail: + # format the flake.nix + subprocess.run(["nixpkgs-fmt", path / "flake.nix"]) + # write missing flake.lock entries using nix flake lock + subprocess.run(["nix", "flake", "lock"], cwd=path) + self.set_repositories_in_python_path(path) # create modules folder if not exists modules_path = path / "modules" del_path(modules_path) @@ -94,15 +115,29 @@ def write_nix(self, path: os.PathLike): repo = Repo.init(self.repo_dir()) repo.git.add(".") + def set_repositories_in_python_path(self, path: os.PathLike): + repositories = needed_repositories | self.repositories + load_repositories(path, repositories) + @classmethod def load_from_dict(cls, d): return cls(**migrate(d)) def get_module_class_instance_by_type(self, module_type: str): - for module in ALL_MODULES: - if module.type == module_type: - return module - raise Exception(f"module with type {module_type} not found") + # for module in ALL_MODULES: + # if module.type == module_type: + # return module + # split the module_type by . + module_type = module_type.rsplit(".", 1) + # import the module + try: + module = importlib.import_module(module_type[0]) + # get the class from the module + cls = getattr(module, module_type[1]) + # return an instance of the class + return cls() + except Exception as e: + raise Exception(f"Erorr while importing module {module_type}: {e}") def save(self, path: os.PathLike = "./"): path = os.path.join(path, "state.json") diff --git a/controller/thymis_controller/nix.py b/controller/thymis_controller/nix.py index d7b13b77..cd5b16fe 100644 --- a/controller/thymis_controller/nix.py +++ b/controller/thymis_controller/nix.py @@ -1,3 +1,7 @@ +import subprocess +import json + + def convert_python_value_to_nix(value): if isinstance(value, bool): return str(value).lower() @@ -7,3 +11,29 @@ def convert_python_value_to_nix(value): return f"[{' '.join([convert_python_value_to_nix(v) for v in value])}]" else: return str(value) + + +def get_input_out_path(flake_path, input_name): + # first run `nix build .#inputs..outPath` + # then run `nix eval .#inputs..outPath --json` + cmd = f"nix build {flake_path}#inputs.{input_name}.outPath" + + try: + subprocess.run( + cmd, shell=True, check=True, cwd=flake_path, stderr=subprocess.PIPE + ) + except subprocess.CalledProcessError as e: + print( + f"Command failed: {e.cmd} with exit code {e.returncode}: {e.stderr.decode()}" + ) + return None + + cmd = f"nix eval {flake_path}#inputs.{input_name}.outPath --json" + result = subprocess.run( + cmd, shell=True, check=True, capture_output=True, cwd=flake_path + ) + # result.stdout is a json string + result = json.loads(result.stdout) + # should be a string + assert isinstance(result, str) + return result diff --git a/controller/thymis_controller/routes/router.py b/controller/thymis_controller/routes/router.py index aa06c362..f3f9d02c 100644 --- a/controller/thymis_controller/routes/router.py +++ b/controller/thymis_controller/routes/router.py @@ -1,7 +1,7 @@ import asyncio import json from typing import List -from thymis_controller.models.modules import ALL_MODULES +import thymis_controller.models.modules from thymis_controller.models.state import State from fastapi import APIRouter, Depends, Request, BackgroundTasks, WebSocket from fastapi.responses import FileResponse, RedirectResponse @@ -21,7 +21,7 @@ def get_state(state: State = Depends(get_or_init_state)): @router.get("/available_modules") def get_available_modules(): - return ALL_MODULES + return thymis_controller.models.modules.ALL_MODULES @router.patch("/state") @@ -109,7 +109,10 @@ def get_history(state: State = Depends(get_or_init_state)): @router.post("/action/update") async def update( - background_tasks: BackgroundTasks, state: State = Depends(get_or_init_state) + background_tasks: BackgroundTasks, + project: project.Project = Depends(get_or_init_project), + state: State = Depends(get_or_init_state), ): + project.update_state(state.model_dump()) background_tasks.add_task(state.update, last_build_status) return {"message": "update started"} diff --git a/flake.nix b/flake.nix index 9206427c..fdebbecd 100644 --- a/flake.nix +++ b/flake.nix @@ -22,22 +22,14 @@ thymis = self; }; eachSystem = nixpkgs.lib.genAttrs (import ./flake.systems.nix); - in - rec { - formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.nixpkgs-fmt); - devShells = eachSystem (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - { - default = pkgs.mkShell { - packages = [ - pkgs.poetry - pkgs.nodejs - pkgs.pre-commit - ]; - }; - }); + nixosModules = { + thymis = ./thymis-nixos-module.nix; + } // nixpkgs.lib.mapAttrs' + (name: value: { + name = "thymis-device-${name}"; + value = value; + }) + (import ./devices.nix { inherit inputs; lib = nixpkgs.lib; }); download-image = { thymis-config ? throw "thymis-config is required. Provide with --argstr" }: let thymis-config-parsed = builtins.fromJSON thymis-config; @@ -56,6 +48,24 @@ inherit inputs; }; }); + in + { + inputs = inputs; + formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.nixpkgs-fmt); + devShells = eachSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.mkShell { + packages = [ + pkgs.poetry + pkgs.nodejs + pkgs.pre-commit + ]; + }; + }); + all-download-images = let devices = import ./devices.nix { lib = nixpkgs.lib; }; @@ -89,13 +99,13 @@ { thymis-frontend = thymis-frontend; thymis-controller = thymis-controller; - thymis-controller-container = pkgs.dockerTools.buildImage { + thymis-controller-container = pkgs.dockerTools.buildImage { name = "thymis-controller"; config = { Cmd = [ "${thymis-controller}/bin/thymis-controller" ]; }; }; - thymis-frontend-container = pkgs.dockerTools.buildImage { + thymis-frontend-container = pkgs.dockerTools.buildImage { name = "thymis-frontend"; config = { Cmd = [ "${thymis-frontend}/bin/thymis-controller" ]; @@ -103,13 +113,6 @@ }; } ); - nixosModules = { - thymis = ./thymis-nixos-module.nix; - } // nixpkgs.lib.mapAttrs' - (name: value: { - name = "thymis-device-${name}"; - value = value; - }) - (import ./devices.nix { inherit inputs; lib = nixpkgs.lib; }); + nixosModules = nixosModules; }; } diff --git a/frontend/src/lib/TableBodyEditCell.svelte b/frontend/src/lib/TableBodyEditCell.svelte index 4bf21164..63bd0970 100644 --- a/frontend/src/lib/TableBodyEditCell.svelte +++ b/frontend/src/lib/TableBodyEditCell.svelte @@ -4,7 +4,7 @@ import clickOutside from 'svelte-outside-click'; export let value: string; - export let onEnter: (() => void) | null = null; + export let onEnter: ((value: string) => void) | null = null; let isEditing: boolean = false; @@ -15,11 +15,11 @@ onEnter?.()} + on:blur={() => onEnter?.(value)} on:keypress={(e) => { if (e.key === 'Enter') { isEditing = false; - onEnter?.(); + onEnter?.(value); } }} /> diff --git a/frontend/src/lib/state.ts b/frontend/src/lib/state.ts index 9934143c..89233174 100644 --- a/frontend/src/lib/state.ts +++ b/frontend/src/lib/state.ts @@ -42,7 +42,12 @@ export type Device = { tags: string[]; }; +export type Repo = { + url: string; +}; + export type State = { + repositories: { [name: string]: Repo }; devices: Device[]; tags: Tag[]; }; diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 44a0a416..6d31c927 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -9,7 +9,8 @@ "orchestrate": "Verwalten", "devices": "Geräte", "history": "Versionen", - "terminal": "Terminal" + "terminal": "Terminal", + "settings": "Einstellungen" }, "common": { "search": "Suchen...", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 1446baf2..285652ec 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -9,7 +9,8 @@ "orchestrate": "Orchestrate", "devices": "Devices", "history": "History", - "terminal": "Terminal" + "terminal": "Terminal", + "settings": "Settings" }, "common": { "search": "Search...", @@ -184,5 +185,16 @@ } } } + }, + "settings": { + "repo": { + "title": "Repositories", + "name": "Name", + "url": "URL", + "actions": "Actions", + "edit-name": "Edit Name", + "edit-url": "Edit URL", + "delete": "Delete" + } } } diff --git a/frontend/src/routes/Sidebar.svelte b/frontend/src/routes/Sidebar.svelte index 90b59755..3d0f14f4 100644 --- a/frontend/src/routes/Sidebar.svelte +++ b/frontend/src/routes/Sidebar.svelte @@ -23,7 +23,8 @@ SlidersSolid, CodeCommitSolid, TerminalSolid, - ChartSimpleSolid + ChartSimpleSolid, + GearSolid } from 'svelte-awesome-icons'; import DeviceSelect from '$lib/DeviceSelect.svelte'; import { queryParam } from 'sveltekit-search-params'; @@ -103,6 +104,11 @@ icon: TerminalSolid, href: '/terminal', hidden: !device + }, + { + name: $t('nav.settings'), + icon: GearSolid, + href: '/settings' } ]; diff --git a/frontend/src/routes/settings/+page.svelte b/frontend/src/routes/settings/+page.svelte new file mode 100644 index 00000000..e666e85e --- /dev/null +++ b/frontend/src/routes/settings/+page.svelte @@ -0,0 +1,87 @@ + + +{$t('nav.settings')} +{$t('settings.repo.title')} + + + {$t('settings.repo.name')} + {$t('settings.repo.url')} + {$t('settings.repo.actions')} + + + {#each Object.entries(data.state.repositories) as [name, repo]} + + changeRepoName(name, newName)} /> + saveState(data.state)} /> + +
+ +
+
+
+ {/each} +
+
+ diff --git a/thymis-nixos-module.nix b/thymis-nixos-module.nix index a1623031..4739f579 100644 --- a/thymis-nixos-module.nix +++ b/thymis-nixos-module.nix @@ -9,7 +9,7 @@ in { imports = [ - inputs.home-manager.nixosModules.default + inputs.thymis.inputs.home-manager.nixosModules.default "${modulesPath}/profiles/base.nix" ]; options = {