refactor rice into config
This commit is contained in:
parent
8872a12d20
commit
818af30329
64 changed files with 229 additions and 230 deletions
260
graphical/webapps/firefox-webapp.nix
Normal file
260
graphical/webapps/firefox-webapp.nix
Normal file
|
@ -0,0 +1,260 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (builtins) getAttr stringLength substring;
|
||||
inherit (lib)
|
||||
mkOption
|
||||
getExe
|
||||
listToAttrs
|
||||
attrsToList
|
||||
imap
|
||||
;
|
||||
inherit (lib.attrsets)
|
||||
mapAttrs
|
||||
mapAttrs'
|
||||
nameValuePair
|
||||
;
|
||||
inherit (lib.strings) concatStringsSep toUpper;
|
||||
|
||||
enumerate =
|
||||
a:
|
||||
listToAttrs (
|
||||
imap (
|
||||
id:
|
||||
{
|
||||
name,
|
||||
value,
|
||||
}:
|
||||
{
|
||||
inherit name;
|
||||
value = value // {
|
||||
inherit id;
|
||||
};
|
||||
}
|
||||
) (attrsToList a)
|
||||
);
|
||||
make-app-profiles =
|
||||
cfg:
|
||||
mapAttrs' (
|
||||
name: cfg:
|
||||
nameValuePair "home-manager-webapp-${name}" {
|
||||
inherit (cfg) id;
|
||||
userChrome = ''
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
browser {
|
||||
margin-right: 0px; margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#TabsToolbar {
|
||||
visibility: collapse !important;
|
||||
}
|
||||
|
||||
#nav-bar {
|
||||
margin-top: 0;
|
||||
margin-bottom: -42px;
|
||||
z-index: -100;
|
||||
}
|
||||
|
||||
#main-window[windowtype="navigator:browser"] {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.tab-background[selected="true"] {
|
||||
background: ${cfg.backgroundColor} !important;
|
||||
}
|
||||
'';
|
||||
|
||||
settings = cfg.extraSettings // {
|
||||
"browser.startup.homepage" = builtins.toString cfg.url;
|
||||
"browser.sessionstore.resume_session_once" = false;
|
||||
"browser.sessionstore.resume_from_crash" = false;
|
||||
"browser.cache.disk.enable" = false;
|
||||
"browser.cache.disk.capacity" = 0;
|
||||
"browser.cache.disk.filesystem_reported" = 1;
|
||||
"browser.cache.disk.smart_size.enabled" = false;
|
||||
"browser.cache.disk.smart_size.first_run" = false;
|
||||
"browser.cache.disk.smart_size.use_old_max" = false;
|
||||
"browser.ctrlTab.previews" = true;
|
||||
"browser.tabs.warnOnClose" = false;
|
||||
"plugin.state.flash" = 2;
|
||||
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
|
||||
"browser.tabs.drawInTitlebar" = false;
|
||||
"browser.tabs.inTitlebar" = 0;
|
||||
"browser.contentblocking.category" = "strict";
|
||||
"network.cookie.lifetimePolicy" = 0;
|
||||
"layout.css.prefers-color-scheme.content-override" = getAttr cfg.theme {
|
||||
dark = 0;
|
||||
light = 1;
|
||||
system = 2;
|
||||
};
|
||||
};
|
||||
}
|
||||
) cfg;
|
||||
in
|
||||
{
|
||||
config.hm.options.programs.firefox.webapps = mkOption {
|
||||
default = { };
|
||||
|
||||
type =
|
||||
with lib.types;
|
||||
attrsOf (submodule {
|
||||
options = {
|
||||
####################
|
||||
# Firefox settings #
|
||||
####################
|
||||
url = mkOption {
|
||||
type = str;
|
||||
description = "The URL of the webapp to launch.";
|
||||
};
|
||||
|
||||
# id = mkOption {
|
||||
# type = int;
|
||||
# description = "The Firefox profile ID to set.";
|
||||
# };
|
||||
|
||||
hidden = mkOption {
|
||||
type = bool;
|
||||
description = "Hide this webapp from the list of applications (but still generate a .desktop file).";
|
||||
default = false;
|
||||
};
|
||||
|
||||
extraArgs = mkOption {
|
||||
type = listOf str;
|
||||
default = [ ];
|
||||
description = "Extra args to launch Firefox with.";
|
||||
};
|
||||
|
||||
extraSettings = mkOption {
|
||||
type = attrsOf (either bool (either int str));
|
||||
default = { };
|
||||
description = "Additional Firefox profile settings.";
|
||||
};
|
||||
|
||||
backgroundColor = mkOption {
|
||||
type = str;
|
||||
default = "rgba(0, 0, 0, 0)";
|
||||
description = "The background color to use for loading pages.";
|
||||
};
|
||||
|
||||
theme = mkOption {
|
||||
type = enum [
|
||||
"dark"
|
||||
"light"
|
||||
"system"
|
||||
];
|
||||
default = "system";
|
||||
description = "The application CSS theme to use, if supported.";
|
||||
};
|
||||
|
||||
#########################
|
||||
# Desktop file settings #
|
||||
#########################
|
||||
|
||||
# Copied from xdg.desktopEntries, with slight modification for default settings
|
||||
name = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = "Specific name of the application. Defaults to the capitalized attribute name.";
|
||||
};
|
||||
|
||||
mimeType = mkOption {
|
||||
description = "The MIME type(s) supported by this application.";
|
||||
type = nullOr (listOf str);
|
||||
default = [
|
||||
"text/html"
|
||||
"text/xml"
|
||||
"application/xhtml_xml"
|
||||
];
|
||||
};
|
||||
|
||||
# Copied verbatim from xdg.desktopEntries.
|
||||
genericName = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = "Generic name of the application.";
|
||||
};
|
||||
|
||||
comment = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = "Tooltip for the entry.";
|
||||
};
|
||||
|
||||
categories = mkOption {
|
||||
type = nullOr (listOf str);
|
||||
default = null;
|
||||
description = "Categories in which the entry should be shown in a menu.";
|
||||
};
|
||||
|
||||
icon = mkOption {
|
||||
type = nullOr (either str path);
|
||||
default = null;
|
||||
description = "Icon to display in file manager, menus, etc.";
|
||||
};
|
||||
|
||||
prefersNonDefaultGPU = mkOption {
|
||||
type = nullOr bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If true, the application prefers to be run on a more
|
||||
powerful discrete GPU if available.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
description = "Websites to create special site-specific Firefox instances for.";
|
||||
};
|
||||
|
||||
config.hm.config = {
|
||||
programs.firefox.profiles = make-app-profiles (enumerate config.hm.programs.firefox.webapps);
|
||||
|
||||
xdg.desktopEntries = mapAttrs (name: cfg: {
|
||||
inherit (cfg)
|
||||
genericName
|
||||
comment
|
||||
categories
|
||||
icon
|
||||
mimeType
|
||||
prefersNonDefaultGPU
|
||||
;
|
||||
|
||||
name =
|
||||
if cfg.name == null then
|
||||
(toUpper (substring 0 1 name)) + (substring 1 (stringLength name) name)
|
||||
else
|
||||
cfg.name;
|
||||
|
||||
startupNotify = true;
|
||||
terminal = false;
|
||||
type = "Application";
|
||||
|
||||
exec = concatStringsSep " " (
|
||||
[
|
||||
"${getExe config.hm.programs.firefox.package}"
|
||||
"--name"
|
||||
"${name}"
|
||||
"--app-id"
|
||||
"${name}"
|
||||
"--class"
|
||||
"${name}"
|
||||
"-P"
|
||||
"${config.hm.programs.firefox.profiles."home-manager-webapp-${name}".path}"
|
||||
"--no-remote"
|
||||
]
|
||||
++ cfg.extraArgs
|
||||
++ [ "${cfg.url}" ]
|
||||
);
|
||||
|
||||
settings = {
|
||||
X-MultipleArgs = "false"; # Consider enabling, don't know what this does
|
||||
StartupWMClass = "${name}";
|
||||
NoDisplay = lib.boolToString cfg.hidden;
|
||||
};
|
||||
}) config.hm.programs.firefox.webapps;
|
||||
};
|
||||
}
|
252
graphical/webapps/local-webapp.nix
Normal file
252
graphical/webapps/local-webapp.nix
Normal file
|
@ -0,0 +1,252 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
mkForce
|
||||
getExe
|
||||
getExe'
|
||||
listToAttrs
|
||||
flatten
|
||||
mapAttrsToList
|
||||
mapAttrs
|
||||
mapAttrs'
|
||||
nameValuePair
|
||||
toLower
|
||||
replaceStrings
|
||||
concatMapStringsSep
|
||||
;
|
||||
partOf = cfg: "${replaceStrings [ " " ] [ "-" ] (toLower cfg.name)}.target";
|
||||
# make a firefox webapp + hidden .desktop entry for the client app
|
||||
make-firefox =
|
||||
cfg:
|
||||
mapAttrs' (
|
||||
name: cfg:
|
||||
nameValuePair "${name}-client" {
|
||||
inherit (cfg) name;
|
||||
url = "http://127.0.0.1:${builtins.toString cfg.port}";
|
||||
extraSettings = config.hm.programs.firefox.profiles.default.settings;
|
||||
hidden = true;
|
||||
}
|
||||
) cfg;
|
||||
# make a systemd service for running the frontend
|
||||
make-systemd-service =
|
||||
cfg:
|
||||
mapAttrs' (
|
||||
name: cfg:
|
||||
if (cfg.service != null) then
|
||||
nameValuePair "${cfg.name}-frontend" {
|
||||
Unit = {
|
||||
Description = "${cfg.name} Frontend";
|
||||
WantedBy = mkForce [ ];
|
||||
};
|
||||
|
||||
Service = cfg.service;
|
||||
}
|
||||
else
|
||||
nameValuePair "" { }
|
||||
) cfg;
|
||||
# modify systemd units to be PartOf this target
|
||||
modify-systemd-services =
|
||||
cfg:
|
||||
listToAttrs (
|
||||
flatten (
|
||||
mapAttrsToList (
|
||||
name: cfg:
|
||||
(map (req: {
|
||||
name = "${req}";
|
||||
value = {
|
||||
Unit = {
|
||||
PartOf = partOf cfg;
|
||||
};
|
||||
};
|
||||
}) cfg.requires.services)
|
||||
) cfg
|
||||
)
|
||||
);
|
||||
modify-quadlets =
|
||||
cfg:
|
||||
listToAttrs (
|
||||
flatten (
|
||||
mapAttrsToList (
|
||||
name: cfg:
|
||||
(map (req: {
|
||||
name = "${req}";
|
||||
value = {
|
||||
extraConfig.Unit.PartOf = partOf cfg;
|
||||
};
|
||||
}) cfg.requires.containers)
|
||||
) cfg
|
||||
)
|
||||
);
|
||||
# make a systemd target to collate dependencies
|
||||
make-systemd-target =
|
||||
cfg:
|
||||
mapAttrs (name: cfg: {
|
||||
Unit = {
|
||||
Description = "${cfg.name} Target";
|
||||
WantedBy = mkForce [ ];
|
||||
Requires =
|
||||
(map (req: req + ".service") cfg.requires.services)
|
||||
++ (map (req: "podman-" + req + ".service") cfg.requires.containers);
|
||||
};
|
||||
}) cfg;
|
||||
# make desktop shortcuts and a script which will handle starting everything
|
||||
make-xdg =
|
||||
cfg:
|
||||
mapAttrs (name: cfg: {
|
||||
inherit (cfg) name icon genericName;
|
||||
type = "Application";
|
||||
exec = "${
|
||||
let
|
||||
notify-send = "${getExe' pkgs.libnotify "notify-send"} -a \"${cfg.name}\"";
|
||||
systemctl = "${getExe' pkgs.systemd "systemctl"}";
|
||||
dex = "${getExe pkgs.dex}";
|
||||
podman = "${getExe pkgs.podman}";
|
||||
makeContainerCheck =
|
||||
container: ''[ "$(${podman} inspect -f {{.State.Health.Status}} ${container})" == "healthy" ]'';
|
||||
# makeContainerCheck = container: ''
|
||||
# [ ${podman} inspect -f {{.State.Status}} ${container})" != "running" ]
|
||||
# '';
|
||||
containerChecks =
|
||||
if (cfg.requires.containers != [ ]) then
|
||||
''
|
||||
container_checks() {
|
||||
if ''
|
||||
+ (concatMapStringsSep " && " makeContainerCheck cfg.requires.containers)
|
||||
+ ''
|
||||
; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
''
|
||||
else
|
||||
''
|
||||
container_checks() {
|
||||
return 0
|
||||
}
|
||||
'';
|
||||
in
|
||||
pkgs.writeShellScript "${name}" ''
|
||||
set -euo pipefail
|
||||
|
||||
exit_error() {
|
||||
${notify-send} -w "Failure" $1
|
||||
exit 1
|
||||
}
|
||||
|
||||
${containerChecks}
|
||||
|
||||
${notify-send} "Launching ${name} backend.." "Please be patient."
|
||||
${systemctl} --user start ${name}.target || exit_error "Failed to launch!"
|
||||
|
||||
checks=0
|
||||
until container_checks; do
|
||||
sleep 2
|
||||
checks=$((checks+1))
|
||||
if [ $((checks%10)) -eq 0 ]; then
|
||||
${notify-send} "Waiting for backend."
|
||||
fi
|
||||
if [ $checks -ge 60 ]; then
|
||||
${systemctl} --no-block --user stop ${name}.target
|
||||
exit_error "Failed to launch!"
|
||||
fi
|
||||
done
|
||||
|
||||
${notify-send} "Launching ${name}.."
|
||||
${dex} -w ~/.nix-profile/share/applications/${name}-client.desktop
|
||||
|
||||
${notify-send} "Goodbye" "Shutting down."
|
||||
${systemctl} --user stop ${name}.target
|
||||
exit 0
|
||||
''
|
||||
}";
|
||||
}) cfg;
|
||||
cfg = config.hm.localWebApps;
|
||||
in
|
||||
{
|
||||
config.hm.options.localWebApps = mkOption {
|
||||
default = { };
|
||||
type =
|
||||
with lib.types;
|
||||
attrsOf (submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = str;
|
||||
description = "Display name of the webapp.";
|
||||
};
|
||||
|
||||
genericName = mkOption {
|
||||
type = nullOr str;
|
||||
description = "Generic name of the webapp.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
icon = mkOption {
|
||||
type = nullOr (either str path);
|
||||
description = "Path to a file to use for application icon.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
requires = mkOption {
|
||||
type = nullOr (submodule {
|
||||
options = {
|
||||
containers = mkOption {
|
||||
type = listOf str;
|
||||
default = [ ];
|
||||
};
|
||||
services = mkOption {
|
||||
type = listOf str;
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
});
|
||||
default = null;
|
||||
description = "Containers or services this app requires.";
|
||||
};
|
||||
|
||||
service = mkOption {
|
||||
type = nullOr (submodule {
|
||||
options = {
|
||||
execStartPre = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
execStart = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
execStop = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
});
|
||||
default = null;
|
||||
description = "Submodule containing exec[StartPre/Start/Stop] commands for any required systemd service";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = int;
|
||||
description = "Local port the webapp should host on.";
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
config.hm.config = {
|
||||
programs.firefox.webapps = make-firefox cfg;
|
||||
|
||||
systemd.user.targets = make-systemd-target cfg;
|
||||
systemd.user.services = (make-systemd-service cfg) // (modify-systemd-services cfg);
|
||||
services.podman.containers = modify-quadlets cfg;
|
||||
|
||||
xdg.desktopEntries = make-xdg cfg;
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue