keepbook: install dioxus desktop app

This commit is contained in:
2026-05-05 22:58:35 -07:00
parent fa28f4c433
commit def5b968e2
3 changed files with 383 additions and 359 deletions

18
nixos/flake.lock generated
View File

@@ -278,11 +278,11 @@
"rust-analyzer-src": "rust-analyzer-src_2" "rust-analyzer-src": "rust-analyzer-src_2"
}, },
"locked": { "locked": {
"lastModified": 1769842381, "lastModified": 1777708550,
"narHash": "sha256-0dPzo1ElvAIZ0RwEwx5FfqAUiFj22K9QJOU9stiMCrw=", "narHash": "sha256-Qif3UXT0l5OQq8H9pRWt4/ia4gF48MWK2oHKL8uVx8U=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "b2344f384a82db1410ab09769eb8c4a820de667f", "rev": "74c1591efaff494756b8d35ebe357c6c2bbdca96",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1217,11 +1217,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1777742447, "lastModified": 1778046887,
"narHash": "sha256-NXU/DH7YmgJ8C3vdcQqxP1TfI9vBeJiN46pAp/OuaCg=", "narHash": "sha256-np9C++JA/OgdiPBIkLwRmpEGS8YKDzxs6hy2dn5buPw=",
"owner": "colonelpanic8", "owner": "colonelpanic8",
"repo": "keepbook", "repo": "keepbook",
"rev": "f5ae6de3d4145410df90ffb291b297cf12ad1067", "rev": "8cf913fd43270da40034a90fe81019b39cba76da",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1838,11 +1838,11 @@
"rust-analyzer-src_2": { "rust-analyzer-src_2": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1769786006, "lastModified": 1777639980,
"narHash": "sha256-ax6cH54Nc20QuxlHNC8RMt1P8quMECY4gaACFAdd5ec=", "narHash": "sha256-6d7Hdurvbjc5uwJuc0YiK7rZBGj6Gs3uzfBFcTs+xCc=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "eb0588812b041ebbf2645555f2a4df3bcd853c6d", "rev": "64cdaeb06f69b6b769a492edd88b022ae88e8ca2",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -245,7 +245,6 @@
url = "github:noctalia-dev/noctalia-shell"; url = "github:noctalia-dev/noctalia-shell";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
}; };
outputs = inputs @ { outputs = inputs @ {
@@ -266,10 +265,10 @@
... ...
}: let }: let
# Nixpkgs PR patches - just specify PR number and hash # Nixpkgs PR patches - just specify PR number and hash
nixpkgsPRPatches = [ ]; nixpkgsPRPatches = [];
# Custom patches that don't fit the PR template # Custom patches that don't fit the PR template
nixpkgsCustomPatches = [ ]; nixpkgsCustomPatches = [];
# Home-manager PR patches - just specify PR number and hash # Home-manager PR patches - just specify PR number and hash
homeManagerPRPatches = [ homeManagerPRPatches = [
@@ -328,7 +327,7 @@
builtins.listToAttrs (map mkConfigurationParams machineFilenames); builtins.listToAttrs (map mkConfigurationParams machineFilenames);
# Build org-agenda-api container for a given system # Build org-agenda-api container for a given system
mkOrgAgendaApiContainerInfo = system: let mkOrgAgendaApiContainerInfo = system: let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs {inherit system;};
orgApiRev = builtins.substring 0 7 (org-agenda-api.rev or "unknown"); orgApiRev = builtins.substring 0 7 (org-agenda-api.rev or "unknown");
dotfilesRev = builtins.substring 0 7 (self.rev or self.dirtyRev or "dirty"); dotfilesRev = builtins.substring 0 7 (self.rev or self.dirtyRev or "dirty");
dotfilesOrgApi = import ./org-agenda-api.nix { dotfilesOrgApi = import ./org-agenda-api.nix {
@@ -402,15 +401,21 @@
then home-manager.nixosModules.home-manager then home-manager.nixosModules.home-manager
else import "${patchedHomeManagerSource}/nixos"; else import "${patchedHomeManagerSource}/nixos";
# Create a modified inputs with patched home-manager # Create a modified inputs with patched home-manager
patchedInputs = inputs // { patchedInputs =
home-manager = inputs.home-manager // { inputs
nixosModules = inputs.home-manager.nixosModules // { // {
home-manager = patchedHomeManagerModule; home-manager =
}; inputs.home-manager
# Also provide the patched source path for any direct imports // {
outPath = patchedHomeManagerSource.outPath or "${patchedHomeManagerSource}"; nixosModules =
inputs.home-manager.nixosModules
// {
home-manager = patchedHomeManagerModule;
};
# Also provide the patched source path for any direct imports
outPath = patchedHomeManagerSource.outPath or "${patchedHomeManagerSource}";
};
}; };
};
in in
evalConfig { evalConfig {
inherit system; inherit system;
@@ -435,262 +440,268 @@
} }
// specialArgs; // specialArgs;
}; };
in { in
nixConfig = { {
substituters = [ nixConfig = {
"https://cache.nixos.org/" substituters = [
]; "https://cache.nixos.org/"
trusted-public-keys = [ ];
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" trusted-public-keys = [
]; "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
extra-substituters = [ ];
"http://192.168.1.26:5050" extra-substituters = [
"https://ai.cachix.org" "http://192.168.1.26:5050"
"https://cache.nixos-cuda.org" "https://ai.cachix.org"
"https://nix-community.cachix.org" "https://cache.nixos-cuda.org"
"https://cuda-maintainers.cachix.org" "https://nix-community.cachix.org"
"https://numtide.cachix.org" "https://cuda-maintainers.cachix.org"
"https://cache.flox.dev" "https://numtide.cachix.org"
"https://org-agenda-api.cachix.org" "https://cache.flox.dev"
"https://colonelpanic8-dotfiles.cachix.org" "https://org-agenda-api.cachix.org"
"https://codex-cli.cachix.org" "https://colonelpanic8-dotfiles.cachix.org"
"https://claude-code.cachix.org" "https://codex-cli.cachix.org"
"https://noctalia.cachix.org" "https://claude-code.cachix.org"
]; "https://noctalia.cachix.org"
extra-trusted-substituters = [ ];
"https://ai.cachix.org" extra-trusted-substituters = [
"https://cache.nixos.org/" "https://ai.cachix.org"
"https://nix-community.cachix.org" "https://cache.nixos.org/"
"https://cache.nixos-cuda.org" "https://nix-community.cachix.org"
"https://cuda-maintainers.cachix.org" "https://cache.nixos-cuda.org"
"https://numtide.cachix.org" "https://cuda-maintainers.cachix.org"
]; "https://numtide.cachix.org"
extra-trusted-public-keys = [ ];
"1896Folsom.duckdns.org:U2FTjvP95qwAJo0oGpvmUChJCgi5zQoG1YisoI08Qoo=" extra-trusted-public-keys = [
"ai.cachix.org-1:N9dzRK+alWwoKXQlnn0H6aUx0lU/mspIoz8hMvGvbbc=" "1896Folsom.duckdns.org:U2FTjvP95qwAJo0oGpvmUChJCgi5zQoG1YisoI08Qoo="
"cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M=" "ai.cachix.org-1:N9dzRK+alWwoKXQlnn0H6aUx0lU/mspIoz8hMvGvbbc="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" "cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M="
"cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E=" "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"numtide.cachix.org-1:2ps1kLBUWjxIneOy1Ik6cQjb41X0iXVXeHigGmycPPE=" "cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E="
"flox-cache-public-1:7F4OyH7ZCnFhcze3fJdfyXYLQw/aV7GEed86nQ7IsOs=" "numtide.cachix.org-1:2ps1kLBUWjxIneOy1Ik6cQjb41X0iXVXeHigGmycPPE="
"org-agenda-api.cachix.org-1:liKFemKkOLV/rJt2txDNcpDjRsqLuBneBjkSw/UVXKA=" "flox-cache-public-1:7F4OyH7ZCnFhcze3fJdfyXYLQw/aV7GEed86nQ7IsOs="
"colonelpanic8-dotfiles.cachix.org-1:O6GF3nptpeMFapX29okzO92eSWXR36zqW6ZF2C8P0eQ=" "org-agenda-api.cachix.org-1:liKFemKkOLV/rJt2txDNcpDjRsqLuBneBjkSw/UVXKA="
"codex-cli.cachix.org-1:1Br3H1hHoRYG22n//cGKJOk3cQXgYobUel6O8DgSing=" "colonelpanic8-dotfiles.cachix.org-1:O6GF3nptpeMFapX29okzO92eSWXR36zqW6ZF2C8P0eQ="
"claude-code.cachix.org-1:YeXf2aNu7UTX8Vwrze0za1WEDS+4DuI2kVeWEE4fsRk=" "codex-cli.cachix.org-1:1Br3H1hHoRYG22n//cGKJOk3cQXgYobUel6O8DgSing="
"noctalia.cachix.org-1:pCOR47nnMEo5thcxNDtzWpOxNFQsBRglJzxWPp3dkU4=" "claude-code.cachix.org-1:YeXf2aNu7UTX8Vwrze0za1WEDS+4DuI2kVeWEE4fsRk="
]; "noctalia.cachix.org-1:pCOR47nnMEo5thcxNDtzWpOxNFQsBRglJzxWPp3dkU4="
};
nixosConfigurations =
builtins.mapAttrs (
machineName: params: let
machineParams =
if builtins.hasAttr machineName customParams
then (builtins.getAttr machineName customParams)
else {};
in
mkConfig (params // machineParams)
)
defaultConfigurationParams;
} // flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
lib = pkgs.lib;
# Get short revs for tagging
orgApiRev = builtins.substring 0 7 (org-agenda-api.rev or "unknown");
dotfilesRev = builtins.substring 0 7 (self.rev or self.dirtyRev or "dirty");
# Get tangled config files from org-agenda-api.nix
dotfilesOrgApi = import ./org-agenda-api.nix {
inherit pkgs system;
inherit inputs;
};
tangledConfig = dotfilesOrgApi.org-agenda-custom-config;
# Import container build logic
containerLib = import ../org-agenda-api/container.nix {
inherit pkgs system tangledConfig org-agenda-api orgApiRev dotfilesRev;
};
in {
formatter = pkgs.alejandra;
packages = {
colonelpanic-org-agenda-api = containerLib.containers.colonelpanic;
kat-org-agenda-api = containerLib.containers.kat;
} // lib.optionalAttrs pkgs.stdenv.isLinux {
hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack;
hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo;
hyprwinview = inputs.hyprwinview.packages.${system}.hyprwinview;
hypr-workspace-history = inputs.hypr-workspace-history.packages.${system}.hypr-workspace-history;
};
checks = lib.optionalAttrs pkgs.stdenv.isLinux {
hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack;
hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo;
hyprwinview = inputs.hyprwinview.packages.${system}.hyprwinview;
hypr-workspace-history = inputs.hypr-workspace-history.packages.${system}.hypr-workspace-history;
hyprland-config-syntax = pkgs.runCommand "hyprland-config-syntax" {
nativeBuildInputs = [ pkgs.lua5_4 ];
} ''
cp ${../dotfiles/config/hypr/hyprland.lua} hyprland.lua
luac -p hyprland.lua
if grep -n 'hyprctl' hyprland.lua | grep -v 'hyprctl reload' | grep -v 'hyprctl eval' | grep -v 'hyprctl_eval' | grep -v 'hyprctl -j monitors'; then
echo "hyprland.lua should not shell out to hyprctl for window/workspace manipulation" >&2
exit 1
fi
lua <<'LUA'
local callbacks = {}
local function noop() end
local function dispatcher_proxy()
local proxy = {}
return setmetatable(proxy, {
__index = function()
return dispatcher_proxy()
end,
__call = function()
return noop
end,
})
end
local notification = {
is_alive = function()
return true
end,
set_text = noop,
set_timeout = noop,
pause = noop,
resume = noop,
set_paused = noop,
dismiss = noop,
}
local monitor = {
id = 1,
name = "stub-monitor",
focused = true,
}
local workspace = {
id = 1,
name = "1",
windows = 0,
special = false,
monitor = monitor,
}
monitor.active_workspace = workspace
hl = {
animation = noop,
bind = noop,
config = noop,
curve = noop,
env = noop,
exec_cmd = noop,
define_submap = function(_, reset_or_callback, callback)
local cb = type(reset_or_callback) == "function" and reset_or_callback or callback
if cb then
cb()
end
end,
monitor = noop,
workspace_rule = noop,
window_rule = noop,
dsp = dispatcher_proxy(),
notification = {
create = function()
return notification
end,
},
plugin = {
load = noop,
},
get_active_workspace = function()
return workspace
end,
get_active_monitor = function()
return monitor
end,
get_active_window = function()
return nil
end,
get_monitor = function()
return monitor
end,
get_workspace = function(id)
if tostring(id) == "1" then
return workspace
end
return nil
end,
get_windows = function()
return {}
end,
get_workspace_windows = function()
return {}
end,
on = function(_, callback)
callbacks[#callbacks + 1] = callback
end,
timer = function(callback)
callback()
return {
set_enabled = noop,
}
end,
}
dofile("./hyprland.lua")
for _, callback in ipairs(callbacks) do
callback()
end
LUA
touch "$out"
'';
hyprland-verify-config = let
hyprlandPackage = inputs.hyprland.packages.${system}.hyprland;
hyprNStackPackage = inputs.hyprNStack.packages.${system}.hyprNStack;
in pkgs.runCommand "hyprland-lua-verify-config" {} ''
cp ${../dotfiles/config/hypr/hyprland.lua} hyprland.lua
substituteInPlace hyprland.lua \
--replace-fail /run/current-system/sw/lib/libhyprNStack.so \
${hyprNStackPackage}/lib/libhyprNStack.so
export XDG_RUNTIME_DIR="$TMPDIR/runtime"
mkdir -p "$XDG_RUNTIME_DIR"
HYPRLAND_NO_CRASHREPORTER=1 ${pkgs.coreutils}/bin/timeout 20s \
${hyprlandPackage}/bin/Hyprland --verify-config --config "$PWD/hyprland.lua"
touch "$out"
'';
};
# Dev shell for org-agenda-api deployment
devShells.org-agenda-api = pkgs.mkShell {
buildInputs = [
pkgs.flyctl
agenix.packages.${system}.default
pkgs.age
pkgs.ssh-to-age
pkgs.git
pkgs.jq
pkgs.just
pkgs.curl
]; ];
shellHook = ''
echo ""
echo "org-agenda-api deployment shell"
echo ""
echo "Commands:"
echo " just --list - Show available API commands"
echo " ./deploy.sh <instance> - Deploy to Fly.io (colonelpanic or kat)"
echo " flyctl - Fly.io CLI"
echo " agenix -e <file> - Edit encrypted secrets"
echo ""
'';
}; };
nixosConfigurations =
builtins.mapAttrs (
machineName: params: let
machineParams =
if builtins.hasAttr machineName customParams
then (builtins.getAttr machineName customParams)
else {};
in
mkConfig (params // machineParams)
)
defaultConfigurationParams;
} }
); // flake-utils.lib.eachDefaultSystem (
system: let
pkgs = import nixpkgs {inherit system;};
lib = pkgs.lib;
# Get short revs for tagging
orgApiRev = builtins.substring 0 7 (org-agenda-api.rev or "unknown");
dotfilesRev = builtins.substring 0 7 (self.rev or self.dirtyRev or "dirty");
# Get tangled config files from org-agenda-api.nix
dotfilesOrgApi = import ./org-agenda-api.nix {
inherit pkgs system;
inherit inputs;
};
tangledConfig = dotfilesOrgApi.org-agenda-custom-config;
# Import container build logic
containerLib = import ../org-agenda-api/container.nix {
inherit pkgs system tangledConfig org-agenda-api orgApiRev dotfilesRev;
};
in {
formatter = pkgs.alejandra;
packages =
{
colonelpanic-org-agenda-api = containerLib.containers.colonelpanic;
kat-org-agenda-api = containerLib.containers.kat;
}
// lib.optionalAttrs pkgs.stdenv.isLinux {
hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack;
hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo;
hyprwinview = inputs.hyprwinview.packages.${system}.hyprwinview;
hypr-workspace-history = inputs.hypr-workspace-history.packages.${system}.hypr-workspace-history;
};
checks = lib.optionalAttrs pkgs.stdenv.isLinux {
hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack;
hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo;
hyprwinview = inputs.hyprwinview.packages.${system}.hyprwinview;
hypr-workspace-history = inputs.hypr-workspace-history.packages.${system}.hypr-workspace-history;
hyprland-config-syntax =
pkgs.runCommand "hyprland-config-syntax" {
nativeBuildInputs = [pkgs.lua5_4];
} ''
cp ${../dotfiles/config/hypr/hyprland.lua} hyprland.lua
luac -p hyprland.lua
if grep -n 'hyprctl' hyprland.lua | grep -v 'hyprctl reload' | grep -v 'hyprctl eval' | grep -v 'hyprctl_eval' | grep -v 'hyprctl -j monitors'; then
echo "hyprland.lua should not shell out to hyprctl for window/workspace manipulation" >&2
exit 1
fi
lua <<'LUA'
local callbacks = {}
local function noop() end
local function dispatcher_proxy()
local proxy = {}
return setmetatable(proxy, {
__index = function()
return dispatcher_proxy()
end,
__call = function()
return noop
end,
})
end
local notification = {
is_alive = function()
return true
end,
set_text = noop,
set_timeout = noop,
pause = noop,
resume = noop,
set_paused = noop,
dismiss = noop,
}
local monitor = {
id = 1,
name = "stub-monitor",
focused = true,
}
local workspace = {
id = 1,
name = "1",
windows = 0,
special = false,
monitor = monitor,
}
monitor.active_workspace = workspace
hl = {
animation = noop,
bind = noop,
config = noop,
curve = noop,
env = noop,
exec_cmd = noop,
define_submap = function(_, reset_or_callback, callback)
local cb = type(reset_or_callback) == "function" and reset_or_callback or callback
if cb then
cb()
end
end,
monitor = noop,
workspace_rule = noop,
window_rule = noop,
dsp = dispatcher_proxy(),
notification = {
create = function()
return notification
end,
},
plugin = {
load = noop,
},
get_active_workspace = function()
return workspace
end,
get_active_monitor = function()
return monitor
end,
get_active_window = function()
return nil
end,
get_monitor = function()
return monitor
end,
get_workspace = function(id)
if tostring(id) == "1" then
return workspace
end
return nil
end,
get_windows = function()
return {}
end,
get_workspace_windows = function()
return {}
end,
on = function(_, callback)
callbacks[#callbacks + 1] = callback
end,
timer = function(callback)
callback()
return {
set_enabled = noop,
}
end,
}
dofile("./hyprland.lua")
for _, callback in ipairs(callbacks) do
callback()
end
LUA
touch "$out"
'';
hyprland-verify-config = let
hyprlandPackage = inputs.hyprland.packages.${system}.hyprland;
hyprNStackPackage = inputs.hyprNStack.packages.${system}.hyprNStack;
in
pkgs.runCommand "hyprland-lua-verify-config" {} ''
cp ${../dotfiles/config/hypr/hyprland.lua} hyprland.lua
substituteInPlace hyprland.lua \
--replace-fail /run/current-system/sw/lib/libhyprNStack.so \
${hyprNStackPackage}/lib/libhyprNStack.so
export XDG_RUNTIME_DIR="$TMPDIR/runtime"
mkdir -p "$XDG_RUNTIME_DIR"
HYPRLAND_NO_CRASHREPORTER=1 ${pkgs.coreutils}/bin/timeout 20s \
${hyprlandPackage}/bin/Hyprland --verify-config --config "$PWD/hyprland.lua"
touch "$out"
'';
};
# Dev shell for org-agenda-api deployment
devShells.org-agenda-api = pkgs.mkShell {
buildInputs = [
pkgs.flyctl
agenix.packages.${system}.default
pkgs.age
pkgs.ssh-to-age
pkgs.git
pkgs.jq
pkgs.just
pkgs.curl
];
shellHook = ''
echo ""
echo "org-agenda-api deployment shell"
echo ""
echo "Commands:"
echo " just --list - Show available API commands"
echo " ./deploy.sh <instance> - Deploy to Fly.io (colonelpanic or kat)"
echo " flyctl - Fly.io CLI"
echo " agenix -e <file> - Edit encrypted secrets"
echo ""
'';
};
}
);
} }

View File

@@ -1,116 +1,129 @@
{ config, lib, pkgs, inputs, makeEnable, ... }: {
let config,
lib,
pkgs,
inputs,
makeEnable,
...
}: let
cfg = config.myModules."keepbook-sync"; cfg = config.myModules."keepbook-sync";
keepbookTray = keepbookPackages = inputs.keepbook.packages.${pkgs.stdenv.hostPlatform.system};
inputs.keepbook.packages.${pkgs.stdenv.hostPlatform.system}.keepbook-tray.overrideAttrs (_: { keepbookTray = keepbookPackages.keepbook-tray.overrideAttrs (_: {
# Upstream currently includes a contract test that expects a built TS CLI # Upstream currently includes a contract test that expects a built TS CLI
# entrypoint under ts/dist/, but the Nix build does not build the TS # entrypoint under ts/dist/, but the Nix build does not build the TS
# artifacts first. Skip checks to keep the package usable on NixOS. # artifacts first. Skip checks to keep the package usable on NixOS.
doCheck = false; doCheck = false;
}); });
keepbookDioxusDesktopPackages =
lib.optional (keepbookPackages ? keepbook-dioxus-desktop)
keepbookPackages.keepbook-dioxus-desktop;
daemonArgs = [ daemonArgs =
"--config" cfg.configPath [
"--interval" cfg.interval "--config"
"--jitter" cfg.jitter cfg.configPath
] "--interval"
++ lib.optionals (cfg.historyPoints != null) [ "--history-points" (toString cfg.historyPoints) ] cfg.interval
++ lib.optionals (!cfg.syncOnStart) [ "--no-sync-on-start" ] "--jitter"
++ lib.optionals (!cfg.syncPrices) [ "--no-sync-prices" ] cfg.jitter
++ lib.optionals (!cfg.syncSymlinks) [ "--no-sync-symlinks" ] ]
++ lib.optionals (cfg.balanceStaleness != null) [ "--balance-staleness" cfg.balanceStaleness ] ++ lib.optionals (cfg.historyPoints != null) ["--history-points" (toString cfg.historyPoints)]
++ lib.optionals (cfg.priceStaleness != null) [ "--price-staleness" cfg.priceStaleness ]; ++ lib.optionals (!cfg.syncOnStart) ["--no-sync-on-start"]
++ lib.optionals (!cfg.syncPrices) ["--no-sync-prices"]
++ lib.optionals (!cfg.syncSymlinks) ["--no-sync-symlinks"]
++ lib.optionals (cfg.balanceStaleness != null) ["--balance-staleness" cfg.balanceStaleness]
++ lib.optionals (cfg.priceStaleness != null) ["--price-staleness" cfg.priceStaleness];
daemonExec = lib.escapeShellArgs ([ "${keepbookTray}/bin/keepbook-sync-daemon" ] ++ daemonArgs); daemonExec = lib.escapeShellArgs (["${keepbookTray}/bin/keepbook-sync-daemon"] ++ daemonArgs);
enabledModule = makeEnable config "myModules.keepbook-sync" false { enabledModule = makeEnable config "myModules.keepbook-sync" false {
environment.systemPackages = [ keepbookTray ]; environment.systemPackages = [keepbookTray] ++ keepbookDioxusDesktopPackages;
home-manager.users.${cfg.user} = { home-manager.users.${cfg.user} = {
systemd.user.services.keepbook-sync-daemon = { systemd.user.services.keepbook-sync-daemon = {
Unit = { Unit = {
Description = "keepbook sync daemon"; Description = "keepbook sync daemon";
After = [ "graphical-session.target" "tray.target" ]; After = ["graphical-session.target" "tray.target"];
PartOf = [ "graphical-session.target" ]; PartOf = ["graphical-session.target"];
Requires = [ "tray.target" ]; Requires = ["tray.target"];
}; };
Service = { Service = {
ExecStart = daemonExec; ExecStart = daemonExec;
Restart = "always"; Restart = "always";
RestartSec = 5; RestartSec = 5;
Environment = [ "RUST_LOG=info" ]; Environment = ["RUST_LOG=info"];
}; };
Install = { Install = {
WantedBy = [ "graphical-session.target" ]; WantedBy = ["graphical-session.target"];
}; };
}; };
}; };
}; };
in in
enabledModule // { enabledModule
# Merge our extra options with the enable option produced by makeEnable. // {
options = lib.recursiveUpdate enabledModule.options { # Merge our extra options with the enable option produced by makeEnable.
myModules."keepbook-sync" = { options = lib.recursiveUpdate enabledModule.options {
user = lib.mkOption { myModules."keepbook-sync" = {
type = lib.types.str; user = lib.mkOption {
default = "imalison"; type = lib.types.str;
description = "User account to run the keepbook sync daemon."; default = "imalison";
}; description = "User account to run the keepbook sync daemon.";
};
configPath = lib.mkOption { configPath = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "/home/imalison/.local/share/keepbook/keepbook.toml"; default = "/home/imalison/.local/share/keepbook/keepbook.toml";
description = "Path to keepbook.toml used by the daemon."; description = "Path to keepbook.toml used by the daemon.";
}; };
interval = lib.mkOption { interval = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "30m"; default = "30m";
description = "Base sync interval for keepbook-sync-daemon (e.g. 30m, 1h)."; description = "Base sync interval for keepbook-sync-daemon (e.g. 30m, 1h).";
}; };
jitter = lib.mkOption { jitter = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "5m"; default = "5m";
description = "Random jitter applied around each scheduled interval."; description = "Random jitter applied around each scheduled interval.";
}; };
balanceStaleness = lib.mkOption { balanceStaleness = lib.mkOption {
type = lib.types.nullOr lib.types.str; type = lib.types.nullOr lib.types.str;
default = null; default = null;
description = "Optional override for balance staleness threshold."; description = "Optional override for balance staleness threshold.";
}; };
priceStaleness = lib.mkOption { priceStaleness = lib.mkOption {
type = lib.types.nullOr lib.types.str; type = lib.types.nullOr lib.types.str;
default = null; default = null;
description = "Optional override for price staleness threshold."; description = "Optional override for price staleness threshold.";
}; };
syncOnStart = lib.mkOption { syncOnStart = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
description = "Run a sync cycle immediately when the daemon starts."; description = "Run a sync cycle immediately when the daemon starts.";
}; };
syncPrices = lib.mkOption { syncPrices = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
description = "Enable periodic price refresh during sync cycles."; description = "Enable periodic price refresh during sync cycles.";
}; };
syncSymlinks = lib.mkOption { syncSymlinks = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
description = "Enable periodic symlink rebuild during sync cycles."; description = "Enable periodic symlink rebuild during sync cycles.";
}; };
historyPoints = lib.mkOption { historyPoints = lib.mkOption {
type = lib.types.nullOr lib.types.int; type = lib.types.nullOr lib.types.int;
default = null; default = null;
description = "Optional override for the maximum recent portfolio history rows shown in the tray menu."; description = "Optional override for the maximum recent portfolio history rows shown in the tray menu.";
};
}; };
}; };
}; }
}