diff --git a/alt/flake.lock b/alt/flake.lock new file mode 100755 index 0000000..57fc2c7 --- /dev/null +++ b/alt/flake.lock @@ -0,0 +1,296 @@ +{ + "nodes": { + "crane": { + "inputs": { + "nixpkgs": [ + "schizofox", + "searx-randomizer", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1701386725, + "narHash": "sha256-w4aBlMYh9Y8co1V80m5LzEKMijUJ7CBTq209WbqVwUU=", + "owner": "ipetkov", + "repo": "crane", + "rev": "8b9bad9b30bd7a9ed08782e64846b7485f9d0a38", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "schizofox", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1706830856, + "narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1698882062, + "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "hercules-ci-effects": { + "inputs": { + "flake-parts": [ + "schizofox", + "nixpak", + "flake-parts" + ], + "nixpkgs": [ + "schizofox", + "nixpak", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1704029560, + "narHash": "sha256-a4Iu7x1OP+uSYpqadOu8VCPY+MPF3+f6KIi+MAxlgyw=", + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "rev": "d5cbf433a6ae9cae05400189a8dbc6412a03ba16", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712462372, + "narHash": "sha256-WA3bbBWhd3o1wAgyHZNypjb/LG4oq+IWxFq8ey8yNPU=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "a561ad6ab38578c812cc9af3b04f2cc60ebf48c9", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "schizofox", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1708591310, + "narHash": "sha256-8mQGVs8JccWTnORgoLOTh9zvf6Np+x2JzhIc+LDcJ9s=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "0e0e9669547e45ea6cca2de4044c1a384fd0fe55", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "nixpak": { + "inputs": { + "flake-parts": [ + "schizofox", + "flake-parts" + ], + "hercules-ci-effects": "hercules-ci-effects", + "nixpkgs": [ + "schizofox", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1708597894, + "narHash": "sha256-KxpKOBDGPJ76k37vLukYHp/wd7U4DoUVIvy8atHfy/k=", + "owner": "nixpak", + "repo": "nixpak", + "rev": "535dd408c4b19f407bc22e42eb32ccb9256e5865", + "type": "github" + }, + "original": { + "owner": "nixpak", + "repo": "nixpak", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1712439257, + "narHash": "sha256-aSpiNepFOMk9932HOax0XwNxbA38GOUVOiXfUVPOrck=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "ff0dbd94265ac470dda06a657d5fe49de93b4599", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1698611440, + "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1708475490, + "narHash": "sha256-g1v0TsWBQPX97ziznfJdWhgMyMGtoBFs102xSYO4syU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0e74ca98a74bc7270d28838369593635a5db3260", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nur": { + "locked": { + "lastModified": 1712435091, + "narHash": "sha256-Hyn/2goBwkDGxTF6IBcc1HpRscpLg8ErEy+vmQwEqoc=", + "owner": "nix-community", + "repo": "NUR", + "rev": "d47aa79f2aae0bea15c6a40b7fca5830fcfe1346", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "root": { + "inputs": { + "home-manager": "home-manager", + "nixpkgs": "nixpkgs", + "nur": "nur", + "schizofox": "schizofox" + } + }, + "schizofox": { + "inputs": { + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "home-manager": "home-manager_2", + "nixpak": "nixpak", + "nixpkgs": "nixpkgs_2", + "searx-randomizer": "searx-randomizer" + }, + "locked": { + "lastModified": 1710502118, + "narHash": "sha256-kPzvCwGVuLlPDVRD35dMnudWPpEzRXfU/9DHsG12PaY=", + "owner": "schizofox", + "repo": "schizofox", + "rev": "8dde2033a6f448c48a48d4d0aeb22bf2da840b7d", + "type": "github" + }, + "original": { + "owner": "schizofox", + "repo": "schizofox", + "type": "github" + } + }, + "searx-randomizer": { + "inputs": { + "crane": "crane", + "flake-parts": "flake-parts_2", + "nixpkgs": [ + "schizofox", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1704412376, + "narHash": "sha256-Ap/AudJxCYBDWYy0lyqP0/FZYJCibL7jKkoj6hp1WS0=", + "owner": "schizofox", + "repo": "searx-randomizer", + "rev": "c36a473732ba6b4f6024ac1c181631cf4d542b17", + "type": "github" + }, + "original": { + "owner": "schizofox", + "repo": "searx-randomizer", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/alt/flake.nix b/alt/flake.nix new file mode 100755 index 0000000..95e786a --- /dev/null +++ b/alt/flake.nix @@ -0,0 +1,60 @@ +{ + description = "My NixOS configuration"; + + inputs = { + nixpkgs.url= "github:nixos/nixpkgs/nixos-unstable"; + nur.url = "github:nix-community/NUR"; + schizofox.url="github:schizofox/schizofox"; + home-manager = { + url = "github:nix-community/home-manager/"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs @ { self, nixpkgs, nur, home-manager, ...}: + let + inherit (self) outputs; + mkSystem = { + hostname, + modules ? [], + user-configs ? [ { name = "vali"; config = ./home/vali/common.nix; }], + system ? "x86_64-linux" + #overlays ? import -/overlays/packages.nix + }: + let + profile-config = { inherit hostname system modules user-configs; }; + in + nixpkgs.lib.nixosSystem { + inherit modules; + specialArgs = { inherit inputs outputs profile-config; }; + }; + + mkHome = user: modules: pkgs: home-manager.lib.homeManagerConfiguration { + inherit modules pkgs user; + extraSpecialArgs = { inherit inputs outputs user; }; + }; + in { + nixpkgs.config.allowUnfree = true; + nixosConfigurations = { + laptop = mkSystem { + hostname = "nixos"; + modules = [./hosts/laptop]; + user-configs = [{ + name = "vali"; + config = ./home/vali/laptop.nix; + }]; + }; + xfce = mkSystem { + hostname = "nixos"; + modules = [ ./hosts/xfce ]; + user-configs = [{ + name = "vali"; + config = ./home/vali/xfce.nix; + }]; + }; + }; + homeManagerConfiguration = { + "vali@laptop" = mkHome "vali" [ home/vali/laptop.nix ] nixpkgs.legacyPackages."x86_64-linux"; + }; + }; +} diff --git a/alt/home/vali/laptop.nix b/alt/home/vali/laptop.nix new file mode 100755 index 0000000..e9ac02c --- /dev/null +++ b/alt/home/vali/laptop.nix @@ -0,0 +1,27 @@ +{ inputs, outputs, pkgs, user, ... }: + +{ + imports = [ + # Would look like this: + # ../../terminal/zsh/home.nix + inputs.schizofox.homeManagerModule + ../../modules/web/schizofox.nix + #../../modules/terminal/zsh/home.nix + ]; + xdg.configHome = "/home/${user}/.config/"; + programs.home-manager.enable = true; + home = { + stateVersion = "23.11"; + username = "${user}"; + homeDirectory = "/home/${user}"; + }; + + # GNOME settings: + dconf.settings = { + "org/gnome/shell" = { + disable-user-extensions = false; + enabled-extensions = [ "appindicatorsupport@rgcjonas.gmail.com" ]; + }; + "org/gnome/desktop/interface".color-scheme = "prefer-dark"; + }; +} diff --git a/alt/home/vali/xfce.nix b/alt/home/vali/xfce.nix new file mode 100755 index 0000000..814755e --- /dev/null +++ b/alt/home/vali/xfce.nix @@ -0,0 +1,18 @@ +{ inputs, outputs, pkgs, user, ... }: + +{ + imports = [ + # Would look like this: + # ../../terminal/zsh/home.nix + inputs.schizofox.homeManagerModule + ../../modules/web/schizofox.nix + #../../modules/terminal/zsh/home.nix + ]; + xdg.configHome = "/home/${user}/.config/"; + programs.home-manager.enable = true; + home = { + stateVersion = "23.11"; + username = "${user}"; + homeDirectory = "/home/${user}"; + }; +} diff --git a/alt/hosts/common/default.nix b/alt/hosts/common/default.nix new file mode 100755 index 0000000..e65e5ae --- /dev/null +++ b/alt/hosts/common/default.nix @@ -0,0 +1,93 @@ +{ inputs, outputs, profile-config, pkgs, ... }: + +{ + nixpkgs.config.allowUnfree = true; + imports = [ + #profile-config.overlays + inputs.home-manager.nixosModules.home-manager + ./packages.nix + ]; + + services.locate = { + enable = true; + interval = "daily"; + package = pkgs.plocate; + localuser = null; + }; + + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + + home-manager.users = builtins.listToAttrs (builtins.map( + u-conf: { + inherit inputs; + name = u-conf.name; + value = import u-conf.config { inherit pkgs inputs outputs; user = u-conf.name; }; + } + )profile-config.user-configs); + + users.users = builtins.listToAttrs (builtins.map( + u-conf: { + name = u-conf.name; + value = { + initialPassword = "${u-conf.name}"; + isNormalUser = true; + extraGroups = [ "wheel" "audio" "video" "input"]; + }; + } + )profile-config.user-configs); + + boot.loader = { + efi.canTouchEfiVariables = true; + grub = { + enable = true; + efiSupport = true; + device = "nodev"; + }; + }; + + time.timeZone = "Europe/Zurich"; + i18n.defaultLocale = "en_US.UTF-8"; + console.keyMap = "de"; + # Remove unnecessary packages + environment.gnome.excludePackages = + (with pkgs; [ + gnome-photos + gnome-tour + gedit + ]) ++ + (with pkgs.gnome; [ + epiphany + geary + totem + tali + iagno + hitori + atomix + ]); + services.xserver.excludePackages = [ pkgs.xterm ]; + documentation.nixos.enable = false; + # Set the keyboard layout to german + services.xserver.xkb.layout= "de"; + # Eable CUPS + services.printing.enable = true; + # Sound settings + sound.enable = true; + hardware.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + jack.enable = true; + pulse.enable = true; + wireplumber.enable = true; + alsa.support32Bit = true; + }; + services.udev.packages = with pkgs; [ gnome.gnome-settings-daemon ]; + + nix = { + package = pkgs.nixFlakes; + extraOptions = "experimental-features = nix-command flakes"; + }; + system.stateVersion = "23.11"; +} diff --git a/alt/hosts/common/packages.nix b/alt/hosts/common/packages.nix new file mode 100755 index 0000000..512098b --- /dev/null +++ b/alt/hosts/common/packages.nix @@ -0,0 +1,23 @@ +{ inputs, outputs, profile-config, pkgs, ... }: + +{ + environment.systemPackages = with pkgs; [ + vim + neovim + eza + zsh + git + zip + unzip + neofetch + fastfetch + wget + zoxide + python3 + gcc + htop + networkmanager + gnomeExtensions.appindicator + uwufetch + ]; +} diff --git a/alt/hosts/laptop/default.nix b/alt/hosts/laptop/default.nix new file mode 100755 index 0000000..70b2af3 --- /dev/null +++ b/alt/hosts/laptop/default.nix @@ -0,0 +1,13 @@ +{ inputs, outputs, pks, profile-config, ... }: + +{ + imports = [ + ./hardware-configuration.nix + ../common + ./packages.nix + ]; + services.xserver.enable = true; + services.xserver.displayManager.gdm.enable = true; + services.xserver.desktopManager.gnome.enable = true; + security.polkit.enable = true; +} diff --git a/alt/hosts/laptop/hardware-configuration.nix b/alt/hosts/laptop/hardware-configuration.nix new file mode 100755 index 0000000..50ae60d --- /dev/null +++ b/alt/hosts/laptop/hardware-configuration.nix @@ -0,0 +1,39 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/b29322ae-b475-4241-85d5-16b69d3cbdc0"; + fsType = "ext4"; + }; + + boot.initrd.luks.devices."luks-d12a57e8-f071-485c-ab1c-e8f7a7897dfb".device = "/dev/disk/by-uuid/d12a57e8-f071-485c-ab1c-e8f7a7897dfb"; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/33F4-58C3"; + fsType = "vfat"; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp59s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/alt/hosts/laptop/packages.nix b/alt/hosts/laptop/packages.nix new file mode 100755 index 0000000..3aa4de0 --- /dev/null +++ b/alt/hosts/laptop/packages.nix @@ -0,0 +1,28 @@ +{ inputs, outputs, pkgs, profile-config, ... }: + +{ + environment.systemPackages = with pkgs; [ + jetbrains.idea-community + ani-cli + okular + texliveFull + signal-desktop + nextcloud-client + vlc + strawberry + telegram-desktop + thunderbird + betterbird + vesktop + zsh + zoxide + eza + mpv + librewolf + keepassxc + feh + libreoffice + openjdk + gnome.gnome-tweaks + ]; +} diff --git a/alt/hosts/xfce/default.nix b/alt/hosts/xfce/default.nix new file mode 100755 index 0000000..f02b850 --- /dev/null +++ b/alt/hosts/xfce/default.nix @@ -0,0 +1,22 @@ +{ config, pkgs, callPackage, ... }: +{ + imports = [ + ./hardware-configuration.nix + ./packages.nix + ../common + ]; + services.xserver = { + enable = true; + desktopManager = { + xterm.enable = false; + xfce = { + enable = true; + noDesktop = true; + enableXfwm = false; + }; + }; + displayManager.defaultSession = "xfce"; + windowManager.i3.enable = true; + }; + ... +} diff --git a/alt/hosts/xfce/hardware-configuration.nix b/alt/hosts/xfce/hardware-configuration.nix new file mode 100755 index 0000000..50ae60d --- /dev/null +++ b/alt/hosts/xfce/hardware-configuration.nix @@ -0,0 +1,39 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/b29322ae-b475-4241-85d5-16b69d3cbdc0"; + fsType = "ext4"; + }; + + boot.initrd.luks.devices."luks-d12a57e8-f071-485c-ab1c-e8f7a7897dfb".device = "/dev/disk/by-uuid/d12a57e8-f071-485c-ab1c-e8f7a7897dfb"; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/33F4-58C3"; + fsType = "vfat"; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp59s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/alt/hosts/xfce/packages.nix b/alt/hosts/xfce/packages.nix new file mode 100755 index 0000000..4e0c9e1 --- /dev/null +++ b/alt/hosts/xfce/packages.nix @@ -0,0 +1,27 @@ +{ inputs, outputs, pkgs, profile-config, ... }: + +{ + environment.systemPackages = with pkgs; [ + jetbrains.idea-community + ani-cli + okular + texliveFull + signal-desktop + nextcloud-client + vlc + strawberry + telegram-desktop + betterbird + vesktop + zsh + zoxide + eza + mpv + librewolf + keepassxc + feh + libreoffice + openjdk + + ]; +} diff --git a/alt/modules/terminal/zsh/home.nix b/alt/modules/terminal/zsh/home.nix new file mode 100755 index 0000000..accc345 --- /dev/null +++ b/alt/modules/terminal/zsh/home.nix @@ -0,0 +1,31 @@ +{ pkgs, config, ... } + +{ + programs.zsh = { + enable = true; + enableCompletion = true; + enableAutoSuggestions = true; + + shellAliases = { + c = "clear"; + cc = "cd && clear"; + la = "eza -lah"; + ls = "eza" + update = "sudo nixos-rebuild switch --flake '/home/vali/.flake/'#laptop"; + nv = "nvim"; + sunv = "sudo nvim"; + }; + history.size = 10000; + history.path = "${config.xdg.dataHome}/zsh/history"; + + oh-my-zsh = { + enable = true; + plugins = [ "git" "thefuck" ]; + }; + home.packages = with pkgs; [ thefuck ]; + programs.zoxide = { + enable = true; + enableZshIntegration = true; + } + } +} diff --git a/alt/modules/web/schizofox.nix b/alt/modules/web/schizofox.nix new file mode 100755 index 0000000..b86f330 --- /dev/null +++ b/alt/modules/web/schizofox.nix @@ -0,0 +1,72 @@ +{ pkgs, inputs, ... }: { +#imports = [ inputs.schizofox.homeManagerModule ]; +programs.schizofox = { + enable = true; + + theme = { + colors = { + background-darker = "181825"; + background = "1e1e2e"; + foreground = "cdd6f4"; + }; + + font = "Lexend"; + + extraUserChrome = '' + body { + color: red !important; + } + .urlbarView { + display: none !important; + } + ''; + }; + + search = { + defaultSearchEngine = "Brave"; + removeEngines = ["Google" "Bing" "Amazon.com" "eBay" "Twitter" "Wikipedia"]; + searxUrl = "https://searx.be"; + searxQuery = "https://searx.be/search?q={searchTerms}&categories=general"; + addEngines = [ + { + Name = "Etherscan"; + Description = "Checking balances"; + Alias = "!eth"; + Method = "GET"; + URLTemplate = "https://etherscan.io/search?f=0&q={searchTerms}"; + } + ]; + }; + + security = { + sanitizeOnShutdown = false; + sandbox = true; + userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0"; + }; + + misc = { + drmFix = true; + disableWebgl = false; + #startPageURL = "file://${builtins.readFile ./startpage.html}"; + }; + + extensions = { + simplefox.enable = true; + darkreader.enable = true; + + extraExtensions = { + "webextension@metamask.io".install_url = "https://addons.mozilla.org/firefox/downloads/latest/ether-metamask/latest.xpi"; + }; + }; + + misc.bookmarks = [ + #{ + # Title = "Example"; + # URL = "https://example.com"; + # Favicon = "https://example.com/favicon.ico"; + # Placement = "toolbar"; + # Folder = "FolderName"; + #} + ]; +}; +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..9ade5c8 --- /dev/null +++ b/flake.nix @@ -0,0 +1,43 @@ +{ + description = "Our NixOS config lol"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + nur.url = "github:nix-community/NUR"; + schizofox.url = "github:schizofox/schizofox"; + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs.lib.follows = "nixpkgs"; + }; + home-manager = { + url = "github:nix-community/home-manager/"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs @ { self, nixpkgs, nur, home-manager, ... }: { + in { + nixpkgs.config.allowUnfree = true; + + nixosConfigurations = { + laptop = mkSystem { + hostname = "nixos"; + modules = [./hosts/laptop]; + user-configs = [{ + name = "vali"; + config = ./home/vali/laptop.nix; + }]; + }; + xfce = mkSystem { + hostname = "nixos"; + modules = [ ./hosts/xfce ]; + user-configs = [{ + name = "vali"; + config = ./home/vali/xfce.nix; + }]; + }; + }; + + }; + +} diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..9b380f5 --- /dev/null +++ b/notes.md @@ -0,0 +1,2 @@ +## Used Stuff +I think it'd be nice to use flake-parts, they make our config more sane. diff --git a/nyx/.editorconfig b/nyx/.editorconfig new file mode 100644 index 0000000..0e4c54d --- /dev/null +++ b/nyx/.editorconfig @@ -0,0 +1,32 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = tab +indent_size = 4 +insert_final_newline = true +tab_width = 4 +trim_trailing_whitespace = true + +[*.md] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = false + +[*.sh] +indent_style = space +indent_size = 2 + +[*.{nix,yml,yaml}] +indent_style = space +indent_size = 2 +tab_width = 2 + +[*.{js,lock,diff,patch,age}] +indent_style = unset +indent_size = unset +insert_final_newline = unset +trim_trailing_whitespace = unset +end_of_line = unset + diff --git a/nyx/.envrc b/nyx/.envrc new file mode 100644 index 0000000..1691f5a --- /dev/null +++ b/nyx/.envrc @@ -0,0 +1,2 @@ +watch_dir flake +use flake . --builders "" diff --git a/nyx/.forgejo/workflows/check.yml b/nyx/.forgejo/workflows/check.yml new file mode 100644 index 0000000..81a5dcb --- /dev/null +++ b/nyx/.forgejo/workflows/check.yml @@ -0,0 +1,15 @@ +name: Flake Check + +on: [push] +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + - name: Install Nix + uses: https://github.com/DeterminateSystems/nix-installer-action@v5 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: Check + run: nix flake check diff --git a/nyx/.forgejo/workflows/fmt.yml b/nyx/.forgejo/workflows/fmt.yml new file mode 100644 index 0000000..649a6ae --- /dev/null +++ b/nyx/.forgejo/workflows/fmt.yml @@ -0,0 +1,15 @@ +name: Flake Check + +on: [push] +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: https://code.forgejo.org/actions/checkout@v4 + - name: Install Nix + uses: https://github.com/DeterminateSystems/nix-installer-action@v5 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: Check + run: nix fmt -- -c . diff --git a/nyx/.gitattributes b/nyx/.gitattributes new file mode 100644 index 0000000..553530f --- /dev/null +++ b/nyx/.gitattributes @@ -0,0 +1,24 @@ +# always use LF line endings so that if a repo is accessed +# in Unix via a file share from Windows, the scripts will work +**/*.sh text eol=lf + +# try to get markdown files to be treated as markdown +# by linguist - ** prefix is for all subdirectories +**/*.md linguist-detectable +**/*.md linguist-language=Markdown + +# make .age files basically unreadable1 +secrets/*.age binary + +# luacheckrc is lua, lets treat it as such +.luacheckrc linguist-detectable +.luacheckrc linguist-language=Lua + +# Git Configuration files +*.gitattributes linguist-detectable=false +*.gitattributes linguist-documentation=false +*.gitignore linguist-detectable=false +*.gitignore linguist-documentation=false +*.editorconfig linguist-detectable=false +*.editorconfig linguist-documentation=false + diff --git a/nyx/.gitignore b/nyx/.gitignore new file mode 100644 index 0000000..3b21537 --- /dev/null +++ b/nyx/.gitignore @@ -0,0 +1,9 @@ +# Ignore nix stuff +result +.direnv/ + +# Ignore VM stuff +*.qcow2 + +# Ignore pre-commit config +.pre-commit-config.yaml diff --git a/nyx/.luacheckrc b/nyx/.luacheckrc new file mode 100644 index 0000000..1197d63 --- /dev/null +++ b/nyx/.luacheckrc @@ -0,0 +1,36 @@ +-- vim: ft=lua tw=80 + +max_comment_line_length = false +codes = true + +-- Don't report unused self arguments of methods. +self = false + +-- Rerun tests only if their modification time changed. +cache = true + +ignore = { + "212", -- Unused argument + "631", -- Line is too long + "121", -- setting read-only global variable 'vim' + "122", -- setting read-only field of global variable 'vim' + "542", -- Empty if branch + "581", -- negation of a relational operator- operator can be flipped (not for tables) +} + +globals = { + "vim.g", + "vim.b", + "vim.w", + "vim.o", + "vim.bo", + "vim.wo", + "vim.go", + "vim.env" +} + +read_globals = { + "vim", + "a", + "assert", +} diff --git a/nyx/.luarc.json b/nyx/.luarc.json new file mode 100644 index 0000000..0ec54cd --- /dev/null +++ b/nyx/.luarc.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", + "workspace": { + "library": ["runtime/lua"], + "checkThirdParty": "Disable" + }, + + "diagnostics": { + "groupFileStatus": { + "strict": "Opened", + "strong": "Opened" + }, + "groupSeverity": { + "strong": "Warning", + "strict": "Warning" + }, + "unusedLocalExclude": ["_*"], + "disable": ["luadoc-miss-see-name"] + } +} diff --git a/nyx/LICENSE b/nyx/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/nyx/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/nyx/README.md b/nyx/README.md new file mode 100644 index 0000000..6f7932d --- /dev/null +++ b/nyx/README.md @@ -0,0 +1,239 @@ +

+ +
+ Nýx +

+ +

+ My overengineered NixOS flake: Desktops, laptops, servers and everything + else that can run an OS.
+

+ + + +

+ Desktop Preview +

+ +

+ Screenshot last updated 2024-03-19 +

+ +## High Level Overview + +A high level overview of this monorepo, containing configurations for **all** of my machines +that are running or have ran NixOS at some point in time. As I physically cannot stop +tinkering with my configuration, nothing in this repository (including the overview sections) +should be considered final. As such, it is **not recommended to be used as a template** but +you are welcome to browse the codebase to your liking, you may find bits that are interesting +or/and useful to you. + +_Before you proceed, I would like to point you towards the [credits](#credits) section below +where I pay tribute to the individuals who have contributed to this project, whether through +code reference, suggestions, bug reports, or simply moral support._ + +### Notable Features + +[module options]: ./modules/options/style +[profiles]: ./modules/profiles +[wallpkgs]: https://github.com/notashelf/wallpkgs +[flake-parts]: https://flake.parts +[impermanence]: https://github.com/nix-community/impermanence + +- **All-in-one** - Servers, desktops, laptops, virtual machines and anything you + can think of. Managed in one place. + - **Sane Defaults** - The modules attempt to bring the most sane defaults, while + providing per-host toggles for conflicting choices. + - **Flexible Modules** - Both Home-manager and NixOS modules allow users to + retrieve NixOS or home-manager configurations from anywhere. + - **Extensive Configuration** - Most desktop programs are configured out of the + box and shared across hosts, with override options for per-host controls. + - **Custom extended library** - An extended library for functions that help + organize my system. +- **Shared Configurations** - Reduces re-used boilerplate code by sharing + modules and profiles across hosts. +- **Fully Modular** - Utilizes NixOS' module system to avoid hard-coding any of + the options. + - **Profiles & Roles** - Provide serialized configuration sets and pluggables + for easily changing large portions of configurations with less options and + minimal imports. + - **Detached Homes** - Home-manager configurations are able to be detached for + non-NixOS usage. + - **Modularized Flake Design** - With the help of [flake-parts], the flake is + fully modular: keeping my `flake.nix` cleaner than ever. + - **Declarative Themes** - Using my [module options], [profiles] and [wallpkgs]. + Everything theming is handled inside the flake. + - **Tree-wide formatting** - Format files in any language with the help of devshells + and treefmt-nix modules for flake-parts. +- **Declarative nftables firewall** - Overengineered nftables chain builder for easy + firewall setups. +- **Personal Installation Media** - Personalized ISO images for system installation + and recovery. +- **Secrets Management** - Manage secrets through Agenix. +- **Opt-in Impermanence** - On-demand ephemeral root using BTRFS rollbacks + and [impermanence]. +- **Encryption Ready** - Supports and actively utilizes full disk encryption. +- **Wayland First** - Leaves Xorg in the past where it belongs. Everything is + configured around Wayland, with Xorg only as a fallback. + +### Repo Structure + +[flake schemas]: https://determinate.systems/posts/flake-schemas +[Home-Manager]: https://github.com/nix-community/home-manager + +- [flake.nix](./flake.nix) Ground zero of my system configuration. Declaring entrypoints +- [lib](./lib) Personal library of functions and utilities +- [docs](./docs)The documentation for my flake repository + - [notes](./docs/notes) Notes from tedious or/and under-documented processes I have gone through. More or less a blog + - [cheatsheet](./docs/cheatsheet.md) Useful tips that are hard to memorize, but easy to write down +- [flake/](./flake) Individual parts of my flake, powered by flake-parts + - [modules](./flake/modules) modules provided by my flake for both internal and public use + - [pkgs](./flake/pkgs) packages exported by my flake + - [schemes](./flake/schemes) home-baked flake schemas for upcoming [flake schemas] + - [templates](./flake/templates) templates for initializing flakes. Provides some language-specific flakes + - [args.nix](./flake/args.nix) initiate and configure nixpkgs locally + - [deployments.nix](./flake/deployments.nix) host setup for deploy-rs, currently a work in progress + - [treefmt.nix](./flake/treefmt.nix) various language-specific configurations for treefmt +- [homes](./homes) my personalized [Home-Manager] configuration module +- [hosts](./hosts) per-host configurations that contain machine specific instructions and setups +- [modules](./modules) modularized NixOS configurations + - [core](./modules/common) The core module that all systems depend on + - [common](./modules/common) Module configurations shared between all hosts (except installers) + - [profiles](./modules/profiles) Internal module system overrides based on host declarations + - [roles](./modules/roles) A profile-like system that work through imports and ship predefined configurations + - [extra](./modules/extra) Extra modules that are rarely imported + - [shared](./modules/extra/shared) Modules that are both shared for outside consumption, and imported by the flake itself + - [exported](./modules/extra/exported) Modules that are strictly for outside consumption and are not imported by the flake itself + - [options](./modules/options) Definitions of module options used by common modules + - [meta](./modules/options/meta) Internal, read-only module that defines host capabilities based on other options + - [device](./modules/options/device) Hardware capabilities of the host + - [documentation](./modules/options/docs) Local module system documentation + - [system](./modules/options/system) OS-wide configurations for generic software and firmware on system level + - [theme](./modules/options/theme) Active theme configurations ranging from QT theme to shell colors + - [usrEnv](./modules/options/usrEnv) userspace exclusive configurations. E.g. lockscreen or package sets +- [secrets](./secrets) Agenix secrets + +## Host Specifications + +| Name | Description | Type | Arch | +| :----------- | :------------------------------------------------------------------------------------------------ | :-----: | :-----------: | +| `gaea` | Custom live media, used as an installer | ISO | - | +| `erebus` | Air-gapped virtual machine/live-iso configuration for sensitive jobs | ISO | - | +| `enyo` | Day-to-day desktop workstation boasting a full AMD system. | Desktop | x86_64-linux | +| `helios` | Hetzner cloud VPS for non-critical infrastructure | Server | x86_64-linux | +| `prometheus` | HP Pavillion with a a GTX 1050 and i7-7700hq | Laptop | x86_64-linux | +| `epimetheus` | Twin of prometheus, features full disk encryption in addition to everything prometheus provides | Laptop | x86_64-linux | +| `hermes` | HP Pavillion with a Ryzen 7 7730U, and my main portable workstation. Used on-the-go | Laptop | x86_64-linux | +| `atlas` | Proof of concept server host that is used by my Raspberry Pi 400 | Server | aarch64-linux | +| `icarus` | My 2014 Lenovo Yoga Ideapad that acts as a portable server, used for testing hardware limitations | Laptop | x86_64-linux | +| `artemis` | VM host for testing basic NixOS concepts. Previously targeted aarch64-linux | VM | x86_64-linux | +| `apollon` | VM host for testing networked services, generally used on servers | VM | x86_64-linux | +| `leto` | VM host running medium-priority infrastructure inside a virtualized root server | VM | x86_64-linux | + +## Credits & Special Thanks to + +[atrocious abstractions]: ./lib/builders.nix + +My special thanks go to [fufexan](https://github.com/fufexan) for +convincing me to use NixOS and sticking around to answer my most +stupid and deranged questions, as well as my [atrocious abstractions]. + +And to [sioodmy](https://github.com/sioodmy) which my configuration is initially based on. The +simplicity of his configuration flake allowed me to take a foothold in the Nix world. + +### Awesome People + +I ~~shamelessly stole from~~ got inspired by those folks + +[sioodmy](https://github.com/sioodmy) - +[fufexan](https://github.com/fufexan) - +[rxyhn](https://github.com/rxyhn) - +[NobbZ](https://github.com/NobbZ) - +[ViperML](https://github.com/viperML) - +[spikespaz](https://github.com/spikespaz) - +[hlissner](https://github.com/hlissner) - +[fortuneteller2k](https://github.com/fortuneteller2k) - +[Max Headroom](https://github.com/max-privatevoid) + +... and surely there are more, but I tend to forget. + +### Anti-credits + +Pretend I haven't credited those people (but I will, because they are equally awesome and I appreciate them) + +[n3oney](https://github.com/n3oney) - +[gerg-l (bald frog)](https://github.com/gerg-l) - +[eclairevoyant](https://github.com/eclairevoyant/) - +[FrothyMarrow](https://github.com/frothymarrow) + +### Other Cool Resources + +Resource that helped shape and improve this configuration, or resources that I strongly recommend that you read +in no particular order. + +#### Readings + +- [A list of Nix library functions and builtins](https://teu5us.github.io/nix-lib.html) +- [Zero to Nix](https://zero-to-nix.com/) +- [Nix Pills](https://nixos.org/guides/nix-pills/) +- [Xe Iaso's blog](https://xeiaso.net/blog) +- [Vinícius Müller's Blog](https://viniciusmuller.github.io/blog) +- [Viper's Blog](https://ayats.org/) +- [Solène's Blog](https://dataswamp.org/~solene) +- [...my own "blog"?](https://notashelf.github.io/nyx/) + +#### Software + +Software that helped this configuration become what it is, or software I find interesting + +**Linux** + +- [Hyprland](https://github.com/hyprwm/Hyprland) +- [ags](https://github.com/aylur/ags) + +**Nix/NixOS** + +- [Agenix](https://github.com/ryantm/agenix) +- [nh](https://github.com/viperML/nh) + +Projects I have made to use in this repository, or otherwise cool software that are +used in this repository that I would like to endorse. + +- [nyxpkgs](https://github.com/notashelf/nyxpkgs) - my personal package collection +- [neovim-flake](https://github.com/notashelf/neovim-flake) - highly modular neovim module for NixOS & Home-manager +- [docr](https://github.com/notashelf/docr) - my barebones static site generator, used to generate my blog +- [schizofox](https://github.com/schizofox/schizofox) - hardened Firefox configuration for the delusional and the paranoid + +Additionally, take a look at my [notes/blog](./docs/notes) for my notes on specific processes on NixOS. + +## License + +Unless explicitly stated otherwise, all code under this repository (except for [anything in docs directory](docs)) +is licensed under the [GPLv3](./LICENSE), or should you prefer, under any later version of the GPL released +by the FSF. + +The notes and documentation available in [docs directory](docs) is licensed under the [CC BY License](./docs/LICENSE). + +All code here (excluding secrets) are available for your convenience and at my expense as I believe it is in NixOS +configurations' spirit to share knowledge with and learn from other NixOS users. As such if you are directly +copying a section of my configuration, please include a copyright notice at the top of the file you import the code. + +It is not enforced, but your kindness and due diligence would be appreciated. + +--- + +

Preview

+ +

+ Desktop Preview +

+

+ Screenshot last updated 2023-12-09 +

+ + diff --git a/nyx/docs/.envrc b/nyx/docs/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/nyx/docs/.envrc @@ -0,0 +1 @@ +use nix diff --git a/nyx/docs/.gitignore b/nyx/docs/.gitignore new file mode 100644 index 0000000..5aa5b09 --- /dev/null +++ b/nyx/docs/.gitignore @@ -0,0 +1,6 @@ + +# Ignore directories generated by our documentation scripts +out/ + +# Ignore compiled stylesheet +templates/style.css diff --git a/nyx/docs/LICENSE b/nyx/docs/LICENSE new file mode 100644 index 0000000..10fabd9 --- /dev/null +++ b/nyx/docs/LICENSE @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the “Licensor.” The text of the Creative Commons public +licenses is dedicated to the public domain under the CC0 Public Domain +Dedication. Except for the limited purpose of indicating that material +is shared under a Creative Commons public license or as otherwise +permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/nyx/docs/gen.sh b/nyx/docs/gen.sh new file mode 100755 index 0000000..757bae7 --- /dev/null +++ b/nyx/docs/gen.sh @@ -0,0 +1,249 @@ +#!/usr/bin/env bash +set -e +set -u +set -o pipefail + +# Site Meta +title="NotAShelf/nyx" +site_url="https://nyx.notashelf.dev" +site_description="NotAShelf's notes on various topics" + +# Directories +tmpdir="$(mktemp -d)" +workingdir="$(pwd)" +outdir="$workingdir"/out +posts_dir="$outdir/posts" +pages_dir="$outdir/pages" + +# A list of posts +json_file="$posts_dir/posts.json" + +create_directory() { + if [ ! -d "$1" ]; then + echo "Creating directory: $1" + mkdir -p "$1" + fi +} + +compile_stylesheet() { + echo "Compiling stylesheet..." + sassc --style=compressed "$1"/"$2" "$1"/out/style.css +} + +generate_posts_json() { + echo "Generating JSON..." + json='{"posts":[' + first=true + for file in "$1"/notes/*.md; do + filename=$(basename "$file") + if [[ $filename != "README.md" ]]; then + if [[ $filename =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then + # Extract date from filename + date=$(echo "$filename" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}') + + # Sanitize title + sanitized_title=$(echo "$filename" | sed -E 's/^[0-9]{4}-[0-9]{2}-[0-9]{2}-//; s/\.md$//; s/-/ /g; s/\b\w/\u&/g') + if [ "$first" = true ]; then + first=false + else + json="$json," + fi + + # JSON object with data we may want to use like a json feed file + # this doesn't, however, actually follow jsonfeed spec + # that is done so by the generate_jsonfeed_spec function + + json_object=$(jq -n \ + --arg name "$filename" \ + --arg url "$site_url/posts/$(basename "$file" .md).html" \ + --arg date "$date" \ + --arg title "$sanitized_title" \ + --arg path "/posts/$(basename "$file" .md).html" \ + '{name: $name, url: $url, date: $date, title: $title, path: $path}') + + # Append JSON object to the array + json="$json$json_object" + fi + fi + done + json="$json]}" + # Format JSON with jq + formatted_json=$(echo "$json" | jq .) + echo "$formatted_json" >"$2" +} + +generate_jsonfeed_spec() { + echo "Generating JSON Feed..." + json=$(jq -n \ + --arg version "https://jsonfeed.org/version/1.1" \ + --arg title "$title" \ + --arg home_page_url "$site_url" \ + --arg feed_url "$site_url/feed.json" \ + '{version: $version, title: $title, home_page_url: $home_page_url, feed_url: $feed_url, items: []}') + + # Initialize the ID counter to 0 + id_counter=0 + + for file in "$1"/notes/*.md; do + filename=$(basename "$file") + if [[ $filename != "README.md" ]]; then + if [[ $filename =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then + # Extract date from filename + date=$(echo "$filename" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}') + + # Sanitize title + sanitized_title=$(echo "$filename" | sed -E 's/^[0-9]{4}-[0-9]{2}-[0-9]{2}-//; s/\.md$//; s/-/ /g; s/\b\w/\u&/g') + + # Generate the URL for the post + url="$site_url/posts/$(basename "$file" .md).html" + + content_raw="$(cat notes/"$(basename "$file" .md)".html)" + + # Generate the JSON object for the item + json_object=$(jq -n \ + --arg id "$id_counter" \ + --arg url "$url" \ + --arg title "$sanitized_title" \ + --arg date "$date" \ + --arg content_html "$content_raw" \ + '{id: $id, url: $url, title: $title, date_published: $date, content_html: $content_raw}') + + # Append the JSON object to the items array + json=$(echo "$json" | jq --argjson item "$json_object" '.items += [$item]') + + # Increment the ID counter + id_counter=$((id_counter + 1)) + fi + fi + done + + # Format JSON with jq + formatted_json=$(echo "$json" | jq .) + echo "$formatted_json" >"$2" +} + +# Index page refers to the "main" page generated +# from the README.md, which I would like to see on the front +generate_index_page() { + local templates="$1"/templates + + echo "Generating index page..." + pandoc --from gfm --to html \ + --standalone \ + --template "$templates"/html/page.html \ + --css /style.css \ + --variable="index:true" \ + --metadata title="$title" \ + --metadata description="$site_description" \ + "$1/notes/README.md" -o "$2/index.html" +} + +generate_other_pages() { + local templates="$2"/templates + + echo "Generating other pages..." + for file in "$1"/notes/*.md; do + filename=$(basename "$file") + if [[ $filename != "README.md" ]]; then + if [[ $filename =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then + # Date in filename imples a blogpost + # convert it to markdown and place it in the posts directory + # since this is a post, it can contain a table of contents + echo "Converting $filename..." + pandoc --from gfm --to html \ + --standalone \ + --template "$templates"/html/page.html \ + --css /style.css \ + --metadata title="$filename" \ + --metadata description="$site_description" \ + --table-of-contents \ + --highlight-style="$templates"/pandoc/custom.theme \ + "$file" -o "$3/posts/$(basename "$file" .md).html" + else + if [[ $filename != "*-md" ]]; then + echo "Converting $filename..." + # No date in filename, means this is a standalone page + # convert it to html and place it in the pages directory + pandoc --from gfm --to html \ + --standalone \ + --template "$templates"/html/page.html \ + --css /style.css \ + --metadata title="$filename" \ + --metadata description="$site_description" \ + "$file" -o "$3/pages/$(basename "$file" .md).html" + fi + fi + fi + done + for file in "$4"/*.md; do + filename=$(basename "$file") + pandoc --from gfm --to html \ + --standalone \ + --template "$templates"/html/page.html \ + --css /style.css \ + --metadata title="$filename" \ + --metadata description="$site_description" \ + --highlight-style="$templates"/pandoc/custom.theme \ + "$file" -o "$3/pages/$(basename "$file" .md).html" + done +} + +write_privacy_policy() { + # write privacy.md as notes/privacy.md + cat >"$1/privacy.md" <"$1/about.md" <<-EOF +# About + +I work with Nix quite often, and share some of the stuff I learn while I do so. This website contains various notes +on things that interested me, or things I thought was worth sharing. If you would like to contribute, or have any feedback +you think would be useful, please feel free to reach out to me via email, available at my GitHub profile or +[on my website](https://notashelf.dev) +EOF +} + +cleanup() { + echo "Cleaning up..." + rm -rf "$tmpdir" +} + +trap cleanup EXIT + +# Create directories +create_directory "$outdir" +create_directory "$posts_dir" +create_directory "$pages_dir" + +# Compile stylesheet +compile_stylesheet "$workingdir" "templates/scss/main.scss" + +# Index page +generate_index_page "$workingdir" "$outdir" + +# Other Pages +write_about_page "$tmpdir" +write_privacy_policy "$tmpdir" +generate_other_pages "$workingdir" "$workingdir" "$outdir" "$tmpdir" + +# Post list and feed file +generate_posts_json "$workingdir" "$json_file" +generate_jsonfeed_spec "$workingdir" "$outdir"/feed.json + +# Cleanup +cleanup + +echo "All tasks completed successfully." diff --git a/nyx/docs/notes/2023-01-22-system-backlight.md b/nyx/docs/notes/2023-01-22-system-backlight.md new file mode 100644 index 0000000..d83b4a6 --- /dev/null +++ b/nyx/docs/notes/2023-01-22-system-backlight.md @@ -0,0 +1,18 @@ +# Notes for 22th of January, 2023 + +Following a system upgrade two days ago, my HP Pavillion laptop has stopped +registering the `intel_backlight` interface in `/sys/class/backlight`, which +is most often used to control backlight by tools such as `brightnessctl.` +Inspecting `dmesg` has given me nothing but aninsanely vague error message. +Only mentioning it is not being loaded (_very helpful, thanks!_) + +After some research, on Google as every other confused Linux user, I have +come across [this article](https://www.linuxquestions.org/questions/slackware-14/brightness-keys-not-working-after-updating-to-kernel-version-6-a-4175720728/) +which mentions backlight behaviour has changed sometime after kernel 6.1.4. +Fortunately for me, the article also refers to the the ever so informative +ArchWiki, which instructs passing one of the [three kernel command-line options](https://wiki.archlinux.org/title/backlight#Kernel_command-line_options). +depending on our needs. + +As I have upgraded from 6.1.3 to 6.1.6 with a flake update, the `acpi_backlight=none` +parameter has made it so that it would skip loading intel backlight entirely. Simply switching +this parameter to `acpi_backlight=native` as per the article above has fixed the issue. diff --git a/nyx/docs/notes/2023-03-14-impermanence.md b/nyx/docs/notes/2023-03-14-impermanence.md new file mode 100644 index 0000000..6bcc22d --- /dev/null +++ b/nyx/docs/notes/2023-03-14-impermanence.md @@ -0,0 +1,355 @@ +# Notes for 14th of March, 2023 + +Today was the day I finally got to setting up both "erase your darlings" +and proper disk encryption. This general setup concept utilizes NixOS' +ability to boot off of a disk that contains only `/nix` and `/boot`, linking +appropriate devices and blocks during the boot process and deleting all state +that programs may have left over my system. + +The end result, for me, was a fully encrypted that uses btrfs +snapshots to restore `/` to its original state on each boot. + +## Resources + +- [This discourse post](https://discourse.nixos.org/t/impermanence-vs-systemd-initrd-w-tpm-unlocking/25167) +- [This blog post](https://elis.nu/blog/2020/06/nixos-tmpfs-as-home) +- [This other blog post](https://guekka.github.io/nixos-server-1/) +- [And this post that the previous post is based on](https://mt-caret.github.io/blog/posts/2020-06-29-optin-state.html) +- [Impermanence](https://github.com/nix-community/impermanence) + +## The actual set-up (and reproduction steps) + +I've had to go through a few guides before I could figure out a set up that I +really like. The final decision was that I would have an encrypted disk that +restores itself to its former state during boot. Is it fast? Absolutely not. +But it sure as hell is cool. And stateless! + +To return the root (and only the root) we use a systemd service that fires +shortly after the disk is encrypted but before the root is actually mounted. +That way, we can unlock the disk, restore the disk to its pristine state +using the snapshot we have taken during installation and mount the root to +go on with our day. + +### Reproduction steps + +#### Partitioning + +First you want to format your disk. If you are really comfortable with +bringing parted to your pre-formatted disks, by all means feel free to skip +this section. I, however, choose to format a fresh disk. + +Start by partitioning the sections of our disk (sda1, sda2 and sda3) +_Device names might change if you're using a nvme disk, i.e nvme0p1._ + +```bash +# Set the disk name to make it easier +DISK=/dev/sda # replace this with the name of the device you are using + +# set up the boot partition +parted "$DISK" -- mklabel gpt +parted "$DISK" -- mkpart ESP fat32 1MiB 1GiB +parted "$DISK" -- set 1 boot on + +mkfs.vfat -n BOOT "$DISK"1 +``` + +```bash +# set up the swap partition +parted "$DISK" -- mkpart Swap linux-swap 1GiB 9GiB +mkswap -L SWAP "$DISK"2 +swapon "$DISK"2 +``` + +_I do in fact use swap in the civilized year of 2023[^1]. If I were a little +more advanced, and if I did not disable hibernation due to overly-hardened +kernel parameters, I would also be encrypting the swap to secure the hibernates... +but that is *currently* out of my scope. You may find this desirable, however, I +will not be providing instructions on that._ + +Encrypt your partition, and open it to make it available under `/dev/mapper/enc`. + +```bash +cryptsetup --verify-passphrase -v luksFormat "$DISK"3 # /dev/sda3 +cryptsetup open "$DISK"3 enc +``` + +Now partition the encrypted device block. + +```bash +parted "$DISK" -- mkpart primary 9GiB 100% +mkfs.btrfs -L NIXOS /dev/mapper/enc +``` + +```bash +mount -t btrfs /dev/mapper/enc /mnt + +# First we create the subvolumes, those may differ as per your preferences +btrfs subvolume create /mnt/root +btrfs subvolume create /mnt/home +btrfs subvolume create /mnt/nix +btrfs subvolume create /mnt/persist # some people may choose to put /persist in /mnt/nix, I am not one of those people. +btrfs subvolume create /mnt/log +``` + +Now that we have created the btrfs subvolumes, it is time for the _readonly_ +snapshot of the root subvolume. + +```bash +btrfs subvolume snapshot -r /mnt/root /mnt/root-blank + +# Make sure to unmount, or nixos-rebuild will try to remove /mnt and fail +umount /mnt +``` + +#### Mounting + +After the subvolumes are created, we mount them with the options that we want. +Ideally, on NixOS, you want the `noatime` option [^2] and zstd +compression, especially on your `/nix` partition. + +The following is my partition layout. If you have created any other subvolumes +in the step above, you will also want to mount them here. Below setup assumes +that you have been following the steps as is. + +```bash +# / +mount -o subvol=root,compress=zstd,noatime /dev/mapper/enc /mnt + +# /home +mkdir /mnt/home +mount -o subvol=home,compress=zstd,noatime /dev/mapper/enc /mnt/home + +# /nix +mkdir /mnt/nix +mount -o subvol=nix,compress=zstd,noatime /dev/mapper/enc /mnt/nix + +# /persist +mkdir /mnt/persist +mount -o subvol=persist,compress=zstd,noatime /dev/mapper/enc /mnt/persist + +# /var/log +mkdir -p /mnt/var/log +mount -o subvol=log,compress=zstd,noatime /dev/mapper/enc /mnt/var/log + +# do not forget to mount the boot partition +mkdir /mnt/boot +mount "$DISK"1 /mnt/boot +``` + +And finally let NixOS generate the hardware configuration. + +```bash +nixos-generate-config --root /mnt +``` + +The genereated configuration will be available at `/mnt/etc/nixos`. + +Before we move on, we need to add the `neededForBoot = true;` to some mounted +subvolumes in `hardware-configuration.nix`. It will look something like this: + +```nix +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "usb_storage" "sd_mod" "rtsx_pci_sdmmc"]; + boot.initrd.kernelModules = []; + boot.kernelModules = ["kvm-intel"]; + boot.extraModulePackages = []; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=root"]; + }; + + boot.initrd.luks.devices."enc".device = "/dev/disk/by-uuid/82144284-cf1d-4d65-9999-2e7cdc3c75d4"; + + fileSystems."/home" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=home"]; + }; + + fileSystems."/nix" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=nix"]; + }; + + fileSystems."/persist" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=persist"]; + neededForBoot = true; # <- add this + }; + + fileSystems."/var/log" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=log"]; + neededForBoot = true; # <- add this + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/FDED-3BCF"; + fsType = "vfat"; + }; + + swapDevices = [ + {device = "/dev/disk/by-uuid/0d1fc824-623b-4bb8-bf7b-63a3e657889d";} + # if you encrypt your swap, it'll also need to be configured here + ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; +} +``` + +Do keep in mind that the NixOS hardware scanner **cannot** pick up your mount +options. Which means that you should specifiy the options (i.e `noatime`) for +each btrfs volume that you have created in `hardware-configuration.nix`. You +can simply add them in the `options = [ ]` list in quotation marks. I +recommend adding at least zstd compression, and optionally `noatime`. + +### Closing Notes + +And that should be all. By this point you are pretty much ready to install +with your existing config. I generally use my configuration flake to boot, so +there is no need to make any revisions. If you are starting from scratch, you +may consider tweaking your configuration.nix before you install the system. +An editor, such as Neovim, or your preferred DE/wm make good additions to your +configuration. + +Once it's all done, take a deep breath and `nixos-install`. Once the +installation is done, you'll be prompted for the root password and after that +you can reboot. Now you are running NixOS on an encrypted disk. Nice! + +Next up, if you are feeling _really_ fancy today, is to configure disk +erasure and impermanence. + +#### Impermanence + +For BTRFS snapshots, I use a systemd service that goes + +```nix +boot.initrd.systemd = { + enable = true; # this enabled systemd support in stage1 - required for the below setup + services.rollback = { + description = "Rollback BTRFS root subvolume to a pristine state"; + wantedBy = [ + "initrd.target" + ]; + + after = [ + # LUKS/TPM process + "systemd-cryptsetup@enc.service" + ]; + + before = [ + "sysroot.mount" + ]; + + unitConfig.DefaultDependencies = "no"; + serviceConfig.Type = "oneshot"; + script = '' + mkdir -p /mnt + + # We first mount the btrfs root to /mnt + # so we can manipulate btrfs subvolumes. + mount -o subvol=/ /dev/mapper/enc /mnt + + # While we're tempted to just delete /root and create + # a new snapshot from /root-blank, /root is already + # populated at this point with a number of subvolumes, + # which makes `btrfs subvolume delete` fail. + # So, we remove them first. + # + # /root contains subvolumes: + # - /root/var/lib/portables + # - /root/var/lib/machines + + btrfs subvolume list -o /mnt/root | + cut -f9 -d' ' | + while read subvolume; do + echo "deleting /$subvolume subvolume..." + btrfs subvolume delete "/mnt/$subvolume" + done && + echo "deleting /root subvolume..." && + btrfs subvolume delete /mnt/root + echo "restoring blank /root subvolume..." + btrfs subvolume snapshot /mnt/root-blank /mnt/root + + # Once we're done rolling back to a blank snapshot, + # we can unmount /mnt and continue on the boot process. + umount /mnt + ''; + }; +}; + +``` + +> You may opt in for `boot.initrd.postDeviceCommands = lib.mkBefore ''` +> as [this blog post](https://mt-caret.github.io/blog/posts/2020-06-29-optin-state.html) +> suggests. I am not exactly sure how exactly those options actually +> compare, however, a systemd service means it will be accessible through the +> the systemd service interface, which is why I opt-in for a service. + +##### Implications + +What this implies is that certain files such as saved networks for +network-manager will be deleted on each reboot. While a little clunky, +[Impermanence](https://github.com/nix-community/impermanence) is a great +solution to our problem. + +Impermanence exposes to our system an `environment.persistence.""` option that we can use to make certain directories or files permanent. +My module goes like this: + +```nix +imports = [inputs.impermanence.nixosModules.impermanence]; # the import will be different if flakes are not enabled on your system + +environment.persistence."/persist" = { + directories = [ + "/etc/nixos" + "/etc/NetworkManager/system-connections" + "/etc/secureboot" + "/var/db/sudo" + ]; + + files = [ + "/etc/machine-id" + + # ssh stuff + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + # if you use docker or LXD, also persist their directories + ]; +}; +``` + +And that is pretty much it. If everything went well, you should now be telling +your friends about your new system boasting full disk encryption _and_ root +rollbacks. + +## Why? + +Honestly, why not? + +[^1]: + I could be using `tmpfs` for `/` at this point in time. Unfortunately, since I share this setup on some of my low-end laptops, I've got no RAM + to spare - which is exactly why I have opted out with BTRFS. It is a reliable filesystem that I am used to, and it allows for us to use a script + that we'll see later on. + +[^2]: https://opensource.com/article/20/6/linux-noatime diff --git a/nyx/docs/notes/2023-05-21-packaging-nextjs-webapps.md b/nyx/docs/notes/2023-05-21-packaging-nextjs-webapps.md new file mode 100644 index 0000000..31eaaa1 --- /dev/null +++ b/nyx/docs/notes/2023-05-21-packaging-nextjs-webapps.md @@ -0,0 +1,145 @@ +# Notes for 21st of June, 2023 + +Recenty I have had to go through the misfortune of hosting some websites +written with _NextJS_ on my VPS running NixOS, this note entry shall document +my experience and the "easy" path I have chosen. + +## Packaging + +The websites I hosted were of two variety: those statically exported, and +those that cannot be statically exported. + +### Statically Exported Webapps + +Statically exported ones are easy to package, because it is a matter of +running `npm build` (or whatever your build script is) with the following +NextJS settings + +```js +// next.config.js +module.exports = { + distDir: "dist", // an artitrary path for your export + output: "export", +}; +``` + +This will export a static website with a bunch of html files that you can +then serve with nodePackages.serve or a webserver like nginx or apache. +And that is the end of your worries for a statically exported website! No +headache, just write a simple derivation, such as the one below + +```nix +# default.nix +{ + buildNpmPackage, + pkg-config, + python3, + ... +}: +buildNpmPackage { + pname = "your-website"; + version = "0.1"; + + src = ./.; + # needs to be updated everytime you update npm dependencies + npmDepsHash = "sha256-some-hash"; + # some npm packages may need to be built from source, because nodejs is a *terrible* ecosystem + nativeBuildInputs = [pkg-config python3]; + + # move exported website to $out + postInstall = '' + cp -rf dist/* $out + ''; +} +``` + +and serve its path with a simple tool after building the derivation, I find +nginx to be awfully convenient for doing so, but you may choose caddy if you +prefer. + +### Webapps that cannot be statically exported + +If your website depends on API routes for some reasons, then Next will not +allow you to do static export. Which means you need to run `next start` in +some shape or form. While a systemd service is certainly a way of doing it +(one that I do not recommend), a oci container works as well if not better. + +You can write a "simple" docker image for your oci container to use, such as +the one below + +```nix +# dockerImage.nix +{ + pkgs, + inputs, + ... +}: { + dockerImage = pkgs.dockerTools.buildImage { + config = { + WorkingDir = "/your-website"; + Cmd = ["npm" "run" "serve"]; + }; + + name = "your-website"; + tag = "latest"; + + fromImage = pkgs.dockerTools.buildImage { + name = "node"; + tag = "18-alpine"; + }; + + copyToRoot = pkgs.buildEnv { + name = "image-root"; + + paths = with pkgs; [ + # this package is called from a flake.nix alongside the derivation for the website + inputs.self.packages.${pkgs.system}.your-website + nodejs + bash + ]; + + pathsToLink = [ + "/bin" + "/your-website" + ]; + }; + }; +} +``` + +Then, configure oci-containers module option to pick up the Docker image that +you have built. This is a simplified version of my VPS' container setup. +An example can be found in my [server module](https://github.com/NotAShelf/nyx/blob/a9e129663ac91302f2fd935351a71cbbd2832f64/modules/core/roles/server/system/services/mkm.nix) + +```nix +virtualisation.oci-containers = { + backend = "podman"; + containers = { + "website-container" = { + autoStart = true; + ports = [ + "3000:3000" # bind container's port 3000 to the outside port 3000 for NextJS + ]; + + extraOptions = ["--network=host"]; + + image = "your-website"; + imageFile = inputs.website-flake.packages.${pkgs.system}.dockerImage; + }; + }; +}; +``` + +After a rebuild, your system will provision the container and start it on +port **3000**. You can access it with `your-server-ip:3000` in your +browser, and even configure nginx to set up a reverse proxy to assign +your domain. + +```conf +"example.com" = { + locations."/".proxyPass = "http://127.0.0.1:3000"; +}; +``` + +This will assign your domain to your webserver, and allow outside +visitors to view your "awesome" NextJS webapp. diff --git a/nyx/docs/notes/2023-06-07-extended-nixpkgs.md b/nyx/docs/notes/2023-06-07-extended-nixpkgs.md new file mode 100644 index 0000000..00f96bc --- /dev/null +++ b/nyx/docs/notes/2023-06-07-extended-nixpkgs.md @@ -0,0 +1,103 @@ +# Notes for 7th of June, 2023 + +Those are my notes on extending nixpkgs with your own functions and +abstractions. There may be other ways of doing it, but this is the one I find +to be most ergonomic. + +## What is `nixpkgs.lib` + +In the context of the Nix package manager and NixOS, `nixpkgs.lib` refers to +a module within the Nixpkgs repository. The `nixpkgs.lib` module provides a +set of utility functions and definitions that are commonly used across the +Nixpkgs repository. It contains various helper functions and abstractions that +make it easier to write Nix expressions and define packages. We often use those +functions to simplify our configurations and the nix package build processes. + +## Why would you need to extend `nixpkgs.lib` + +While the library functions provided by nixpkgs is quite extensive and usually +suits my needs, I sometimes feel the need to define my own function or wrap an +existing function to complete a task. Normally we can handle the process of a +function inside a simple `let in` and be well off, but there may be times you +need to re-use the existing function across your configuration file. + +In such times, you might want to either write your own lib and inherit it at +the source of your `flake.nix` to then inherit them across your configuration. + +Today's notes document the process of doing exactly that. + +## Extending `nixpkgs.lib` + +I find the easiest way of extending nixpkgs.lib to be using an overlay. + +```nix +# lib/default.nix +{ + nixpkgs, + lib, + inputs, + ... +}: nixpkgs.lib.extend ( + final: prev: { + # your functions go here + } + ) +``` + +The above structure takes the existing `lib` from `nixpkgs`, and appends your +own configurations to it. You may then import this library in your `flake.nix` +to pass it to other imports and definitions. + +```nix +# flake.nix +flake = let + # extended nixpkgs lib, contains my custom functions + lib = import ./lib {inherit nixpkgs lib inputs;}; +in { + # entry-point for nixos configurations + nixosConfigurations = import ./hosts {inherit nixpkgs self lib;}; +}; +``` + +In this example (see my `flake.nix` for the actual implementation) I import my +extended lib from `lib/default.nix`, where I defined the overlay. I then pass +the extended lib to my `nixosConfiguratiıns`, which is an entry-point for all +of my NixOS configurations. As such, I am able to re-use my own utility +functions across my system as I see fit. + +The problem with this approach is that it may be confusing for other people +reviewing your configuration. With this approach, `lib.customFunction` looks +identical to any lib function, which may lead to people thinking the function +exists in nixpkgs itself while it is only provided by your configuration. The +solution for that is simple though, instead of extending `nixpkgs.lib`, you may +define your own lib that does not inherit from `nixpkgs.lib` and only contains +your functions. The process would be similar, and you would not need to define +an overlay. + +```nix +# flake.nix +flake = let + # extended nixpkgs lib, contains my custom functions + lib' = import ./lib {inherit nixpkgs lib inputs;}; +in { + # entry-point for nixos configurations + nixosConfigurations = import ./hosts {inherit nixpkgs self lib';}; +}; +``` + +where your `lib/default.nix` looks like + +```nix +# lib/default.nix +{ + nixpkgs, + lib, + inputs, + ... +}: { + # your functions here +} +``` + +You can find a real life example of the alternative approach in +my [neovim-flake's lib](https://github.com/NotAShelf/neovim-flake/blob/main/lib/stdlib-extended.nix). diff --git a/nyx/docs/notes/2023-07-14-openssh-custom-port.md b/nyx/docs/notes/2023-07-14-openssh-custom-port.md new file mode 100644 index 0000000..19534b8 --- /dev/null +++ b/nyx/docs/notes/2023-07-14-openssh-custom-port.md @@ -0,0 +1,82 @@ +# Notes for 14th of July, 2023 + +My VPS, which hosts some of my infrastructure, has been running NixOS +for a while now. Although weak, I use it for distributed builds alongside the +rest of my NixOS machines on a Tailscale network. + +This server, due to it hosting my infrastructure that communicates with the +rest of the internet (i.e my mailserver), is somewhat responsive to queries +from the public - which includes _very_ agressive portscans (thanks, skiddies!) + +To mitigate that, I have decided to change the ssh port from the default **22** +to something different. While this is not exactly a pancea, it helps alleviate +the insane log spam I get from failed ssh requests. + +## The OpenSSH Configuration + +First thing we've done is to configure openssh to listen on the new port on +your server configuration + +```nix +services.openssh = { + ports = [2222]; +} +``` + +With this set, openssh on the server will now be listening on the port **2222** +instead of the default **22**. For the changes to take effect after a +rebuild, you might need to run `systemctl restart sshd.socket`. + +Then we want to configure our client to use the correct port for our server +instead of the default **22**. + +```nix +programs.ssh.extraConfig = '' + Host nix-builder + HostName nix-builder-hostname # if you are using Tailscale, this can just be the hostname of a device on your Tailscale network + Port 2222 +''; +``` + +And done, that is all for the ssh side of things. Next up, we need to configure +out builder to use the correct host. + +## Nix Builder Configuration + +Assuming you already have a remote builder configured, you will only need to +patch the `hostName` with the one on your `openssh.extraConfig`. + +```nix +nix.buildMachines = [{ + hostName = "nix-builder-hostname"; + sshUser = "nix-builder"; + sshKey = "/path/to/key"; + systems = ["x86_64-linux"]; + maxJobs = 2; + speedFactor = 2; + supportedFeatures = ["kvm"]; +}]; +``` + +If you have added the correct `hostName` and `sshUser`, the builder will be +picked up automatically on the next rebuild. + +### Home-Manager + +If you are using Home-Manager, you might also want to configure your +declarative ~/.config/ssh/config to use the new port. That can be achieved +through `programs.ssh.matchBlocks` option under Home-Manager + +```nix +programs.ssh.matchBlocks = { + "builder" = { + hostname = "nix-builder-hostname"; + user = "nix-builder"; + identityFile = "~/.ssh/builder-key"; + port = 2222; + }; +} +``` + +And that will be all. You are ready to use your new non-default port, mostly +safe from port scanners. diff --git a/nyx/docs/notes/2023-11-11-using-headscale.md b/nyx/docs/notes/2023-11-11-using-headscale.md new file mode 100644 index 0000000..82d41bd --- /dev/null +++ b/nyx/docs/notes/2023-11-11-using-headscale.md @@ -0,0 +1,88 @@ +# Notes for 11th of November, 2023 + +Today's main attraction is the Headscale setup on my VPS running NixOS, which +I've finally came around to self-host. + +There has been much talk about this new product called Tailscale recently +around the web, especially in the last few years. Tailscale is a VPN +service that makes the devices and applications we own accessible anywhere +using the open source WireGuard protocol to establish encrypted point-to-point +connections. I have been using Tailscale for a while now, but in an effort +to move all of my services to self-owned hardware some of my services have +been moved over to my NixOS server over time. + +Many of Tailscale’s components are open-source, especially its clients, but +the server remains closed-source. Tailscale is a SaaS product and monetization +naturally is a big concern, however, we care more about controlling our own data +than their attempts of monetization. + +This is where the (very appropriately named) Headscale comes in; Headscale is +an open-source, self-hosted implementation of the Tailscale control server. The +configuration is extremely straightforward, as Headscale will handle everything +for us. + +## Running Headscale + +Below is a simple configuration for the Headscale module of NixOS. + +```nix +services = let + domain = "example.com"; +in { + headscale = { + enable = true; + address = "0.0.0.0"; + port = 8085; + + settings = { + server_url = "https://tailscale.${domain}"; + + dns_config = { + override_local_dns = true; + base_domain = "${domain}"; + magic_dns = true; + domains = ["tailscale.${domain}"]; + nameservers = [ + "9.9.9.9" # no cloudflare, nice + ]; + }; + + ip_prefixes = [ + "100.64.0.0/10" + "fd7a:115c:a1e0::/48" + ]; + }; + }; +}; +``` + +## Using Headscale + +We must first create a user, which we can do with + +```console +headscale users create myUser +``` + +Then on the machine that will be our client, we need to login. + +```console +tailscale up --login-server tailscale.example.com # replace this URL with your own as configured abovea +``` + +Followed by registering the machine. + +```console +# machine key will be obtained visiting the URL that is returned from the above command +headscale --user myUser nodes register --key +``` + +And finally logging into your Tailnet using the URL and your machine key. + +```console +tailscale up --login-server https://tailscale.example.com --authkey +``` + +And all done! Now try connecting to one of your machines using the hostname now +to test if the connection is actually working. If anything goes wrong, make +sure to check your DNS settings: remember, it's always the DNS. diff --git a/nyx/docs/notes/README.md b/nyx/docs/notes/README.md new file mode 100644 index 0000000..3107fc7 --- /dev/null +++ b/nyx/docs/notes/README.md @@ -0,0 +1,29 @@ +# Notes + +Howdy! Welcome to my collection of notes. + +This is where I store my notes on topics and processes that I find particularly +difficult, obscure or otherwise interesting. Mostly on Linux and NixOS, +perhaps on programming in the future. + +If those notes helped you in any way, that is great! That means my time writing +those notes were well spent. If you were already a Nix/NixOS expert who somehow +found their way in here, and got really bored reading my notes then I only ask +that you point out my mistakes where you spot them. Your time will be very much +appreciated. + +If you are a reader looking for some pro tips, I would like to remind you that I +am not an expert in Nix or NixOS. My notes are limited by my own knowledge. +However, I would be happy to try and answer your questions nevertheless; and we +can try figuring out the answer together, should we both happen to be stuck. + +If you spot a mistake, please let me know and I would be happy to learn from you. +Thanks! + +| Date | Category | Description | +| ---------- | ---------- | -------------------------------------------------------------------------------------------------- | +| 22-01-2023 | Linux | My notes on a kernel parameter change affecting my backlight state | +| 14-03-2023 | Nix | Reproduction steps NixOS setup with ephemeral root using BTRFS subvolumes and full disk encryption | +| 07-06-2023 | Nix | Notes on extending or writing your own nixpkgs library to use in your configurations | +| 21-06-2023 | Nix/NextJS | A guide on serving statically exported and non-statically exported NextJS Webapps on NixOS | +| 14-07-2023 | Nix/NixOS | Notes on a potentially working distributed builds setup on NixOS with a non-default ssh port | diff --git a/nyx/docs/notes/cheatsheet.md b/nyx/docs/notes/cheatsheet.md new file mode 100644 index 0000000..4e0f025 --- /dev/null +++ b/nyx/docs/notes/cheatsheet.md @@ -0,0 +1,48 @@ +# Cheat sheet + +## Show GC roots + +```sh +nix-store --gc --print-roots | grep -v "" | column -t | sort -k3 -k1 +``` + +## List all packages + +```sh +nix-store -q --requisites /run/current-system | cut -d- -f2- | sort | uniq +``` + +You can add a `wc -l` at the end of the above command, but that will not be an accurate representation of +your package count, as the same package can be repeated with different versions. + +## Find biggest packages + +```sh +nix path-info -hsr /run/current-system/ | sort -hrk2 | head -n10 +``` + +## Find biggest closures (packages including dependencies) + +```sh +nix path-info -hSr /run/current-system/ | sort -hrk2 | head -n10 +``` + +## Show package dependencies as tree + +> Assuming `hello` is in PATH + +```sh +nix-store -q --tree $(realpath $(which hello)) +``` + +## Show package dependencies including size + +```sh +nix path-info -hSr nixpkgs#hello +``` + +## Show the things that will change on reboot + +```sh +diff <(nix-store -qR /run/current-system) <(nix-store -qR /run/booted-system) +``` diff --git a/nyx/docs/notes/yubikey-todo.md b/nyx/docs/notes/yubikey-todo.md new file mode 100644 index 0000000..becd1f2 --- /dev/null +++ b/nyx/docs/notes/yubikey-todo.md @@ -0,0 +1,8 @@ +# TODO + + + +## Resources + +- https://superuser.com/questions/1628782/gpg-signing-failed-no-pinentry +- https://superuser.com/questions/397149/can-you-gpg-sign-old-commits diff --git a/nyx/docs/shell.nix b/nyx/docs/shell.nix new file mode 100644 index 0000000..6c9bdb5 --- /dev/null +++ b/nyx/docs/shell.nix @@ -0,0 +1,8 @@ +{pkgs ? import {}}: +pkgs.mkShell { + packages = with pkgs; [ + pandoc + jq + sassc + ]; +} diff --git a/nyx/docs/templates/html/page.html b/nyx/docs/templates/html/page.html new file mode 100644 index 0000000..09454b6 --- /dev/null +++ b/nyx/docs/templates/html/page.html @@ -0,0 +1,127 @@ + + + + + + + $for(author-meta)$ + + $endfor$ $if(date-meta)$ + + $endif$ $if(keywords)$ + + $endif$ $if(description-meta)$ + + $endif$ + $title$ + + $for(css)$ + + $endfor$ + + + + + + + + + + +
+ + +
+ +
+ $if(toc)$ + + $endif$ $body$ $for(include-after)$ $include-after$ $endfor$ +
+ + + + diff --git a/nyx/docs/templates/pandoc/custom.theme b/nyx/docs/templates/pandoc/custom.theme new file mode 100644 index 0000000..8180100 --- /dev/null +++ b/nyx/docs/templates/pandoc/custom.theme @@ -0,0 +1,212 @@ +{ + "text-color": "#C3CBE9", + "background-color": null, + "line-number-color": null, + "line-number-background-color": null, + "text-styles": { + "Alert": { + "text-color": "#ffcfaf", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Annotation": { + "text-color": "#7f9f7f", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Attribute": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "BaseN": { + "text-color": "#dca3a3", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "BuiltIn": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Char": { + "text-color": "#dca3a3", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Comment": { + "text-color": "#7f9f7f", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "CommentVar": { + "text-color": "#7f9f7f", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Constant": { + "text-color": "#dca3a3", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "ControlFlow": { + "text-color": "#f0dfaf", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "DataType": { + "text-color": "#dfdfbf", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "DecVal": { + "text-color": "#dcdccc", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Documentation": { + "text-color": "#7f9f7f", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Error": { + "text-color": "#c3bf9f", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Extension": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Float": { + "text-color": "#c0bed1", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Function": { + "text-color": "#efef8f", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Import": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Information": { + "text-color": "#7f9f7f", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Keyword": { + "text-color": "#f0dfaf", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Operator": { + "text-color": "#f0efd0", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Other": { + "text-color": "#efef8f", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Preprocessor": { + "text-color": "#ffcfaf", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "SpecialChar": { + "text-color": "#dca3a3", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "SpecialString": { + "text-color": "#cc9393", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "String": { + "text-color": "#cc9393", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Variable": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "VerbatimString": { + "text-color": "#cc9393", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Warning": { + "text-color": "#7f9f7f", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + } + } +} + diff --git a/nyx/docs/templates/scss/base.scss b/nyx/docs/templates/scss/base.scss new file mode 100644 index 0000000..e8f3256 --- /dev/null +++ b/nyx/docs/templates/scss/base.scss @@ -0,0 +1,178 @@ +*, +::before, +::after { + box-sizing: border-box; +} + +// Base styles +h1 { + font-family: $font-family-secondary; + line-height: 1.15; +} + +body { + font-size: 20px; + line-height: 1.5; + font-family: $font-family-primary; + margin: 0; + padding: 0; + background-color: $primary; + display: flex; + flex-direction: column; + min-height: 100vh; + + @media (max-width: $screen-tablet) { + font-size: 18px; + } +} + +header { + background-color: $primary; + color: $secondary; + padding: 10px 25px; + display: flex; + justify-content: space-between; + align-items: center; + max-width: 80ch; + width: 100%; + margin: 0 auto; + + @media (max-width: $screen-tablet) { + font-size: 14px; + padding: 8px 4px; + } +} + +nav { + ul { + list-style-type: none; + margin: 0; + padding: 0; + display: flex; + + li { + a { + color: $secondary; + text-decoration: none; + } + } + } +} + +main { + text-align: left; + color: $secondary; + padding: 10px 30px; + flex: 1; + margin: 0 auto; + max-width: Min(80ch, 100%); + + a { + &:hover, + &:link, + &:visited, + &:active { + color: $hover-color; + text-decoration: none; + } + } + + @media (max-width: $screen-tablet) { + padding: 12px; + } +} + +// Buttons +/* +.primary-buttons, +.secondary-buttons, +*/ +.dropbtn, +.nav-button { + font-weight: 800; + background-color: $primary; + color: $secondary; + cursor: pointer; + font-weight: 800; + background-color: $primary; + color: $secondary; + cursor: pointer; + font-weight: 800; + font-family: "Roboto Slab", Roboto, Arial, sans-serif; + font-size: 20px; + line-height: 1.5; + border: none; + align-items: center; + margin: 0px 5px; + + &:hover { + color: lighten($secondary, 5%); + } +} + +// Dropdown Button +.dropbtn:hover { + color: lighten($secondary, 5%); +} + +.dropdown { + position: relative; + display: inline-block; + + .dropdown-content { + display: none; + position: absolute; + background-color: $primary; + min-width: 240px; + box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); + z-index: 1; + + a { + color: $secondary; + padding: 12px 16px; + text-decoration: none; + display: block; + + &:hover { + background-color: #2b282d; + } + } + } + + &:hover .dropdown-content { + display: block; + } +} + +main aside { + overflow: scroll; +} + +// Footer Styles +footer { + color: white; + padding: 7px 5px 7px 5px; + text-align: center; + margin-top: auto; + position: relative; + + .footer-divider { + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%); + width: 20%; + height: 1px; + background-color: white; + } + + .footer-icons { + margin: 15px 5px; + + a { + color: white; + text-decoration: none; + margin-bottom: 5px; + } + } +} diff --git a/nyx/docs/templates/scss/components/code.scss b/nyx/docs/templates/scss/components/code.scss new file mode 100644 index 0000000..73c56fc --- /dev/null +++ b/nyx/docs/templates/scss/components/code.scss @@ -0,0 +1,9 @@ +div.sourceCode { + border: 1px solid #3b373d; + padding: 8px; + text-align: left; + background-color: lighten($primary, 3%); + overflow: scroll; + max-width: 100%; + border-radius: 8px; +} diff --git a/nyx/docs/templates/scss/components/table.scss b/nyx/docs/templates/scss/components/table.scss new file mode 100644 index 0000000..4bf4caf --- /dev/null +++ b/nyx/docs/templates/scss/components/table.scss @@ -0,0 +1,21 @@ +table { + border-collapse: collapse; + width: 100%; + margin: 30px 0px; + + th, + td { + border: 1px solid #3b373d; + padding: 8px; + text-align: left; + } + + th { + background-color: #141215; + color: white; + } + + tr:nth-child(even) { + background-color: #2b282d; + } +} diff --git a/nyx/docs/templates/scss/components/toc.scss b/nyx/docs/templates/scss/components/toc.scss new file mode 100644 index 0000000..14b44b7 --- /dev/null +++ b/nyx/docs/templates/scss/components/toc.scss @@ -0,0 +1,30 @@ +// Table Of Content element injected by Pandoc +#TOC { + // better spacing + margin: 20px; + padding: 10px; + + // TOC elements are considered links + // so the below styling applies to all items + a { + text-decoration: none; + color: $secondary; + + &:hover { + color: lighten($secondary, 5%); + } + } + + // make sure all items are properly aligned in separate lines + li, + ul { + list-style-type: square; + margin-left: 20px; + display: block; + } + + // hide the TOC on mobile devices + @media screen and (max-width: 768px) { + display: none; + } +} diff --git a/nyx/docs/templates/scss/main.scss b/nyx/docs/templates/scss/main.scss new file mode 100644 index 0000000..3c04e33 --- /dev/null +++ b/nyx/docs/templates/scss/main.scss @@ -0,0 +1,6 @@ +@import "modern-normalize.css"; +@import "variables"; +@import "base"; +@import "components/toc"; +@import "components/table"; +@import "components/code"; diff --git a/nyx/docs/templates/scss/variables.scss b/nyx/docs/templates/scss/variables.scss new file mode 100644 index 0000000..3b2ec66 --- /dev/null +++ b/nyx/docs/templates/scss/variables.scss @@ -0,0 +1,7 @@ +// Define variables for colors and fonts +$primary: #17181c; +$secondary: #dee2e6; +$hover-color: #66b3ff; +$font-family-primary: "Roboto Slab", Roboto, Arial, sans-serif; +$font-family-secondary: "Courier Prime", Roboto, Arial, serif; +$screen-tablet: 768px; diff --git a/nyx/flake.lock b/nyx/flake.lock new file mode 100644 index 0000000..e06ad31 --- /dev/null +++ b/nyx/flake.lock @@ -0,0 +1,4245 @@ +{ + "nodes": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems" + }, + "locked": { + "lastModified": 1712079060, + "narHash": "sha256-/JdiT9t+zzjChc5qQiF+jhrVhRt8figYH29rZO7pFe4=", + "owner": "ryantm", + "repo": "agenix", + "rev": "1381a759b205dff7a6818733118d02253340fd5e", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "ags": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1712654220, + "narHash": "sha256-Napjcjf8ai5PSWIoAnAh+YCeSVZMduVKBWOsTsq6f5Y=", + "owner": "Aylur", + "repo": "ags", + "rev": "d0ebc14b89cbead9f76ab87e12fddab37afe9cb6", + "type": "github" + }, + "original": { + "owner": "Aylur", + "repo": "ags", + "type": "github" + } + }, + "air-quality-monitor": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": [ + "nixpkgs-small" + ] + }, + "locked": { + "lastModified": 1701228999, + "narHash": "sha256-4rf8KkYI1qSgpDl+0pETK5sDxDOdkCzgU0100QcNGYs=", + "owner": "NotAShelf", + "repo": "air-quality-monitor", + "rev": "f13b8bc45da53c41d59f49cc4549100b2cbf156a", + "type": "github" + }, + "original": { + "owner": "NotAShelf", + "repo": "air-quality-monitor", + "type": "github" + } + }, + "alpha-nvim": { + "flake": false, + "locked": { + "lastModified": 1708891191, + "narHash": "sha256-kTVPKZ/e1us/uHfSwFwR38lFYN8EotJq2jKz6xm/eqg=", + "owner": "goolord", + "repo": "alpha-nvim", + "rev": "41283fb402713fc8b327e60907f74e46166f4cfd", + "type": "github" + }, + "original": { + "owner": "goolord", + "repo": "alpha-nvim", + "type": "github" + } + }, + "anyrun": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1712136515, + "narHash": "sha256-LpjQJYC24S5P5XhJsZX6HqsQT1pohcFzM6N42I6qo/U=", + "owner": "Kirottu", + "repo": "anyrun", + "rev": "be6728884d543665e7bd137bbef62dc1d04a210b", + "type": "github" + }, + "original": { + "owner": "Kirottu", + "repo": "anyrun", + "type": "github" + } + }, + "anyrun-nixos-options": { + "inputs": { + "flake-parts": [ + "flake-parts" + ], + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1704902043, + "narHash": "sha256-YL5ANmzWJAe3IhsuqTccxZIdkQX0tYt9dt9oNw0QwAY=", + "owner": "n3oney", + "repo": "anyrun-nixos-options", + "rev": "aed824957538e65dc3bea414aadbe5e2de611f49", + "type": "github" + }, + "original": { + "owner": "n3oney", + "repo": "anyrun-nixos-options", + "type": "github" + } + }, + "atticd": { + "inputs": { + "crane": "crane", + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs-small" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1711742460, + "narHash": "sha256-0O4v6e4a1toxXZ2gf5INhg4WPE5C5T+SVvsBt+45Mcc=", + "owner": "zhaofengli", + "repo": "attic", + "rev": "4dbdbee45728d8ce5788db6461aaaa89d98081f0", + "type": "github" + }, + "original": { + "owner": "zhaofengli", + "repo": "attic", + "type": "github" + } + }, + "blobs": { + "flake": false, + "locked": { + "lastModified": 1604995301, + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "type": "gitlab" + } + }, + "bufdelete-nvim": { + "flake": false, + "locked": { + "lastModified": 1708814161, + "narHash": "sha256-ljUNfmpImtxFCS19HC9kFlaLlqaPDltKtnx1+/6Y33U=", + "owner": "famiu", + "repo": "bufdelete.nvim", + "rev": "f6bcea78afb3060b198125256f897040538bcb81", + "type": "github" + }, + "original": { + "owner": "famiu", + "repo": "bufdelete.nvim", + "type": "github" + } + }, + "catppuccin": { + "flake": false, + "locked": { + "lastModified": 1711706907, + "narHash": "sha256-GQjxE8lQj52pheJtHCS+9v2lsJY7wMj2IXVCoNRmQSQ=", + "owner": "catppuccin", + "repo": "nvim", + "rev": "aebe43db9cb26e1c70fc5b2fd4158169c405e720", + "type": "github" + }, + "original": { + "owner": "catppuccin", + "repo": "nvim", + "type": "github" + } + }, + "ccc": { + "flake": false, + "locked": { + "lastModified": 1711976559, + "narHash": "sha256-rSOjeklOdIPQvxNfUBG9Hm001cIlBgrPYcnm7afc9TE=", + "owner": "uga-rosa", + "repo": "ccc.nvim", + "rev": "46b8a38a3bc287f27789800d3d26480d093d65b5", + "type": "github" + }, + "original": { + "owner": "uga-rosa", + "repo": "ccc.nvim", + "type": "github" + } + }, + "cellular-automaton": { + "flake": false, + "locked": { + "lastModified": 1693589931, + "narHash": "sha256-szbd6m7hH7NFI0UzjWF83xkpSJeUWCbn9c+O8F8S/Fg=", + "owner": "Eandrju", + "repo": "cellular-automaton.nvim", + "rev": "b7d056dab963b5d3f2c560d92937cb51db61cb5b", + "type": "github" + }, + "original": { + "owner": "Eandrju", + "repo": "cellular-automaton.nvim", + "type": "github" + } + }, + "cheatsheet-nvim": { + "flake": false, + "locked": { + "lastModified": 1640255456, + "narHash": "sha256-TYkGB7cON2t4GwMaR9H1MDG2j3btBv2AR37ade8kqTY=", + "owner": "sudormrfbin", + "repo": "cheatsheet.nvim", + "rev": "9716f9aaa94dd1fd6ce59b5aae0e5f25e2a463ef", + "type": "github" + }, + "original": { + "owner": "sudormrfbin", + "repo": "cheatsheet.nvim", + "type": "github" + } + }, + "cinnamon-nvim": { + "flake": false, + "locked": { + "lastModified": 1711005384, + "narHash": "sha256-LNikkGldBpUsfyH8ThtX7RS1p/z3JzSPonT9qUU84jw=", + "owner": "declancm", + "repo": "cinnamon.nvim", + "rev": "559fe02fae00ffd78377e9c242b2faa25a428592", + "type": "github" + }, + "original": { + "owner": "declancm", + "repo": "cinnamon.nvim", + "type": "github" + } + }, + "cmp-buffer": { + "flake": false, + "locked": { + "lastModified": 1660101488, + "narHash": "sha256-dG4U7MtnXThoa/PD+qFtCt76MQ14V1wX8GMYcvxEnbM=", + "owner": "hrsh7th", + "repo": "cmp-buffer", + "rev": "3022dbc9166796b644a841a02de8dd1cc1d311fa", + "type": "github" + }, + "original": { + "owner": "hrsh7th", + "repo": "cmp-buffer", + "type": "github" + } + }, + "cmp-nvim-lsp": { + "flake": false, + "locked": { + "lastModified": 1702205473, + "narHash": "sha256-/0sh9vJBD9pUuD7q3tNSQ1YLvxFMNykdg5eG+LjZAA8=", + "owner": "hrsh7th", + "repo": "cmp-nvim-lsp", + "rev": "5af77f54de1b16c34b23cba810150689a3a90312", + "type": "github" + }, + "original": { + "owner": "hrsh7th", + "repo": "cmp-nvim-lsp", + "type": "github" + } + }, + "cmp-path": { + "flake": false, + "locked": { + "lastModified": 1664784283, + "narHash": "sha256-thppiiV3wjIaZnAXmsh7j3DUc6ceSCvGzviwFUnoPaI=", + "owner": "hrsh7th", + "repo": "cmp-path", + "rev": "91ff86cd9c29299a64f968ebb45846c485725f23", + "type": "github" + }, + "original": { + "owner": "hrsh7th", + "repo": "cmp-path", + "type": "github" + } + }, + "cmp-treesitter": { + "flake": false, + "locked": { + "lastModified": 1702163214, + "narHash": "sha256-K7F9iqmB13ONenwsbaND8F4010MvHQXp7DxMFfcsZ4A=", + "owner": "ray-x", + "repo": "cmp-treesitter", + "rev": "13e4ef8f4dd5639fca2eb9150e68f47639a9b37d", + "type": "github" + }, + "original": { + "owner": "ray-x", + "repo": "cmp-treesitter", + "type": "github" + } + }, + "cmp-vsnip": { + "flake": false, + "locked": { + "lastModified": 1669100283, + "narHash": "sha256-2mkN03noOr5vBvRbSb35xZKorSH+8savQNZtgM9+QcM=", + "owner": "hrsh7th", + "repo": "cmp-vsnip", + "rev": "989a8a73c44e926199bfd05fa7a516d51f2d2752", + "type": "github" + }, + "original": { + "owner": "hrsh7th", + "repo": "cmp-vsnip", + "type": "github" + } + }, + "codewindow-nvim": { + "flake": false, + "locked": { + "lastModified": 1695487629, + "narHash": "sha256-/u2Zjbd9m3/iJU3I3HzFzXWxuvoycwJoIq7UFeHNtKM=", + "owner": "gorbit99", + "repo": "codewindow.nvim", + "rev": "8c8f5ff66e123491c946c04848d744fcdc7cac6c", + "type": "github" + }, + "original": { + "owner": "gorbit99", + "repo": "codewindow.nvim", + "type": "github" + } + }, + "comment-nvim": { + "flake": false, + "locked": { + "lastModified": 1691409559, + "narHash": "sha256-+dF1ZombrlO6nQggufSb0igXW5zwU++o0W/5ZA07cdc=", + "owner": "numToStr", + "repo": "Comment.nvim", + "rev": "0236521ea582747b58869cb72f70ccfa967d2e89", + "type": "github" + }, + "original": { + "owner": "numToStr", + "repo": "Comment.nvim", + "type": "github" + } + }, + "copilot-cmp": { + "flake": false, + "locked": { + "lastModified": 1694286652, + "narHash": "sha256-srgNohm/aJpswNJ5+T7p+zi9Jinp9e5FA8/wdk6VRiY=", + "owner": "zbirenbaum", + "repo": "copilot-cmp", + "rev": "72fbaa03695779f8349be3ac54fa8bd77eed3ee3", + "type": "github" + }, + "original": { + "owner": "zbirenbaum", + "repo": "copilot-cmp", + "type": "github" + } + }, + "copilot-lua": { + "flake": false, + "locked": { + "lastModified": 1709095198, + "narHash": "sha256-JX3sdsnOnjkY7r9fCtC2oauo0PXF3SQ+SHUo8ifBvAc=", + "owner": "zbirenbaum", + "repo": "copilot.lua", + "rev": "f7612f5af4a7d7615babf43ab1e67a2d790c13a6", + "type": "github" + }, + "original": { + "owner": "zbirenbaum", + "repo": "copilot.lua", + "type": "github" + } + }, + "crane": { + "inputs": { + "nixpkgs": [ + "atticd", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1702918879, + "narHash": "sha256-tWJqzajIvYcaRWxn+cLUB9L9Pv4dQ3Bfit/YjU5ze3g=", + "owner": "ipetkov", + "repo": "crane", + "rev": "7195c00c272fdd92fc74e7d5a0a2844b9fadb2fb", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "crane_2": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1711299236, + "narHash": "sha256-6/JsyozOMKN8LUGqWMopKTSiK8N79T8Q+hcxu2KkTXg=", + "owner": "ipetkov", + "repo": "crane", + "rev": "880573f80d09e18a11713f402b9e6172a085449f", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "crane_3": { + "inputs": { + "nixpkgs": [ + "schizofox", + "searx-randomizer", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1701386725, + "narHash": "sha256-w4aBlMYh9Y8co1V80m5LzEKMijUJ7CBTq209WbqVwUU=", + "owner": "ipetkov", + "repo": "crane", + "rev": "8b9bad9b30bd7a9ed08782e64846b7485f9d0a38", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "crates-nvim": { + "flake": false, + "locked": { + "lastModified": 1710361360, + "narHash": "sha256-wfwSHuP05PEqCbpEG7GStGElMLkrDEbPW7V6p1EANGU=", + "owner": "Saecki", + "repo": "crates.nvim", + "rev": "b4f4987ccdb1cc3899ee541ef4375c73c48c4570", + "type": "github" + }, + "original": { + "owner": "Saecki", + "repo": "crates.nvim", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1700795494, + "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "dashboard-nvim": { + "flake": false, + "locked": { + "lastModified": 1712122933, + "narHash": "sha256-s2PDyOnE3jVk+RCp0aaV2vVJGkO394iDhQTEHRcb9kY=", + "owner": "glepnir", + "repo": "dashboard-nvim", + "rev": "7c0c09d55118a2afeb8874e885f87ae80d8ff452", + "type": "github" + }, + "original": { + "owner": "glepnir", + "repo": "dashboard-nvim", + "type": "github" + } + }, + "deploy-rs": { + "inputs": { + "flake-compat": "flake-compat_2", + "nixpkgs": "nixpkgs_4", + "utils": "utils" + }, + "locked": { + "lastModified": 1711973905, + "narHash": "sha256-UFKME/N1pbUtn+2Aqnk+agUt8CekbpuqwzljivfIme8=", + "owner": "serokell", + "repo": "deploy-rs", + "rev": "88b3059b020da69cbe16526b8d639bd5e0b51c8b", + "type": "github" + }, + "original": { + "owner": "serokell", + "repo": "deploy-rs", + "type": "github" + } + }, + "devshell": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1711099426, + "narHash": "sha256-HzpgM/wc3aqpnHJJ2oDqPBkNsqWbW0WfWUO8lKu8nGk=", + "owner": "numtide", + "repo": "devshell", + "rev": "2d45b54ca4a183f2fdcf4b19c895b64fbf620ee8", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "diffview-nvim": { + "flake": false, + "locked": { + "lastModified": 1700506468, + "narHash": "sha256-3EdnBUka9Rh5Brl6TWpN6GlD9z32mmY3Ip+wyiKob/8=", + "owner": "sindrets", + "repo": "diffview.nvim", + "rev": "3dc498c9777fe79156f3d32dddd483b8b3dbd95f", + "type": "github" + }, + "original": { + "owner": "sindrets", + "repo": "diffview.nvim", + "type": "github" + } + }, + "dirt-samples-src": { + "flake": false, + "locked": { + "lastModified": 1667426233, + "narHash": "sha256-Zl2bi9QofcrhU63eMtg+R6lhV9ExQS/0XNTJ+oq65Uo=", + "owner": "tidalcycles", + "repo": "dirt-samples", + "rev": "92f2145e661b397e62ca0ff3965819e7c7db0dad", + "type": "github" + }, + "original": { + "owner": "tidalcycles", + "ref": "master", + "repo": "dirt-samples", + "type": "github" + } + }, + "dracula": { + "flake": false, + "locked": { + "lastModified": 1708834650, + "narHash": "sha256-I3rtbJYv1D+kniOLL9hmTF3ucp/qSNewnO2GmYAERko=", + "owner": "Mofiqul", + "repo": "dracula.nvim", + "rev": "8d8bddb8814c3e7e62d80dda65a9876f97eb699c", + "type": "github" + }, + "original": { + "owner": "Mofiqul", + "repo": "dracula.nvim", + "type": "github" + } + }, + "dressing-nvim": { + "flake": false, + "locked": { + "lastModified": 1710299803, + "narHash": "sha256-9AwOFTRvhWFo7USgoFYfceiojZM62IXPpBs8CnSqc18=", + "owner": "stevearc", + "repo": "dressing.nvim", + "rev": "18e5beb3845f085b6a33c24112b37988f3f93c06", + "type": "github" + }, + "original": { + "owner": "stevearc", + "repo": "dressing.nvim", + "type": "github" + } + }, + "elixir-ls": { + "flake": false, + "locked": { + "lastModified": 1711286188, + "narHash": "sha256-OIB5f+FBOPsTWKGWyoU+/NQDMsJXBdj1v7UclbTP5ZY=", + "owner": "elixir-lsp", + "repo": "elixir-ls", + "rev": "3e71900e0d0891f9f95e35d9a52b16c6a773a259", + "type": "github" + }, + "original": { + "owner": "elixir-lsp", + "repo": "elixir-ls", + "type": "github" + } + }, + "elixir-tools": { + "flake": false, + "locked": { + "lastModified": 1710172806, + "narHash": "sha256-pVDeS9oCFzA9t9J/JfYG/RfdMoSmaaERd5nUgL9KHyM=", + "owner": "elixir-tools", + "repo": "elixir-tools.nvim", + "rev": "4d003f4b41ab9b4f8b569104fa7818f048ed4e25", + "type": "github" + }, + "original": { + "owner": "elixir-tools", + "repo": "elixir-tools.nvim", + "type": "github" + } + }, + "fidget-nvim": { + "flake": false, + "locked": { + "lastModified": 1710942727, + "narHash": "sha256-8pBg8uQto5UzNBRhjFFMMmWLnmpYsG0L1mDa+FN8tpU=", + "owner": "j-hui", + "repo": "fidget.nvim", + "rev": "933db4596e4bab1b09b6d48a10e21819e4cc458f", + "type": "github" + }, + "original": { + "owner": "j-hui", + "repo": "fidget.nvim", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_10": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_3": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_4": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_5": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_6": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_7": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_8": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_9": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1698882062, + "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "anyrun", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1696343447, + "narHash": "sha256-B2xAZKLkkeRFG5XcHHSXXcP7To9Xzr59KXeZiRf4vdQ=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "c9afaba3dfa4085dbd2ccb38dfade5141e33d9d4", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_4": { + "inputs": { + "nixpkgs-lib": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709336216, + "narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_5": { + "inputs": { + "nixpkgs-lib": [ + "neovim-nightly", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_6": { + "inputs": { + "nixpkgs-lib": [ + "neovim-nightly", + "hercules-ci-effects", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709336216, + "narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, + "flake-parts_7": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_2" + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_8": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_3" + }, + "locked": { + "lastModified": 1698882062, + "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_4" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_4": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_5": { + "inputs": { + "systems": "systems_10" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_6": { + "inputs": { + "systems": "systems_11" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_7": { + "inputs": { + "systems": "systems_13" + }, + "locked": { + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flutter-tools": { + "flake": false, + "locked": { + "lastModified": 1711622317, + "narHash": "sha256-TQRz2MHg6qnzZGUDVFUoaZJiTBwQ3Hjqvc8AAeVS93Y=", + "owner": "akinsho", + "repo": "flutter-tools.nvim", + "rev": "4f18033c3b78aa5450e538d81dfbbb3e67aeadec", + "type": "github" + }, + "original": { + "owner": "akinsho", + "repo": "flutter-tools.nvim", + "type": "github" + } + }, + "gesture-nvim": { + "flake": false, + "locked": { + "lastModified": 1704802204, + "narHash": "sha256-vAky7yvPw2ZmS0i268eKCpUp75bylNGA+ckvhuWVKgc=", + "owner": "notomo", + "repo": "gesture.nvim", + "rev": "5124a05debd62326cc899a35a09862a675d7f3da", + "type": "github" + }, + "original": { + "owner": "notomo", + "repo": "gesture.nvim", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "pre-commit-hooks-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitsigns-nvim": { + "flake": false, + "locked": { + "lastModified": 1712162672, + "narHash": "sha256-uEHuKccCAYpLGVJovz2PY2Q7THA47z8TA5CHWexBv3E=", + "owner": "lewis6991", + "repo": "gitsigns.nvim", + "rev": "b45ff86f5618d1421a88c12d4feb286b80a1e2d3", + "type": "github" + }, + "original": { + "owner": "lewis6991", + "repo": "gitsigns.nvim", + "type": "github" + } + }, + "glow-nvim": { + "flake": false, + "locked": { + "lastModified": 1703345545, + "narHash": "sha256-GsNcASzVvY0066kak2nvUY5luzanoBclqcUOsODww8g=", + "owner": "ellisonleao", + "repo": "glow.nvim", + "rev": "238070a686c1da3bccccf1079700eb4b5e19aea4", + "type": "github" + }, + "original": { + "owner": "ellisonleao", + "repo": "glow.nvim", + "type": "github" + } + }, + "gruvbox": { + "flake": false, + "locked": { + "lastModified": 1706538659, + "narHash": "sha256-jWnrRy/PT7D0UcPGL+XTbKHWvS0ixvbyqPtTzG9HY84=", + "owner": "ellisonleao", + "repo": "gruvbox.nvim", + "rev": "6e4027ae957cddf7b193adfaec4a8f9e03b4555f", + "type": "github" + }, + "original": { + "owner": "ellisonleao", + "repo": "gruvbox.nvim", + "type": "github" + } + }, + "hercules-ci-effects": { + "inputs": { + "flake-parts": "flake-parts_6", + "nixpkgs": [ + "neovim-nightly", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1710478346, + "narHash": "sha256-Xjf8BdnQG0tLhPMlqQdwCIjOp7Teox0DP3N/jjyiGM4=", + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "rev": "64e7763d72c1e4c1e5e6472640615b6ae2d40fbf", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "type": "github" + } + }, + "hercules-ci-effects_2": { + "inputs": { + "flake-parts": [ + "nixpak", + "flake-parts" + ], + "nixpkgs": [ + "nixpak", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1704029560, + "narHash": "sha256-a4Iu7x1OP+uSYpqadOu8VCPY+MPF3+f6KIi+MAxlgyw=", + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "rev": "d5cbf433a6ae9cae05400189a8dbc6412a03ba16", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "type": "github" + } + }, + "highlight-undo": { + "flake": false, + "locked": { + "lastModified": 1695227852, + "narHash": "sha256-I1AwVYqpJNA3K1AwGy/VgPnbrYvX19qfI9bQFZNu1SU=", + "owner": "tzachar", + "repo": "highlight-undo.nvim", + "rev": "50a6884a8476be04ecce8f1c4ed692c5000ef0a1", + "type": "github" + }, + "original": { + "owner": "tzachar", + "repo": "highlight-undo.nvim", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712645849, + "narHash": "sha256-67v20E0gH7nvAaMsah2oRIocnxGO25fATUyzQHIywxQ=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "40a99619da804a78a0b166e5c6911108c059c3a8", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "schizofox", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1708591310, + "narHash": "sha256-8mQGVs8JccWTnORgoLOTh9zvf6Np+x2JzhIc+LDcJ9s=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "0e0e9669547e45ea6cca2de4044c1a384fd0fe55", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "hop-nvim": { + "flake": false, + "locked": { + "lastModified": 1694283445, + "narHash": "sha256-SnuFeD/lrMxKtpBRPgIwdG0kVF7BWe02PiV7URVDASI=", + "owner": "phaazon", + "repo": "hop.nvim", + "rev": "1a1eceafe54b5081eae4cb91c723abd1d450f34b", + "type": "github" + }, + "original": { + "owner": "phaazon", + "repo": "hop.nvim", + "type": "github" + } + }, + "hyprcursor": { + "inputs": { + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1712434681, + "narHash": "sha256-qwmR2p1oc48Bj7gUDvb1oGL19Rjs2PmEmk4ChV01A5o=", + "owner": "hyprwm", + "repo": "hyprcursor", + "rev": "818d8c4b69e0997483d60b75f701fe14b561a7a3", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprcursor", + "type": "github" + } + }, + "hyprland": { + "inputs": { + "hyprcursor": "hyprcursor", + "hyprland-protocols": "hyprland-protocols", + "hyprlang": "hyprlang", + "nixpkgs": "nixpkgs_5", + "systems": "systems_5", + "wlroots": "wlroots", + "xdph": "xdph" + }, + "locked": { + "lastModified": 1712676164, + "narHash": "sha256-CDxfxIUTu+2nkLjq46LWHa98WB85AcdglURwi5obgAM=", + "owner": "hyprwm", + "repo": "Hyprland", + "rev": "1343aa865d04d80313b0e674c28ecfdbeb90e876", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "Hyprland", + "type": "github" + } + }, + "hyprland-contrib": { + "inputs": { + "nixpkgs": [ + "nixpkgs-small" + ] + }, + "locked": { + "lastModified": 1712505318, + "narHash": "sha256-fzlBLhXUN6y7mzEtcGNRDXxFakBEfaj4Bmj5PuoCNaM=", + "owner": "hyprwm", + "repo": "contrib", + "rev": "5870244b592c22558b658dbaf94f9e41afb0316f", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "contrib", + "type": "github" + } + }, + "hyprland-plugins": { + "inputs": { + "hyprland": [ + "hyprland" + ], + "systems": [ + "hyprland-plugins", + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1712420644, + "narHash": "sha256-h2X8qhN5RKYQXzT1kxKgUz1u1QthqOrP9xk800mTM6E=", + "owner": "hyprwm", + "repo": "hyprland-plugins", + "rev": "5ec0140d4aeca42b8a33e7f335f979e376d1b549", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-plugins", + "type": "github" + } + }, + "hyprland-protocols": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1691753796, + "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", + "owner": "hyprwm", + "repo": "hyprland-protocols", + "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-protocols", + "type": "github" + } + }, + "hyprland-protocols_2": { + "inputs": { + "nixpkgs": [ + "xdg-portal-hyprland", + "nixpkgs" + ], + "systems": [ + "xdg-portal-hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1691753796, + "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", + "owner": "hyprwm", + "repo": "hyprland-protocols", + "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-protocols", + "type": "github" + } + }, + "hyprlang": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1711671891, + "narHash": "sha256-C/Wwsy/RLxHP1axFFl+AnwJRWfd8gxDKKoa8nt8Qk3c=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "c1402612146ba06606ebf64963a02bc1efe11e74", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprlang_2": { + "inputs": { + "nixpkgs": "nixpkgs_6", + "systems": "systems_6" + }, + "locked": { + "lastModified": 1711250455, + "narHash": "sha256-LSq1ZsTpeD7xsqvlsepDEelWRDtAhqwetp6PusHXJRo=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "b3e430f81f3364c5dd1a3cc9995706a4799eb3fa", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprlang_3": { + "inputs": { + "nixpkgs": [ + "xdg-portal-hyprland", + "nixpkgs" + ], + "systems": "systems_14" + }, + "locked": { + "lastModified": 1708681732, + "narHash": "sha256-ULZZLZ9C33G13IaXLuAc4oTzHUvnATI8Fj2u6gzMfT0=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "f4466367ef0a92a6425d482050dc2b8840c0e644", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprpaper": { + "inputs": { + "hyprlang": "hyprlang_2", + "nixpkgs": "nixpkgs_7", + "systems": "systems_7" + }, + "locked": { + "lastModified": 1712639354, + "narHash": "sha256-HJHML1N4vgQQK+bfptbP42b6bmS9b8BTKKOPsifomaw=", + "owner": "hyprwm", + "repo": "hyprpaper", + "rev": "07e8e6cfd9d47697a2ee0543a2d653eb4d3f7165", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprpaper", + "type": "github" + } + }, + "hyprpicker": { + "inputs": { + "nixpkgs": "nixpkgs_8" + }, + "locked": { + "lastModified": 1711283076, + "narHash": "sha256-Cda+XbHpvyz3HhdJ7FlXFoaazOWtdBoOWmEaj4ZFwRM=", + "owner": "hyprwm", + "repo": "hyprpicker", + "rev": "0eb49192a5cdd5e6e8e6c2c82c33857d78d6cd56", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprpicker", + "type": "github" + } + }, + "icon-picker-nvim": { + "flake": false, + "locked": { + "lastModified": 1704321319, + "narHash": "sha256-VZKsVeSmPR3AA8267Mtd5sSTZl2CAqnbgqceCptgp4w=", + "owner": "ziontee113", + "repo": "icon-picker.nvim", + "rev": "3ee9a0ea9feeef08ae35e40c8be6a2fa2c20f2d3", + "type": "github" + }, + "original": { + "owner": "ziontee113", + "repo": "icon-picker.nvim", + "type": "github" + } + }, + "image-nvim": { + "flake": false, + "locked": { + "lastModified": 1711809713, + "narHash": "sha256-4xsyVDZOFidvLqwfWRB7BPMOejWk3/uhsnUsCNG/hpU=", + "owner": "3rd", + "repo": "image.nvim", + "rev": "a0b756d589c1623ebbfe344666e6d7c49bdc9d71", + "type": "github" + }, + "original": { + "owner": "3rd", + "repo": "image.nvim", + "type": "github" + } + }, + "impermanence": { + "locked": { + "lastModified": 1708968331, + "narHash": "sha256-VUXLaPusCBvwM3zhGbRIJVeYluh2uWuqtj4WirQ1L9Y=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "a33ef102a02ce77d3e39c25197664b7a636f9c30", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "indent-blankline": { + "flake": false, + "locked": { + "lastModified": 1710388427, + "narHash": "sha256-Xp8ZQBz0in2MX3l0bnLUsSbH0lDPE+QvdmFpBFry5yY=", + "owner": "lukas-reineke", + "repo": "indent-blankline.nvim", + "rev": "3d08501caef2329aba5121b753e903904088f7e6", + "type": "github" + }, + "original": { + "owner": "lukas-reineke", + "repo": "indent-blankline.nvim", + "type": "github" + } + }, + "kommentary": { + "flake": false, + "locked": { + "lastModified": 1701264889, + "narHash": "sha256-lpa3o42jieVKqs+ZCU8HBqWsoqoc53JKMmCNmIJ0rH0=", + "owner": "b3nj5m1n", + "repo": "kommentary", + "rev": "d5a111a3bc4109a8f913a5863c9092b3b3801482", + "type": "github" + }, + "original": { + "owner": "b3nj5m1n", + "repo": "kommentary", + "type": "github" + } + }, + "lanzaboote": { + "inputs": { + "crane": "crane_2", + "flake-compat": [ + "flake-compat" + ], + "flake-parts": "flake-parts_4", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks-nix": "pre-commit-hooks-nix", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1712261512, + "narHash": "sha256-qsBZ3tJj/3LR8jNYyCKjyCe0ePj4cMynSWBMC1OEDtc=", + "owner": "nix-community", + "repo": "lanzaboote", + "rev": "999c0cb03f748fe311bca78961dbf0562dc91659", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "lanzaboote", + "type": "github" + } + }, + "leap-nvim": { + "flake": false, + "locked": { + "lastModified": 1711935259, + "narHash": "sha256-HcuNaKyf+rmhg3t4BQXiRlyeavwyhy16pfPn1Y1l09k=", + "owner": "ggandor", + "repo": "leap.nvim", + "rev": "7a9407d17fab3a1c3cfe201965d680a408776152", + "type": "github" + }, + "original": { + "owner": "ggandor", + "repo": "leap.nvim", + "type": "github" + } + }, + "libgit2": { + "flake": false, + "locked": { + "lastModified": 1697646580, + "narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=", + "owner": "libgit2", + "repo": "libgit2", + "rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5", + "type": "github" + }, + "original": { + "owner": "libgit2", + "repo": "libgit2", + "type": "github" + } + }, + "lsp-lines": { + "flake": false, + "locked": { + "lastModified": 1709989705, + "narHash": "sha256-opViLzbwtyUgDoaVKz4z6SN06N8jCQ0YmoqPIht8e64=", + "owner": "~whynothugo", + "repo": "lsp_lines.nvim", + "rev": "6f3defec73f7c87939e800e9afa5d0571b19b401", + "type": "sourcehut" + }, + "original": { + "owner": "~whynothugo", + "repo": "lsp_lines.nvim", + "type": "sourcehut" + } + }, + "lsp-signature": { + "flake": false, + "locked": { + "lastModified": 1710647656, + "narHash": "sha256-O7y7pcCvF0xUFamG+wMLe4mC6hUQ679rJV+ZUoWB0oY=", + "owner": "ray-x", + "repo": "lsp_signature.nvim", + "rev": "c6aeb2f1d2538bbdfdaab1664d9d4c3c75aa9db8", + "type": "github" + }, + "original": { + "owner": "ray-x", + "repo": "lsp_signature.nvim", + "type": "github" + } + }, + "lspkind": { + "flake": false, + "locked": { + "lastModified": 1704982040, + "narHash": "sha256-/QLdBU/Zwmkw1NGuLBD48tvrmIP9d9WHhgcLEQgRTWo=", + "owner": "onsails", + "repo": "lspkind-nvim", + "rev": "1735dd5a5054c1fb7feaf8e8658dbab925f4f0cf", + "type": "github" + }, + "original": { + "owner": "onsails", + "repo": "lspkind-nvim", + "type": "github" + } + }, + "lspsaga": { + "flake": false, + "locked": { + "lastModified": 1670360222, + "narHash": "sha256-7ENInq3LAPPTdm0Fb7klOc630j8m4LRj1kLZZFYLh68=", + "owner": "tami5", + "repo": "lspsaga.nvim", + "rev": "5faeec9f2508d2d49a66c0ac0d191096b4e3fa81", + "type": "github" + }, + "original": { + "owner": "tami5", + "repo": "lspsaga.nvim", + "type": "github" + } + }, + "lualine": { + "flake": false, + "locked": { + "lastModified": 1710998293, + "narHash": "sha256-+2fi58GolO3e0O7+kl+idNeFuTfJA1b5yCBdY2RnVjA=", + "owner": "hoob3rt", + "repo": "lualine.nvim", + "rev": "b5e8bb642138f787a2c1c5aedc2a78cb2cebbd67", + "type": "github" + }, + "original": { + "owner": "hoob3rt", + "repo": "lualine.nvim", + "type": "github" + } + }, + "mind-nvim": { + "flake": false, + "locked": { + "lastModified": 1679526071, + "narHash": "sha256-JIhAhQYGLLRucwlhzfckQYU5qjqbHtNH52JlGS5a79w=", + "owner": "phaazon", + "repo": "mind.nvim", + "rev": "002137dd7cf97865ebd01b6a260209d2daf2da66", + "type": "github" + }, + "original": { + "owner": "phaazon", + "repo": "mind.nvim", + "type": "github" + } + }, + "minimap-vim": { + "flake": false, + "locked": { + "lastModified": 1710689313, + "narHash": "sha256-GR8VAHla5HWry1TAZQv0Xp7iG256vIGeQcBGMxyt310=", + "owner": "wfxr", + "repo": "minimap.vim", + "rev": "395378137e6180762d5b963ca9ad5ac2db5d3283", + "type": "github" + }, + "original": { + "owner": "wfxr", + "repo": "minimap.vim", + "type": "github" + } + }, + "modes-nvim": { + "flake": false, + "locked": { + "lastModified": 1702245923, + "narHash": "sha256-Kd2hf5obrPvCVLtRcFjLd75byyrB2o3uYCSEMW6IeCc=", + "owner": "mvllow", + "repo": "modes.nvim", + "rev": "4035a46aaabe43faf1b54740575af9dd5bb03809", + "type": "github" + }, + "original": { + "owner": "mvllow", + "repo": "modes.nvim", + "type": "github" + } + }, + "naersk": { + "inputs": { + "nixpkgs": [ + "neovim-flake", + "rnix-lsp", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1655042882, + "narHash": "sha256-9BX8Fuez5YJlN7cdPO63InoyBy7dm3VlJkkmTt6fS1A=", + "owner": "nix-community", + "repo": "naersk", + "rev": "cddffb5aa211f50c4b8750adbec0bbbdfb26bb9f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "naersk", + "type": "github" + } + }, + "neocord": { + "flake": false, + "locked": { + "lastModified": 1711651358, + "narHash": "sha256-ZZF7ttn/6QIsaub1m0LV0ZirvNVXyFh+WDc39wi4UsM=", + "owner": "IogaMaster", + "repo": "neocord", + "rev": "6269823e78a2d2d8c3954068da196879cf2f0fe6", + "type": "github" + }, + "original": { + "owner": "IogaMaster", + "repo": "neocord", + "type": "github" + } + }, + "neodev-nvim": { + "flake": false, + "locked": { + "lastModified": 1711715247, + "narHash": "sha256-mAJOMVN7/xO7ykVNAeTeX+z2A/7yB8zdqlEKHL6Pb74=", + "owner": "folke", + "repo": "neodev.nvim", + "rev": "ce9a2e8eaba5649b553529c5498acb43a6c317cd", + "type": "github" + }, + "original": { + "owner": "folke", + "repo": "neodev.nvim", + "type": "github" + } + }, + "neovim-flake": { + "inputs": { + "alpha-nvim": "alpha-nvim", + "bufdelete-nvim": "bufdelete-nvim", + "catppuccin": "catppuccin", + "ccc": "ccc", + "cellular-automaton": "cellular-automaton", + "cheatsheet-nvim": "cheatsheet-nvim", + "cinnamon-nvim": "cinnamon-nvim", + "cmp-buffer": "cmp-buffer", + "cmp-nvim-lsp": "cmp-nvim-lsp", + "cmp-path": "cmp-path", + "cmp-treesitter": "cmp-treesitter", + "cmp-vsnip": "cmp-vsnip", + "codewindow-nvim": "codewindow-nvim", + "comment-nvim": "comment-nvim", + "copilot-cmp": "copilot-cmp", + "copilot-lua": "copilot-lua", + "crates-nvim": "crates-nvim", + "dashboard-nvim": "dashboard-nvim", + "diffview-nvim": "diffview-nvim", + "dracula": "dracula", + "dressing-nvim": "dressing-nvim", + "elixir-ls": "elixir-ls", + "elixir-tools": "elixir-tools", + "fidget-nvim": "fidget-nvim", + "flake-parts": [ + "flake-parts" + ], + "flake-utils": [ + "flake-utils" + ], + "flutter-tools": "flutter-tools", + "gesture-nvim": "gesture-nvim", + "gitsigns-nvim": "gitsigns-nvim", + "glow-nvim": "glow-nvim", + "gruvbox": "gruvbox", + "highlight-undo": "highlight-undo", + "hop-nvim": "hop-nvim", + "icon-picker-nvim": "icon-picker-nvim", + "image-nvim": "image-nvim", + "indent-blankline": "indent-blankline", + "kommentary": "kommentary", + "leap-nvim": "leap-nvim", + "lsp-lines": "lsp-lines", + "lsp-signature": "lsp-signature", + "lspkind": "lspkind", + "lspsaga": "lspsaga", + "lualine": "lualine", + "mind-nvim": "mind-nvim", + "minimap-vim": "minimap-vim", + "modes-nvim": "modes-nvim", + "neocord": "neocord", + "neodev-nvim": "neodev-nvim", + "nil": [ + "nil" + ], + "nixpkgs": [ + "nixpkgs-small" + ], + "nmd": "nmd", + "noice-nvim": "noice-nvim", + "none-ls": "none-ls", + "nui-nvim": "nui-nvim", + "nvim-autopairs": "nvim-autopairs", + "nvim-bufferline-lua": "nvim-bufferline-lua", + "nvim-cmp": "nvim-cmp", + "nvim-code-action-menu": "nvim-code-action-menu", + "nvim-colorizer-lua": "nvim-colorizer-lua", + "nvim-cursorline": "nvim-cursorline", + "nvim-dap": "nvim-dap", + "nvim-dap-ui": "nvim-dap-ui", + "nvim-docs-view": "nvim-docs-view", + "nvim-lightbulb": "nvim-lightbulb", + "nvim-lspconfig": "nvim-lspconfig", + "nvim-navbuddy": "nvim-navbuddy", + "nvim-navic": "nvim-navic", + "nvim-neoclip": "nvim-neoclip", + "nvim-nio": "nvim-nio", + "nvim-notify": "nvim-notify", + "nvim-session-manager": "nvim-session-manager", + "nvim-surround": "nvim-surround", + "nvim-tree-lua": "nvim-tree-lua", + "nvim-treesitter-context": "nvim-treesitter-context", + "nvim-ts-autotag": "nvim-ts-autotag", + "nvim-web-devicons": "nvim-web-devicons", + "obsidian-nvim": "obsidian-nvim", + "onedark": "onedark", + "orgmode-nvim": "orgmode-nvim", + "oxocarbon": "oxocarbon", + "plenary-nvim": "plenary-nvim", + "project-nvim": "project-nvim", + "registers": "registers", + "rnix-lsp": "rnix-lsp", + "rose-pine": "rose-pine", + "rust-tools": "rust-tools", + "scrollbar-nvim": "scrollbar-nvim", + "smartcolumn": "smartcolumn", + "sqls-nvim": "sqls-nvim", + "systems": "systems_8", + "tabular": "tabular", + "telescope": "telescope", + "tidalcycles": "tidalcycles", + "todo-comments": "todo-comments", + "toggleterm-nvim": "toggleterm-nvim", + "tokyonight": "tokyonight", + "trouble": "trouble", + "vim-dirtytalk": "vim-dirtytalk", + "vim-illuminate": "vim-illuminate", + "vim-markdown": "vim-markdown", + "vim-repeat": "vim-repeat", + "vim-startify": "vim-startify", + "vim-vsnip": "vim-vsnip", + "which-key": "which-key", + "zig": "zig" + }, + "locked": { + "lastModified": 1712493555, + "narHash": "sha256-KlRdjMyLINy8kIMuL4FJRP94ozlA3X8m2Ws7lDAtZBQ=", + "owner": "NotAShelf", + "repo": "neovim-flake", + "rev": "e1835f6c468f46266848feed5ee33e64204f3dea", + "type": "github" + }, + "original": { + "owner": "NotAShelf", + "ref": "v0.6", + "repo": "neovim-flake", + "type": "github" + } + }, + "neovim-flake_2": { + "inputs": { + "flake-utils": "flake-utils_5", + "nixpkgs": [ + "neovim-nightly", + "nixpkgs" + ] + }, + "locked": { + "dir": "contrib", + "lastModified": 1712618449, + "narHash": "sha256-+6/UTHSYSwoGwpXanZmwvn29Oo+OomtVp7UyP9K4f0Y=", + "owner": "neovim", + "repo": "neovim", + "rev": "2528093bbea8862ede0feb6eb29bdc5451a6313b", + "type": "github" + }, + "original": { + "dir": "contrib", + "owner": "neovim", + "repo": "neovim", + "type": "github" + } + }, + "neovim-nightly": { + "inputs": { + "flake-compat": "flake-compat_5", + "flake-parts": "flake-parts_5", + "hercules-ci-effects": "hercules-ci-effects", + "neovim-flake": "neovim-flake_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712621069, + "narHash": "sha256-3IikHqy/bH81Qp0cjHn1a554ERd1tfzKMIP0zEKC3PA=", + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "rev": "cf37798bbd7c772b80048b54c738febd2df02e6d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "type": "github" + } + }, + "nh": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712645404, + "narHash": "sha256-uEVd15WsX+Wti9PXW724puFcsFO72VTiJyBwW2WXT9M=", + "owner": "viperML", + "repo": "nh", + "rev": "fe4a96a0b0b0662dba7c186b4a1746c70bbcad03", + "type": "github" + }, + "original": { + "owner": "viperML", + "repo": "nh", + "type": "github" + } + }, + "nil": { + "inputs": { + "flake-utils": "flake-utils_6", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": [ + "rust-overlay" + ] + }, + "locked": { + "lastModified": 1704611696, + "narHash": "sha256-4ZCgV5oHdEc3q+XaIzy//gh20uC/aSuAtMU9bsfgLZk=", + "owner": "oxalica", + "repo": "nil", + "rev": "059d33a24bb76d2048740bcce936362bf54b5bc9", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "nil", + "type": "github" + } + }, + "nix-index-db": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712459390, + "narHash": "sha256-e12bNDottaGoBgd0AdH/bQvk854xunlWAdZwr/oHO1c=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "4676d72d872459e1e3a248d049609f110c570e9a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, + "nix-super": { + "inputs": { + "flake-compat": "flake-compat_6", + "libgit2": "libgit2", + "nixpkgs": "nixpkgs_12", + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1712350614, + "narHash": "sha256-q+fOInSvIDP1de1A3Pn4juBK2fkZJG3ezZNhhgHQpwc=", + "owner": "privatevoid-net", + "repo": "nix-super", + "rev": "afffb6659d3672e166f3d541f0656144e1cbbb27", + "type": "github" + }, + "original": { + "owner": "privatevoid-net", + "repo": "nix-super", + "type": "github" + } + }, + "nixfmt": { + "flake": false, + "locked": { + "lastModified": 1712357216, + "narHash": "sha256-pWf+rNxSPUJjY8p6T6633Gg+lMm3MsRtJnj/TdtZa5k=", + "owner": "nixos", + "repo": "nixfmt", + "rev": "35b0186137d9cac7097a0374d96e3b9a687a30d7", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixfmt", + "type": "github" + } + }, + "nixos-hardware": { + "locked": { + "lastModified": 1712566108, + "narHash": "sha256-c9nT2ZODGqobISP41kUwCQ84Srwg7a/1TmPFQuol2/8=", + "owner": "nixos", + "repo": "nixos-hardware", + "rev": "1e3b3a35b7083f4152f5a516798cf9b21e686465", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixos-hardware", + "type": "github" + } + }, + "nixpak": { + "inputs": { + "flake-parts": [ + "flake-parts" + ], + "hercules-ci-effects": "hercules-ci-effects_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709985524, + "narHash": "sha256-29ZwMJBErP41ZPis1MskhdheDRgt+reDuf53jONSkc8=", + "owner": "nixpak", + "repo": "nixpak", + "rev": "b0862a125da8fe5d179633d6cc7aed57d5316871", + "type": "github" + }, + "original": { + "owner": "nixpak", + "repo": "nixpak", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1708475490, + "narHash": "sha256-g1v0TsWBQPX97ziznfJdWhgMyMGtoBFs102xSYO4syU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0e74ca98a74bc7270d28838369593635a5db3260", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1698611440, + "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib_2": { + "locked": { + "dir": "lib", + "lastModified": 1711703276, + "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib_3": { + "locked": { + "dir": "lib", + "lastModified": 1698611440, + "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-small": { + "locked": { + "lastModified": 1712645145, + "narHash": "sha256-ClKLPnuBwqNWh+/3Wq7aMnUOWIDxU8Asml/YBX64WBY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e160d4327caca711fb7286cce448ca2d341518da", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable-small", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1711460390, + "narHash": "sha256-akSgjDZL6pVHEfSE6sz1DNSXuYX6hq+P/1Z5IoYWs7E=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "44733514b72e732bd49f5511bd0203dea9b9a434", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1710695816, + "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "614b4613980a522ba49f0d194531beddbb7220d3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_3": { + "locked": { + "lastModified": 1710695816, + "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "614b4613980a522ba49f0d194531beddbb7220d3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_10": { + "locked": { + "lastModified": 1693844670, + "narHash": "sha256-t69F2nBB8DNQUWHD809oJZJVE+23XBrth4QZuVd6IE0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3c15feef7770eb5500a4b8792623e2d6f598c9c1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_11": { + "locked": { + "lastModified": 1702350026, + "narHash": "sha256-A+GNZFZdfl4JdDphYKBJ5Ef1HOiFsP18vQe9mqjmUis=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9463103069725474698139ab10f17a9d125da859", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_12": { + "locked": { + "lastModified": 1709083642, + "narHash": "sha256-7kkJQd4rZ+vFrzWu8sTRtta5D1kBG0LSRYAfhtmMlSo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b550fe4b4776908ac2a861124307045f8e717c8e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_13": { + "locked": { + "lastModified": 1712439257, + "narHash": "sha256-aSpiNepFOMk9932HOax0XwNxbA38GOUVOiXfUVPOrck=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ff0dbd94265ac470dda06a657d5fe49de93b4599", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_14": { + "locked": { + "lastModified": 1712163089, + "narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "fd281bd6b7d3e32ddfa399853946f782553163b5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_15": { + "locked": { + "lastModified": 1708475490, + "narHash": "sha256-g1v0TsWBQPX97ziznfJdWhgMyMGtoBFs102xSYO4syU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0e74ca98a74bc7270d28838369593635a5db3260", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1696193975, + "narHash": "sha256-mnQjUcYgp9Guu3RNVAB2Srr1TqKcPpRXmJf4LJk6KRY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "fdd898f8f79e8d2f99ed2ab6b3751811ef683242", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1690031011, + "narHash": "sha256-kzK0P4Smt7CL53YCdZCBbt9uBFFhE0iNvCki20etAf4=", + "path": "/nix/store/gxw5rlp29swdpgz26vhaqzy21b9pxrim-source", + "rev": "12303c652b881435065a98729eb7278313041e49", + "type": "path" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1702272962, + "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_5": { + "locked": { + "lastModified": 1712439257, + "narHash": "sha256-aSpiNepFOMk9932HOax0XwNxbA38GOUVOiXfUVPOrck=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ff0dbd94265ac470dda06a657d5fe49de93b4599", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_6": { + "locked": { + "lastModified": 1708475490, + "narHash": "sha256-g1v0TsWBQPX97ziznfJdWhgMyMGtoBFs102xSYO4syU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0e74ca98a74bc7270d28838369593635a5db3260", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_7": { + "locked": { + "lastModified": 1711163522, + "narHash": "sha256-YN/Ciidm+A0fmJPWlHBGvVkcarYWSC+s3NTPk/P+q3c=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "44d0940ea560dee511026a53f0e2e2cde489b4d4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_8": { + "locked": { + "lastModified": 1683014792, + "narHash": "sha256-6Va9iVtmmsw4raBc3QKvQT2KT/NGRWlvUlJj46zN8B8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1a411f23ba299db155a5b45d5e145b85a7aafc42", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_9": { + "locked": { + "lastModified": 1656753965, + "narHash": "sha256-BCrB3l0qpJokOnIVc3g2lHiGhnjUi0MoXiw6t1o8H1E=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "0ea7a8f1b939d74e5df8af9a8f7342097cdf69eb", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nmd": { + "flake": false, + "locked": { + "lastModified": 1705050560, + "narHash": "sha256-x3zzcdvhJpodsmdjqB4t5mkVW22V3wqHLOun0KRBzUI=", + "owner": "~rycee", + "repo": "nmd", + "rev": "66d9334933119c36f91a78d565c152a4fdc8d3d3", + "type": "sourcehut" + }, + "original": { + "owner": "~rycee", + "repo": "nmd", + "type": "sourcehut" + } + }, + "noice-nvim": { + "flake": false, + "locked": { + "lastModified": 1711471279, + "narHash": "sha256-y6gHNkWVsIuwBf7MblCTKTZSqjGDxqeFeQZWexzwk94=", + "owner": "folke", + "repo": "noice.nvim", + "rev": "0cbe3f88d038320bdbda3c4c5c95f43a13c3aa12", + "type": "github" + }, + "original": { + "owner": "folke", + "repo": "noice.nvim", + "type": "github" + } + }, + "none-ls": { + "flake": false, + "locked": { + "lastModified": 1708525772, + "narHash": "sha256-VCDUKiy9C3Bu9suf2bI6XSis1+j01oFC3GFPyQxi74c=", + "owner": "nvimtools", + "repo": "none-ls.nvim", + "rev": "bb680d752cec37949faca7a1f509e2fe67ab418a", + "type": "github" + }, + "original": { + "owner": "nvimtools", + "repo": "none-ls.nvim", + "rev": "bb680d752cec37949faca7a1f509e2fe67ab418a", + "type": "github" + } + }, + "nui-nvim": { + "flake": false, + "locked": { + "lastModified": 1710740032, + "narHash": "sha256-Zr5CNx6BIM6naCXW8YBc/Oj1qOtWV/3tuMoaaZjoSZA=", + "owner": "MunifTanjim", + "repo": "nui.nvim", + "rev": "cbd2668414331c10039278f558630ed19b93e69b", + "type": "github" + }, + "original": { + "owner": "MunifTanjim", + "repo": "nui.nvim", + "type": "github" + } + }, + "nvim-autopairs": { + "flake": false, + "locked": { + "lastModified": 1710930065, + "narHash": "sha256-H4mJ43Eyo36noIqYZ0lyqM7WPwgIKqi96OjW5F3pfvU=", + "owner": "windwp", + "repo": "nvim-autopairs", + "rev": "dbfc1c34bed415906395db8303c71039b3a3ffb4", + "type": "github" + }, + "original": { + "owner": "windwp", + "repo": "nvim-autopairs", + "type": "github" + } + }, + "nvim-bufferline-lua": { + "flake": false, + "locked": { + "lastModified": 1709805539, + "narHash": "sha256-drvgwupiyRAoShL2enXEYUumkYJnG+QtIkBIVqVZK+U=", + "owner": "akinsho", + "repo": "nvim-bufferline.lua", + "rev": "64e2c5def50dfd6b6f14d96a45fa3d815a4a1eef", + "type": "github" + }, + "original": { + "owner": "akinsho", + "repo": "nvim-bufferline.lua", + "type": "github" + } + }, + "nvim-cmp": { + "flake": false, + "locked": { + "lastModified": 1712041554, + "narHash": "sha256-DBxQTmwuEGj2g7LP7d1PJk/SyO0iJq2CIIHsFh0QJ4I=", + "owner": "hrsh7th", + "repo": "nvim-cmp", + "rev": "ce16de5665c766f39c271705b17fff06f7bcb84f", + "type": "github" + }, + "original": { + "owner": "hrsh7th", + "repo": "nvim-cmp", + "type": "github" + } + }, + "nvim-code-action-menu": { + "flake": false, + "locked": { + "lastModified": 1702287297, + "narHash": "sha256-pY+aP9iBuJhvDZzVEsOHZmnfaq3vUP7TfKEEQrj+Mo8=", + "owner": "weilbith", + "repo": "nvim-code-action-menu", + "rev": "8c7672a4b04d3cc4edd2c484d05b660a9cb34a1b", + "type": "github" + }, + "original": { + "owner": "weilbith", + "repo": "nvim-code-action-menu", + "type": "github" + } + }, + "nvim-colorizer-lua": { + "flake": false, + "locked": { + "lastModified": 1703321305, + "narHash": "sha256-oKvFN2K+ASlPNwj2rhptR/ErYgo6XKBPhXSZotDdCP0=", + "owner": "NvChad", + "repo": "nvim-colorizer.lua", + "rev": "85855b38011114929f4058efc97af1059ab3e41d", + "type": "github" + }, + "original": { + "owner": "NvChad", + "repo": "nvim-colorizer.lua", + "type": "github" + } + }, + "nvim-cursorline": { + "flake": false, + "locked": { + "lastModified": 1650034925, + "narHash": "sha256-Uhw65p1KBjs8KsVOmTzuiu3XKclxBob8AVdWEt30C/8=", + "owner": "yamatsum", + "repo": "nvim-cursorline", + "rev": "804f0023692653b2b2368462d67d2a87056947f9", + "type": "github" + }, + "original": { + "owner": "yamatsum", + "repo": "nvim-cursorline", + "type": "github" + } + }, + "nvim-dap": { + "flake": false, + "locked": { + "lastModified": 1711382674, + "narHash": "sha256-HoLnYeA18TpHM1SJ3NOY53ZAyBo2y2EoUbAIr7TqtQI=", + "owner": "mfussenegger", + "repo": "nvim-dap", + "rev": "405df1dcc2e395ab5173a9c3d00e03942c023074", + "type": "github" + }, + "original": { + "owner": "mfussenegger", + "repo": "nvim-dap", + "type": "github" + } + }, + "nvim-dap-ui": { + "flake": false, + "locked": { + "lastModified": 1710867604, + "narHash": "sha256-KAwCt8E3lC0fzXQ9GpPsdb9wdWC6G2P4C/YFQFY9AAM=", + "owner": "rcarriga", + "repo": "nvim-dap-ui", + "rev": "edfa93f60b189e5952c016eee262d0685d838450", + "type": "github" + }, + "original": { + "owner": "rcarriga", + "repo": "nvim-dap-ui", + "type": "github" + } + }, + "nvim-docs-view": { + "flake": false, + "locked": { + "lastModified": 1705711563, + "narHash": "sha256-N5PrJKhF6pHkel4EyAllNdEYQRninfSyaAXPbuAiD+s=", + "owner": "amrbashir", + "repo": "nvim-docs-view", + "rev": "78d88bca16f32a430572758677f9246f6d7f7b94", + "type": "github" + }, + "original": { + "owner": "amrbashir", + "repo": "nvim-docs-view", + "type": "github" + } + }, + "nvim-lightbulb": { + "flake": false, + "locked": { + "lastModified": 1689887436, + "narHash": "sha256-Meoop66jINllnxN6aohuPmU7DEjn64FMq/b8zuy9FEQ=", + "owner": "kosayoda", + "repo": "nvim-lightbulb", + "rev": "8f00b89dd1b1dbde16872bee5fbcee2e58c9b8e9", + "type": "github" + }, + "original": { + "owner": "kosayoda", + "repo": "nvim-lightbulb", + "type": "github" + } + }, + "nvim-lspconfig": { + "flake": false, + "locked": { + "lastModified": 1712139869, + "narHash": "sha256-DMhB4L/0FjYbhNx7SwFnyFVa4PLVLlwB4uiNbiKUmEo=", + "owner": "neovim", + "repo": "nvim-lspconfig", + "rev": "96e5711040df23583591391ce49e556b8cd248d8", + "type": "github" + }, + "original": { + "owner": "neovim", + "repo": "nvim-lspconfig", + "type": "github" + } + }, + "nvim-navbuddy": { + "flake": false, + "locked": { + "lastModified": 1711239174, + "narHash": "sha256-EZXzFjGsZHkb2Ui5uvOottPHA8X15F6xyikab4dBlYk=", + "owner": "SmiteshP", + "repo": "nvim-navbuddy", + "rev": "f34237e8a41ebc6e2716af2ebf49854d8c5289c8", + "type": "github" + }, + "original": { + "owner": "SmiteshP", + "repo": "nvim-navbuddy", + "type": "github" + } + }, + "nvim-navic": { + "flake": false, + "locked": { + "lastModified": 1701345631, + "narHash": "sha256-0p5n/V8Jlj9XyxV/fuMwsbQ7oV5m9H2GqZZEA/njxCQ=", + "owner": "SmiteshP", + "repo": "nvim-navic", + "rev": "8649f694d3e76ee10c19255dece6411c29206a54", + "type": "github" + }, + "original": { + "owner": "SmiteshP", + "repo": "nvim-navic", + "type": "github" + } + }, + "nvim-neoclip": { + "flake": false, + "locked": { + "lastModified": 1701664728, + "narHash": "sha256-QtqLKdrDGzIiSEo3DZtv0C7wx3KlrcyePoIYdvH6vpk=", + "owner": "AckslD", + "repo": "nvim-neoclip.lua", + "rev": "798cd0592a81c185465db3a091a0ff8a21af60fd", + "type": "github" + }, + "original": { + "owner": "AckslD", + "repo": "nvim-neoclip.lua", + "type": "github" + } + }, + "nvim-nio": { + "flake": false, + "locked": { + "lastModified": 1712067294, + "narHash": "sha256-bjYtZygrL05qB2dM7Q8lJor81VYO+u8/JWQqfZ19Wzk=", + "owner": "nvim-neotest", + "repo": "nvim-nio", + "rev": "173f285eebb410199273fa178aa517fd2d7edd80", + "type": "github" + }, + "original": { + "owner": "nvim-neotest", + "repo": "nvim-nio", + "type": "github" + } + }, + "nvim-notify": { + "flake": false, + "locked": { + "lastModified": 1708161547, + "narHash": "sha256-xJYPOX4YLcWojMCdP1RO22/7FMrbcBQxqxrcVCE2TrU=", + "owner": "rcarriga", + "repo": "nvim-notify", + "rev": "5371f4bfc1f6d3adf4fe9d62cd3a9d44356bfd15", + "type": "github" + }, + "original": { + "owner": "rcarriga", + "repo": "nvim-notify", + "type": "github" + } + }, + "nvim-session-manager": { + "flake": false, + "locked": { + "lastModified": 1708284146, + "narHash": "sha256-+TDWY8mprJfUp9ZFKbz83to7XW8iiovja22jHms+N1A=", + "owner": "Shatur", + "repo": "neovim-session-manager", + "rev": "d8e1ba3bbcf3fdc6a887bcfbd94c48ae4707b457", + "type": "github" + }, + "original": { + "owner": "Shatur", + "repo": "neovim-session-manager", + "type": "github" + } + }, + "nvim-surround": { + "flake": false, + "locked": { + "lastModified": 1709063002, + "narHash": "sha256-uInXJq+TrfKM9WfOlUAYxbDad9mwf7DK5lETyTu+ShM=", + "owner": "kylechui", + "repo": "nvim-surround", + "rev": "84a26afce16cffa7e3322cfa80a42cddf60616eb", + "type": "github" + }, + "original": { + "owner": "kylechui", + "repo": "nvim-surround", + "type": "github" + } + }, + "nvim-tree-lua": { + "flake": false, + "locked": { + "lastModified": 1711866287, + "narHash": "sha256-AMbUthY+49wREBr7EQSZ/tH8hT4gixPfcPT+ZzssUKw=", + "owner": "nvim-tree", + "repo": "nvim-tree.lua", + "rev": "d8d3a1590a05b2d8b5eb26e2ed1c6052b1b47a77", + "type": "github" + }, + "original": { + "owner": "nvim-tree", + "repo": "nvim-tree.lua", + "type": "github" + } + }, + "nvim-treesitter-context": { + "flake": false, + "locked": { + "lastModified": 1711099836, + "narHash": "sha256-iDBFUMUjGJXzEioZ4cTydDYHRR30GF6z9W0M7IZUasc=", + "owner": "nvim-treesitter", + "repo": "nvim-treesitter-context", + "rev": "f19766163c18515fb4d3c12d572bf9cba6cdb990", + "type": "github" + }, + "original": { + "owner": "nvim-treesitter", + "repo": "nvim-treesitter-context", + "type": "github" + } + }, + "nvim-ts-autotag": { + "flake": false, + "locked": { + "lastModified": 1707265789, + "narHash": "sha256-cPIEIjcYxX3ZkOyou2mYlHMdhBxCoVTpJVXZtiWe9Ks=", + "owner": "windwp", + "repo": "nvim-ts-autotag", + "rev": "531f48334c422222aebc888fd36e7d109cb354cd", + "type": "github" + }, + "original": { + "owner": "windwp", + "repo": "nvim-ts-autotag", + "type": "github" + } + }, + "nvim-web-devicons": { + "flake": false, + "locked": { + "lastModified": 1711417099, + "narHash": "sha256-G8URFQdABLf3ptj+9kwSFGXly9D+4lkt3SXfbhVDH6g=", + "owner": "nvim-tree", + "repo": "nvim-web-devicons", + "rev": "3ee60deaa539360518eaab93a6c701fe9f4d82ef", + "type": "github" + }, + "original": { + "owner": "nvim-tree", + "repo": "nvim-web-devicons", + "type": "github" + } + }, + "nyxpkgs": { + "inputs": { + "flake-compat": "flake-compat_7", + "flake-parts": "flake-parts_7", + "nixpkgs": "nixpkgs_14" + }, + "locked": { + "lastModified": 1712625255, + "narHash": "sha256-kwk/o5IWw1a99cbrsiAtvPtGh6Gpg52tq435S1eq5dE=", + "owner": "NotAShelf", + "repo": "nyxpkgs", + "rev": "c5d4a7c214ad9c76df67511d8a4514f2484e6dc1", + "type": "github" + }, + "original": { + "owner": "NotAShelf", + "repo": "nyxpkgs", + "type": "github" + } + }, + "obsidian-nvim": { + "flake": false, + "locked": { + "lastModified": 1711994732, + "narHash": "sha256-RD5EhYv2AZvCywxQYKkPjZPY/jEjl2rEofMVCHO6SJQ=", + "owner": "epwalsh", + "repo": "obsidian.nvim", + "rev": "d70f3289399c25153b7f503b838afbf981124a37", + "type": "github" + }, + "original": { + "owner": "epwalsh", + "repo": "obsidian.nvim", + "type": "github" + } + }, + "onedark": { + "flake": false, + "locked": { + "lastModified": 1706527208, + "narHash": "sha256-1+aO8vrUGEe/NIVI1C1xJyuQVPQZ1s510lopkEVP7No=", + "owner": "navarasu", + "repo": "onedark.nvim", + "rev": "1230aaf2a427b2c5b73aba6e4a9a5881d3e69429", + "type": "github" + }, + "original": { + "owner": "navarasu", + "repo": "onedark.nvim", + "type": "github" + } + }, + "orgmode-nvim": { + "flake": false, + "locked": { + "lastModified": 1712161945, + "narHash": "sha256-44dTemgSevEdiluUanGLySo7WbvKrXW+n2dUwUO4cqY=", + "owner": "nvim-orgmode", + "repo": "orgmode", + "rev": "ddcfbb1e52b2ff5b90469eb13214676931a66e09", + "type": "github" + }, + "original": { + "owner": "nvim-orgmode", + "repo": "orgmode", + "type": "github" + } + }, + "oxocarbon": { + "flake": false, + "locked": { + "lastModified": 1687168305, + "narHash": "sha256-2o++5aRDULfI35d+7psa6bk0eSXH2HwfuGjGtYGjR4w=", + "owner": "glyh", + "repo": "oxocarbon.nvim", + "rev": "7591d2e18df05374d612acba2b2573c7ff44dce4", + "type": "github" + }, + "original": { + "owner": "glyh", + "ref": "lualine-support", + "repo": "oxocarbon.nvim", + "type": "github" + } + }, + "plenary-nvim": { + "flake": false, + "locked": { + "lastModified": 1711369325, + "narHash": "sha256-wM/FuK24NPEyaWntwT+mi2SuPExC/abXDK9c2WvgUBk=", + "owner": "nvim-lua", + "repo": "plenary.nvim", + "rev": "8aad4396840be7fc42896e3011751b7609ca4119", + "type": "github" + }, + "original": { + "owner": "nvim-lua", + "repo": "plenary.nvim", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat_8", + "flake-utils": [ + "flake-utils" + ], + "gitignore": "gitignore_2", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_3" + }, + "locked": { + "lastModified": 1712579741, + "narHash": "sha256-igpsH+pa6yFwYOdah3cFciCk8gw+ytniG9quf5f/q84=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "70f504012f0a132ac33e56988e1028d88a48855c", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks-nix": { + "inputs": { + "flake-compat": [ + "lanzaboote", + "flake-compat" + ], + "flake-utils": [ + "lanzaboote", + "flake-utils" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_2" + }, + "locked": { + "lastModified": 1710923068, + "narHash": "sha256-6hOpUiuxuwpXXc/xfJsBUJeqqgGI+JMJuLo45aG3cKc=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "e611897ddfdde3ed3eaac4758635d7177ff78673", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "project-nvim": { + "flake": false, + "locked": { + "lastModified": 1680567592, + "narHash": "sha256-avV3wMiDbraxW4mqlEsKy0oeewaRj9Q33K8NzWoaptU=", + "owner": "ahmedkhalf", + "repo": "project.nvim", + "rev": "8c6bad7d22eef1b71144b401c9f74ed01526a4fb", + "type": "github" + }, + "original": { + "owner": "ahmedkhalf", + "repo": "project.nvim", + "type": "github" + } + }, + "registers": { + "flake": false, + "locked": { + "lastModified": 1703954003, + "narHash": "sha256-/MwIOR7H6ZkH/uLZOcMgg9XOWQB0yYYonbSKl51bXzo=", + "owner": "tversteeg", + "repo": "registers.nvim", + "rev": "22bb98f93a423252fffeb3531f7bc12a3e07b63f", + "type": "github" + }, + "original": { + "owner": "tversteeg", + "repo": "registers.nvim", + "type": "github" + } + }, + "rnix-lsp": { + "inputs": { + "naersk": "naersk", + "nixpkgs": "nixpkgs_9", + "utils": "utils_2" + }, + "locked": { + "lastModified": 1669555118, + "narHash": "sha256-F0s0m62S5bHNVWNHLZD6SeHiLrsDx98VQbRjDyIu+qQ=", + "owner": "nix-community", + "repo": "rnix-lsp", + "rev": "95d40673fe43642e2e1144341e86d0036abd95d9", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "rnix-lsp", + "type": "github" + } + }, + "root": { + "inputs": { + "agenix": "agenix", + "ags": "ags", + "air-quality-monitor": "air-quality-monitor", + "anyrun": "anyrun", + "anyrun-nixos-options": "anyrun-nixos-options", + "atticd": "atticd", + "deploy-rs": "deploy-rs", + "devshell": "devshell", + "flake-compat": "flake-compat_3", + "flake-parts": "flake-parts_3", + "flake-utils": "flake-utils_3", + "home-manager": "home-manager", + "hyprland": "hyprland", + "hyprland-contrib": "hyprland-contrib", + "hyprland-plugins": "hyprland-plugins", + "hyprpaper": "hyprpaper", + "hyprpicker": "hyprpicker", + "impermanence": "impermanence", + "lanzaboote": "lanzaboote", + "neovim-flake": "neovim-flake", + "neovim-nightly": "neovim-nightly", + "nh": "nh", + "nil": "nil", + "nix-index-db": "nix-index-db", + "nix-super": "nix-super", + "nixfmt": "nixfmt", + "nixos-hardware": "nixos-hardware", + "nixpak": "nixpak", + "nixpkgs": "nixpkgs_13", + "nixpkgs-small": "nixpkgs-small", + "nyxpkgs": "nyxpkgs", + "pre-commit-hooks": "pre-commit-hooks", + "rust-overlay": "rust-overlay_2", + "schizofox": "schizofox", + "simple-nixos-mailserver": "simple-nixos-mailserver", + "spicetify": "spicetify", + "treefmt-nix": "treefmt-nix", + "wallpkgs": "wallpkgs", + "xdg-portal-hyprland": "xdg-portal-hyprland" + } + }, + "rose-pine": { + "flake": false, + "locked": { + "lastModified": 1711769966, + "narHash": "sha256-GVYCkyFdVgye/8pEXPT8Y+4YyLmivgX/IHht/G1DdEA=", + "owner": "rose-pine", + "repo": "neovim", + "rev": "19055dfe90bfa46a1e5b0a706d13980bdffa2dee", + "type": "github" + }, + "original": { + "owner": "rose-pine", + "repo": "neovim", + "type": "github" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": [ + "lanzaboote", + "flake-utils" + ], + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1711246447, + "narHash": "sha256-g9TOluObcOEKewFo2fR4cn51Y/jSKhRRo4QZckHLop0=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "dcc802a6ec4e9cc6a1c8c393327f0c42666f22e4", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_2": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712628742, + "narHash": "sha256-FIAlt8mbPUs8jRuh6xpFtYzDsyHzmiLNPcen8HwvD00=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "e7354bb9e5f68b2074e272fd5f5ac3f4848860ba", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-tools": { + "flake": false, + "locked": { + "lastModified": 1704259376, + "narHash": "sha256-kFane5ze7VDiOzF7jdmXkr50XQsNvdb+a9HQtybEVE0=", + "owner": "simrat39", + "repo": "rust-tools.nvim", + "rev": "676187908a1ce35ffcd727c654ed68d851299d3e", + "type": "github" + }, + "original": { + "owner": "simrat39", + "repo": "rust-tools.nvim", + "type": "github" + } + }, + "schizofox": { + "inputs": { + "flake-compat": "flake-compat_9", + "flake-parts": [ + "flake-parts" + ], + "home-manager": "home-manager_2", + "nixpak": [ + "nixpak" + ], + "nixpkgs": [ + "nixpkgs-small" + ], + "searx-randomizer": "searx-randomizer" + }, + "locked": { + "lastModified": 1710502118, + "narHash": "sha256-kPzvCwGVuLlPDVRD35dMnudWPpEzRXfU/9DHsG12PaY=", + "owner": "schizofox", + "repo": "schizofox", + "rev": "8dde2033a6f448c48a48d4d0aeb22bf2da840b7d", + "type": "github" + }, + "original": { + "owner": "schizofox", + "repo": "schizofox", + "type": "github" + } + }, + "scrollbar-nvim": { + "flake": false, + "locked": { + "lastModified": 1684886154, + "narHash": "sha256-zLBexSxQCn9HPY04a9w/UCJP1F5ShI2X12I9xE9H0cM=", + "owner": "petertriho", + "repo": "nvim-scrollbar", + "rev": "35f99d559041c7c0eff3a41f9093581ceea534e8", + "type": "github" + }, + "original": { + "owner": "petertriho", + "repo": "nvim-scrollbar", + "type": "github" + } + }, + "searx-randomizer": { + "inputs": { + "crane": "crane_3", + "flake-parts": "flake-parts_8", + "nixpkgs": [ + "schizofox", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1704412376, + "narHash": "sha256-Ap/AudJxCYBDWYy0lyqP0/FZYJCibL7jKkoj6hp1WS0=", + "owner": "schizofox", + "repo": "searx-randomizer", + "rev": "c36a473732ba6b4f6024ac1c181631cf4d542b17", + "type": "github" + }, + "original": { + "owner": "schizofox", + "repo": "searx-randomizer", + "type": "github" + } + }, + "simple-nixos-mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": "flake-compat_10", + "nixpkgs": [ + "nixpkgs-small" + ], + "utils": "utils_4" + }, + "locked": { + "lastModified": 1710449465, + "narHash": "sha256-2orO8nfplp6uQJBFqKkj1iyNMC6TysmwbWwbb4osTag=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "79c8cfcd5873a85559da6201b116fb38b490d030", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "ref": "master", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, + "smartcolumn": { + "flake": false, + "locked": { + "lastModified": 1710067624, + "narHash": "sha256-DHIeDNUF9n9s14GVeojIwc5QUPwJMYYl3gRvhvO/rdE=", + "owner": "m4xshen", + "repo": "smartcolumn.nvim", + "rev": "cefb17be095ad5526030a21bb2a80553cae09127", + "type": "github" + }, + "original": { + "owner": "m4xshen", + "repo": "smartcolumn.nvim", + "type": "github" + } + }, + "spicetify": { + "inputs": { + "flake-utils": "flake-utils_7", + "nixpkgs": [ + "nixpkgs-small" + ] + }, + "locked": { + "lastModified": 1704167711, + "narHash": "sha256-kFDq+kf/Di/P8bq5sUP8pVwRkrSVrABksBjMPmLic3s=", + "owner": "the-argus", + "repo": "spicetify-nix", + "rev": "1325416f951d6a82cfddb1289864ad782e2b87c4", + "type": "github" + }, + "original": { + "owner": "the-argus", + "repo": "spicetify-nix", + "type": "github" + } + }, + "sqls-nvim": { + "flake": false, + "locked": { + "lastModified": 1684697500, + "narHash": "sha256-jKFut6NZAf/eIeIkY7/2EsjsIhvZQKCKAJzeQ6XSr0s=", + "owner": "nanotee", + "repo": "sqls.nvim", + "rev": "4b1274b5b44c48ce784aac23747192f5d9d26207", + "type": "github" + }, + "original": { + "owner": "nanotee", + "repo": "sqls.nvim", + "type": "github" + } + }, + "superdirt-src": { + "flake": false, + "locked": { + "lastModified": 1611740180, + "narHash": "sha256-GtnqZeMFqFkVhgx2Exu0wY687cHa7mNnVCgjQd6fiIA=", + "owner": "musikinformatik", + "repo": "superdirt", + "rev": "7abb62e89649daa1232b9cbd6427241868abd30e", + "type": "github" + }, + "original": { + "owner": "musikinformatik", + "ref": "master", + "repo": "superdirt", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_10": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_11": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_12": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_13": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_14": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_15": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_5": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_6": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_7": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_9": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "tabular": { + "flake": false, + "locked": { + "lastModified": 1550598128, + "narHash": "sha256-irolBA/m3YIaezl+90h5G+xUOpad+3u44uJqDs4JCUs=", + "owner": "godlygeek", + "repo": "tabular", + "rev": "339091ac4dd1f17e225fe7d57b48aff55f99b23a", + "type": "github" + }, + "original": { + "owner": "godlygeek", + "repo": "tabular", + "type": "github" + } + }, + "telescope": { + "flake": false, + "locked": { + "lastModified": 1712065014, + "narHash": "sha256-8Bp1E9JY1MByjRCcON1HJLYRswLx63lmz20rGrJW7Wc=", + "owner": "nvim-telescope", + "repo": "telescope.nvim", + "rev": "4626aaa2bcfdacf55fd6d44b430e2df81b2403ff", + "type": "github" + }, + "original": { + "owner": "nvim-telescope", + "repo": "telescope.nvim", + "type": "github" + } + }, + "tidal-src": { + "flake": false, + "locked": { + "lastModified": 1654350756, + "narHash": "sha256-tONM5SYYBca0orTLH1EUOilSC1FCluWrFt8AetUx+YQ=", + "owner": "tidalcycles", + "repo": "tidal", + "rev": "fda9c1ecb3722698935245e5409ef8ccdfca16c8", + "type": "github" + }, + "original": { + "owner": "tidalcycles", + "ref": "main", + "repo": "tidal", + "type": "github" + } + }, + "tidalcycles": { + "inputs": { + "dirt-samples-src": "dirt-samples-src", + "nixpkgs": "nixpkgs_10", + "superdirt-src": "superdirt-src", + "tidal-src": "tidal-src", + "utils": "utils_3", + "vim-tidal-src": "vim-tidal-src", + "vowel-src": "vowel-src" + }, + "locked": { + "lastModified": 1694087816, + "narHash": "sha256-GMV5ONQhLwa6xRYhZkmwc2W2jbjAfHfB/OR9vR0+PFA=", + "owner": "mitchmindtree", + "repo": "tidalcycles.nix", + "rev": "1b1c4df5303e07930d23e8361ab8253ebec0c7bb", + "type": "github" + }, + "original": { + "owner": "mitchmindtree", + "repo": "tidalcycles.nix", + "type": "github" + } + }, + "todo-comments": { + "flake": false, + "locked": { + "lastModified": 1711553769, + "narHash": "sha256-BJNU01iTRDNrPv48fgiJRS+ouaHkoqw2AYXKDRgDzfw=", + "owner": "folke", + "repo": "todo-comments.nvim", + "rev": "a7e39ae9e74f2c8c6dc4eea6d40c3971ae84752d", + "type": "github" + }, + "original": { + "owner": "folke", + "repo": "todo-comments.nvim", + "type": "github" + } + }, + "toggleterm-nvim": { + "flake": false, + "locked": { + "lastModified": 1707733615, + "narHash": "sha256-FJyDxQm2vs9R4WkqAbh6ryCvEABfrLSKRrAGo/qI5jM=", + "owner": "akinsho", + "repo": "toggleterm.nvim", + "rev": "193786e0371e3286d3bc9aa0079da1cd41beaa62", + "type": "github" + }, + "original": { + "owner": "akinsho", + "repo": "toggleterm.nvim", + "type": "github" + } + }, + "tokyonight": { + "flake": false, + "locked": { + "lastModified": 1711665767, + "narHash": "sha256-ItCmSUMMTe8iQeneIJLuWedVXsNgm+FXNtdrrdJ/1oE=", + "owner": "folke", + "repo": "tokyonight.nvim", + "rev": "9bf9ec53d5e87b025e2404069b71e7ebdc3a13e5", + "type": "github" + }, + "original": { + "owner": "folke", + "repo": "tokyonight.nvim", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1711963903, + "narHash": "sha256-N3QDhoaX+paWXHbEXZapqd1r95mdshxToGowtjtYkGI=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "49dc4a92b02b8e68798abd99184f228243b6e3ac", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "trouble": { + "flake": false, + "locked": { + "lastModified": 1711693365, + "narHash": "sha256-kIQ72fqAsiMF9jq0MzC6peaHJddYn5PRNXfYFHTQB5Q=", + "owner": "folke", + "repo": "trouble.nvim", + "rev": "b9cf677f20bb2faa2dacfa870b084e568dca9572", + "type": "github" + }, + "original": { + "owner": "folke", + "repo": "trouble.nvim", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "utils_2": { + "locked": { + "lastModified": 1656928814, + "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "utils_3": { + "inputs": { + "systems": "systems_9" + }, + "locked": { + "lastModified": 1692799911, + "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "utils_4": { + "inputs": { + "systems": "systems_12" + }, + "locked": { + "lastModified": 1709126324, + "narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "d465f4819400de7c8d874d50b982301f28a84605", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "vim-dirtytalk": { + "flake": false, + "locked": { + "lastModified": 1711553630, + "narHash": "sha256-1cLseaHfWgyAvzHcK93nl9sy66J/zvlnK7P4vnIthmY=", + "owner": "psliwka", + "repo": "vim-dirtytalk", + "rev": "d2929ffff8639b2b4b4bb7c2b6c04575c1322d2f", + "type": "github" + }, + "original": { + "owner": "psliwka", + "repo": "vim-dirtytalk", + "type": "github" + } + }, + "vim-illuminate": { + "flake": false, + "locked": { + "lastModified": 1707016059, + "narHash": "sha256-KNIu4cNyZddZSRS8KZ0U0T8uSSLJu8iqNLQN8e+Bv94=", + "owner": "RRethy", + "repo": "vim-illuminate", + "rev": "305bf07b919ac526deb5193280379e2f8b599926", + "type": "github" + }, + "original": { + "owner": "RRethy", + "repo": "vim-illuminate", + "type": "github" + } + }, + "vim-markdown": { + "flake": false, + "locked": { + "lastModified": 1709279705, + "narHash": "sha256-eKwWdyvMZ7FV3FvOtqWVD7pulXNnhbEEjHq7MYg1woU=", + "owner": "preservim", + "repo": "vim-markdown", + "rev": "a657e697376909c41475a686eeef7fc7a4972d94", + "type": "github" + }, + "original": { + "owner": "preservim", + "repo": "vim-markdown", + "type": "github" + } + }, + "vim-repeat": { + "flake": false, + "locked": { + "lastModified": 1611544268, + "narHash": "sha256-8rfZa3uKXB3TRCqaDHZ6DfzNbm7WaYnLvmTNzYtnKHg=", + "owner": "tpope", + "repo": "vim-repeat", + "rev": "24afe922e6a05891756ecf331f39a1f6743d3d5a", + "type": "github" + }, + "original": { + "owner": "tpope", + "repo": "vim-repeat", + "type": "github" + } + }, + "vim-startify": { + "flake": false, + "locked": { + "lastModified": 1695213983, + "narHash": "sha256-W5N/Dqxf9hSXEEJsrEkXInFwBXNBJe9Dzx9TVS12mPk=", + "owner": "mhinz", + "repo": "vim-startify", + "rev": "4e089dffdad46f3f5593f34362d530e8fe823dcf", + "type": "github" + }, + "original": { + "owner": "mhinz", + "repo": "vim-startify", + "type": "github" + } + }, + "vim-tidal-src": { + "flake": false, + "locked": { + "lastModified": 1685703852, + "narHash": "sha256-8gyk17YLeKpLpz3LRtxiwbpsIbZka9bb63nK5/9IUoA=", + "owner": "tidalcycles", + "repo": "vim-tidal", + "rev": "e440fe5bdfe07f805e21e6872099685d38e8b761", + "type": "github" + }, + "original": { + "owner": "tidalcycles", + "repo": "vim-tidal", + "type": "github" + } + }, + "vim-vsnip": { + "flake": false, + "locked": { + "lastModified": 1704937299, + "narHash": "sha256-gvm6z4pgSULBVPukewRyjwxZ0vZgreQWbG/0kOB1QBo=", + "owner": "hrsh7th", + "repo": "vim-vsnip", + "rev": "02a8e79295c9733434aab4e0e2b8c4b7cea9f3a9", + "type": "github" + }, + "original": { + "owner": "hrsh7th", + "repo": "vim-vsnip", + "type": "github" + } + }, + "vowel-src": { + "flake": false, + "locked": { + "lastModified": 1641306144, + "narHash": "sha256-zfF6cvAGDNYWYsE8dOIo38b+dIymd17Pexg0HiPFbxM=", + "owner": "supercollider-quarks", + "repo": "vowel", + "rev": "ab59caa870201ecf2604b3efdd2196e21a8b5446", + "type": "github" + }, + "original": { + "owner": "supercollider-quarks", + "ref": "master", + "repo": "vowel", + "type": "github" + } + }, + "wallpkgs": { + "inputs": { + "nixpkgs": [ + "nixpkgs-small" + ] + }, + "locked": { + "lastModified": 1691155724, + "narHash": "sha256-eKauqoDqQPkWwXn/2rIK7HJJdE+/9NQTtV1RHtt32Aw=", + "owner": "NotAShelf", + "repo": "wallpkgs", + "rev": "13e36d84d62ec43a7b1e21b84a42e8d5b4e718ee", + "type": "github" + }, + "original": { + "owner": "NotAShelf", + "repo": "wallpkgs", + "type": "github" + } + }, + "which-key": { + "flake": false, + "locked": { + "lastModified": 1697801635, + "narHash": "sha256-uvghPj/teWrRMm09Gh8iQ/LV2nYJw0lmoiZK6L4+1cY=", + "owner": "folke", + "repo": "which-key.nvim", + "rev": "4433e5ec9a507e5097571ed55c02ea9658fb268a", + "type": "github" + }, + "original": { + "owner": "folke", + "repo": "which-key.nvim", + "type": "github" + } + }, + "wlroots": { + "flake": false, + "locked": { + "host": "gitlab.freedesktop.org", + "lastModified": 1709983277, + "narHash": "sha256-wXWIJLd4F2JZeMaihWVDW/yYXCLEC8OpeNJZg9a9ly8=", + "owner": "wlroots", + "repo": "wlroots", + "rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b", + "type": "gitlab" + }, + "original": { + "host": "gitlab.freedesktop.org", + "owner": "wlroots", + "repo": "wlroots", + "rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b", + "type": "gitlab" + } + }, + "xdg-portal-hyprland": { + "inputs": { + "hyprland-protocols": "hyprland-protocols_2", + "hyprlang": "hyprlang_3", + "nixpkgs": "nixpkgs_15", + "systems": "systems_15" + }, + "locked": { + "lastModified": 1709299639, + "narHash": "sha256-jYqJM5khksLIbqSxCLUUcqEgI+O2LdlSlcMEBs39CAU=", + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "rev": "2d2fb547178ec025da643db57d40a971507b82fe", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "type": "github" + } + }, + "xdph": { + "inputs": { + "hyprland-protocols": [ + "hyprland", + "hyprland-protocols" + ], + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1709299639, + "narHash": "sha256-jYqJM5khksLIbqSxCLUUcqEgI+O2LdlSlcMEBs39CAU=", + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "rev": "2d2fb547178ec025da643db57d40a971507b82fe", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "type": "github" + } + }, + "zig": { + "inputs": { + "flake-compat": "flake-compat_4", + "flake-utils": "flake-utils_4", + "nixpkgs": "nixpkgs_11" + }, + "locked": { + "lastModified": 1712017348, + "narHash": "sha256-At+mk7gHMk2kbisQhkts8cYkz7XhIRei9+zT3wP8bT8=", + "owner": "mitchellh", + "repo": "zig-overlay", + "rev": "63bdd97bf1c93a1da1c658ec9ab974fef52a7280", + "type": "github" + }, + "original": { + "owner": "mitchellh", + "repo": "zig-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nyx/flake.nix b/nyx/flake.nix new file mode 100644 index 0000000..e97268f --- /dev/null +++ b/nyx/flake.nix @@ -0,0 +1,281 @@ +{ + # https://github.com/notashelf/nyx + description = "My NixOS configuration with *very* questionable stability"; + + outputs = { + self, + flake-parts, + ... + } @ inputs: + flake-parts.lib.mkFlake {inherit inputs;} ({withSystem, ...}: { + # systems for which the `perSystem` attributes will be built + systems = [ + "x86_64-linux" + "aarch64-linux" + # and more if they can be supported ... + ]; + + imports = [ + # add self back to inputs to use as `inputs.self` + # I depend on inputs.self *at least* once + {config._module.args._inputs = inputs // {inherit (inputs) self;};} + + # parts and modules from inputs + inputs.flake-parts.flakeModules.easyOverlay + inputs.treefmt-nix.flakeModule + + # parts of the flake + ./flake/modules # nixos and home-manager modules provided by this flake + ./flake/pkgs # packages exposed by the flake + ./flake/templates # flake templates + + ./flake/args.nix # args that are passed to the flake, moved away from the main file + ./flake/deployments.nix # deploy-rs configurations for active hosts + ./flake/fmt.nix # various formatter configurations for this flake + ./flake/iso-images.nix # local installation media + ./flake/pre-commit.nix # pre-commit hooks, performed before each commit inside the devShell + ./flake/shell.nix # devShells exposed by the flake + ]; + + flake = { + # entry-point for nixos configurations + nixosConfigurations = import ./hosts {inherit inputs withSystem;}; + }; + }); + + inputs = { + # Feature-rich and convenient fork of the Nix package manager + nix-super.url = "github:privatevoid-net/nix-super"; + + # We build against nixos unstable, because stable takes way too long to get things into + # more versions with or without pinned branches can be added if deemed necessary + # stable? never heard of her + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-small.url = "github:NixOS/nixpkgs/nixos-unstable-small"; # moves faster, has less packages + + # sometimes nixpkgs breaks something I need, pin a working commit when that occurs + # nixpkgs-pinned.url = "github:NixOS/nixpkgs/b610c60e23e0583cdc1997c54badfd32592d3d3e"; + + # Powered by + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; + + # Home Manager + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Ever wanted nix error messages to be even more cryptic? + # Try flake-utils today! (Devs I beg you please stop) + flake-utils.url = "github:numtide/flake-utils"; + + # Repo for hardware-specific NixOS modules + nixos-hardware.url = "github:nixos/nixos-hardware"; + + # Nix wrapper for building and testing my system + nh = { + url = "github:viperML/nh"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # multi-profile Nix-flake deploy + deploy-rs.url = "github:serokell/deploy-rs"; + + # A tree-wide formatter + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nixfmt = { + url = "github:nixos/nixfmt"; + flake = false; + }; + + # Project shells + devshell = { + url = "github:numtide/devshell"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # guess what this does + # come on, try + pre-commit-hooks = { + url = "github:cachix/pre-commit-hooks.nix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + # sandbox wrappers for programs + nixpak = { + url = "github:nixpak/nixpak"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-parts.follows = "flake-parts"; + }; + + # This exists, I guess + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; + + # Impermanence + # doesn't offer much above properly used symlinks + # but it *is* convenient + impermanence.url = "github:nix-community/impermanence"; + + # Secure-boot support on nixos + # the interface iss still shaky and I would recommend + # avoiding on production systems for now + lanzaboote = { + url = "github:nix-community/lanzaboote"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + flake-compat.follows = "flake-compat"; + }; + }; + + # nix-index database + nix-index-db = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + atticd = { + url = "github:zhaofengli/attic"; + inputs.nixpkgs.follows = "nixpkgs-small"; + }; + + # Secrets management + agenix = { + url = "github:ryantm/agenix"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; + + # Rust overlay + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + # Nix Language server + nil = { + url = "github:oxalica/nil"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.rust-overlay.follows = "rust-overlay"; + }; + + # neovim nightly packages for nix + neovim-nightly = { + url = "github:nix-community/neovim-nightly-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Personal package overlay + nyxpkgs.url = "github:NotAShelf/nyxpkgs"; + + # Personal neovim-flake + neovim-flake = { + url = "github:NotAShelf/neovim-flake/v0.6"; + inputs = { + nixpkgs.follows = "nixpkgs-small"; + nil.follows = "nil"; + flake-utils.follows = "flake-utils"; + flake-parts.follows = "flake-parts"; + }; + }; + + air-quality-monitor = { + url = "github:NotAShelf/air-quality-monitor"; + inputs.nixpkgs.follows = "nixpkgs-small"; + }; + + # use my own wallpapers repository to provide various wallpapers as nix packages + wallpkgs = { + url = "github:NotAShelf/wallpkgs"; + inputs.nixpkgs.follows = "nixpkgs-small"; + }; + + # anyrun program launcher + anyrun.url = "github:Kirottu/anyrun"; + anyrun-nixos-options = { + url = "github:n3oney/anyrun-nixos-options"; + inputs = { + flake-parts.follows = "flake-parts"; + }; + }; + + # aylur's gtk shell (ags) + ags.url = "github:Aylur/ags"; + + # spicetify for theming spotify + spicetify = { + url = "github:the-argus/spicetify-nix"; + inputs.nixpkgs.follows = "nixpkgs-small"; + }; + + # schizophrenic firefox configuration + schizofox = { + url = "github:schizofox/schizofox"; + inputs = { + nixpkgs.follows = "nixpkgs-small"; + flake-parts.follows = "flake-parts"; + nixpak.follows = "nixpak"; + }; + }; + + # mailserver on nixos + simple-nixos-mailserver = { + url = "gitlab:simple-nixos-mailserver/nixos-mailserver/master"; + inputs.nixpkgs.follows = "nixpkgs-small"; + }; + + # Hyprland & Hyprland Contrib repos + # broken: b0f98a3d3e9e5f5f7f89fa4e855dbeb860e7a0c4 + # works: 2ed032a7fd140ee85483a891fa63c16668019577 + hyprland.url = "github:hyprwm/Hyprland"; + xdg-portal-hyprland.url = "github:hyprwm/xdg-desktop-portal-hyprland"; + hyprpicker.url = "github:hyprwm/hyprpicker"; + hyprpaper.url = "github:hyprwm/hyprpaper"; + + hyprland-contrib = { + url = "github:hyprwm/contrib"; + inputs.nixpkgs.follows = "nixpkgs-small"; + }; + + hyprland-plugins = { + url = "github:hyprwm/hyprland-plugins"; + inputs = { + hyprland.follows = "hyprland"; + }; + }; + }; + + nixConfig = { + extra-substituters = [ + "https://nix-community.cachix.org" + "https://nix-gaming.cachix.org" + "https://hyprland.cachix.org" + "https://cache.privatevoid.net" + "https://nyx.cachix.org" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "nix-gaming.cachix.org-1:nbjlureqMbRAxR1gJ/f3hxemL9svXaZF/Ees8vCUUs4=" + "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" + "cache.privatevoid.net:SErQ8bvNWANeAvtsOESUwVYr2VJynfuc9JRwlzTTkVg=" + "notashelf.cachix.org-1:VTTBFNQWbfyLuRzgm2I7AWSDJdqAa11ytLXHBhrprZk=" + "nyx.cachix.org-1:xH6G0MO9PrpeGe7mHBtj1WbNzmnXr7jId2mCiq6hipE=" + ]; + }; +} diff --git a/nyx/flake/args.nix b/nyx/flake/args.nix new file mode 100644 index 0000000..721c42d --- /dev/null +++ b/nyx/flake/args.nix @@ -0,0 +1,32 @@ +{inputs, ...}: { + perSystem = { + config, + system, + ... + }: { + imports = [ + { + _module.args = { + pkgs = config.legacyPackages; + pins = import ./npins; + }; + } + ]; + + legacyPackages = import inputs.nixpkgs { + inherit system; + config.allowUnfree = true; + config.allowUnsupportedSystem = true; + overlays = []; + }; + }; + + flake = { + # extended nixpkgs library, contains my custom functions + # such as system builders + lib = import (inputs.self + /lib) {inherit inputs;}; + + # add `pins` to self so that the flake may refer it freely + pins = import ./npins; + }; +} diff --git a/nyx/flake/deployments.nix b/nyx/flake/deployments.nix new file mode 100644 index 0000000..3adddaf --- /dev/null +++ b/nyx/flake/deployments.nix @@ -0,0 +1,63 @@ +{ + inputs, + self, + lib, + ... +}: let + includedNodes = ["enyo" "helios"]; + mkNode = name: cfg: let + inherit (cfg.pkgs.stdenv.hostPlatform) system; + deployLib = inputs.deploy-rs.lib.${system}; + in { + # this looks pretty goofy, I should get a simpler domain + # it's actually hostname.namespace.domain.tld but my domain and namespace are the same + hostname = "${name}.notashelf.notashelf.dev"; + sshOpts = ["-p" "30"]; + skipChecks = true; + # currently only a single profile system + profilesOrder = ["system"]; + profiles.system = { + sshUser = "root"; + user = "root"; + path = deployLib.activate.nixos cfg; + }; + }; + nodes = lib.mapAttrs mkNode (lib.filterAttrs (name: _: lib.elem name includedNodes) self.nixosConfigurations); +in { + flake = { + deploy = { + autoRollback = true; + magicRollback = true; + inherit nodes; + }; + }; + + perSystem = { + pkgs, + system, + ... + }: let + deployPkgs = import inputs.nixpkgs { + inherit system; + overlays = [ + inputs.deploy-rs.overlay + (_: prev: { + deploy-rs = { + inherit (pkgs) deploy-rs; + inherit (prev.deploy-rs) lib; + }; + }) + ]; + }; + in { + # evaluation of deployChecks is slow + # checks = (deployPkgs.deploy-rs.lib.deployChecks self.deploy) + + apps.deploy = { + type = "app"; + program = pkgs.writeShellScriptBin "deploy" '' + ${deployPkgs.deploy-rs.deploy-rs}/bin/deploy --skip-checks + ''; + }; + }; +} diff --git a/nyx/flake/fmt.nix b/nyx/flake/fmt.nix new file mode 100644 index 0000000..11e13a2 --- /dev/null +++ b/nyx/flake/fmt.nix @@ -0,0 +1,40 @@ +{ + perSystem = { + inputs', + config, + pkgs, + ... + }: { + # provide the formatter for `nix fmt` + formatter = config.treefmt.build.wrapper; + + # configure treefmt + treefmt = { + projectRootFile = "flake.nix"; + + programs = { + alejandra = { + enable = true; + package = inputs'.nyxpkgs.packages.alejandra-no-ads; + }; + + shellcheck.enable = true; # cannot be configured, errors on basic bash convention + + prettier = { + enable = true; + package = pkgs.prettierd; + excludes = ["*.age"]; + settings = { + editorconfig = true; + }; + }; + + shfmt = { + enable = true; + # https://flake.parts/options/treefmt-nix.html#opt-perSystem.treefmt.programs.shfmt.indent_size + indent_size = 2; # set to 0 to use tabs + }; + }; + }; + }; +} diff --git a/nyx/flake/iso-images.nix b/nyx/flake/iso-images.nix new file mode 100644 index 0000000..dea1a40 --- /dev/null +++ b/nyx/flake/iso-images.nix @@ -0,0 +1,27 @@ +{ + inputs, + self, + ... +}: let + installerModule = "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64-new-kernel-no-zfs-installer.nix"; +in { + # ISO images based on available hosts. We avoid basing ISO images + # on active (i.e. desktop) hosts as they likely have secrets set up. + # Images below are designed specifically to be used as live media + # and can be built with `nix build .#images.` + # alternatively hosts can be built with `nix build .#nixosConfigurations.hostName.config.system.build.isoImage` + flake.images = let + gaea = self.nixosConfigurations."gaea"; + erebus = self.nixosConfigurations."erebus"; + atlas = self.nixosConfigurations."atlas".extendModules {modules = [installerModule];}; + in { + # Installation iso + gaea = gaea.config.system.build.isoImage; + + # air-gapped VM + erebus = erebus.config.system.build.isoImage; + + # Raspberry Pi 400 + atlas = atlas.config.system.build.sdImage; + }; +} diff --git a/nyx/flake/modules/default.nix b/nyx/flake/modules/default.nix new file mode 100644 index 0000000..5154d0f --- /dev/null +++ b/nyx/flake/modules/default.nix @@ -0,0 +1,43 @@ +{self, ...}: let + mkFlakeModule = path: + if builtins.isPath path + then self + path + else builtins.throw "${path} is not a real path! Are you stupid?"; +in { + flake = { + # set of modules exposed by my flake to be consumed by others + # those can be imported by adding this flake as an input and then importing the nixosModules. + # i.e imports = [ inputs.nyx.nixosModules.steam-compat ]; or modules = [ inputs.nyx.nixosModules.steam-compat ]; + nixosModules = { + # extends the steam module from nixpkgs/nixos to add a STEAM_COMPAT_TOOLS option + # moved to nix-gaming + # steam-compat = /modules/extra/shared/nixos/steam; + + # a module for the comma tool that wraps it with nix-index and disabled the command-not-found integration + comma-rewrapped = mkFlakeModule /modules/extra/shared/nixos/comma; + + # an open source implementation of wakatime server + wakapi = mkFlakeModule /modules/extra/shared/nixos/wakapi; + + # we do not want to provide a default module + default = builtins.throw "There is no default module, sorry!"; + }; + + homeManagerModules = { + # now available in home-manager + # xplr = mkModule /modules/extra/shared/home-manager/xplr; + + # a home-baked module for gtklock + # allows definning extra modules and the stylesheet + # FIXME: gtklock is currently broken thanks to the deprecation of the necessary wayland protocol + gtklock = mkFlakeModule /modules/extra/shared/home-manager/gtklock; + + vifm = mkFlakeModule /modules/extra/shared/home-manager/vifm; + + transience = mkFlakeModule /modules/extra/shared/home-manager/transience; + + # again, we do not want to provide a default module + default = builtins.throw "There is no default module, sorry!"; + }; + }; +} diff --git a/nyx/flake/npins/default.nix b/nyx/flake/npins/default.nix new file mode 100644 index 0000000..e5e274a --- /dev/null +++ b/nyx/flake/npins/default.nix @@ -0,0 +1,67 @@ +# Generated by npins. Do not modify; will be overwritten regularly +let + data = builtins.fromJSON (builtins.readFile ./sources.json); + version = data.version; + + mkSource = spec: + assert spec ? type; let + path = + if spec.type == "Git" + then mkGitSource spec + else if spec.type == "GitRelease" + then mkGitSource spec + else if spec.type == "PyPi" + then mkPyPiSource spec + else if spec.type == "Channel" + then mkChannelSource spec + else builtins.throw "Unknown source type ${spec.type}"; + in + spec // {outPath = path;}; + + mkGitSource = { + repository, + revision, + url ? null, + hash, + ... + }: + assert repository ? type; + # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository + # In the latter case, there we will always be an url to the tarball + if url != null + then + (builtins.fetchTarball { + inherit url; + sha256 = hash; # FIXME: check nix version & use SRI hashes + }) + else + assert repository.type == "Git"; + builtins.fetchGit { + url = repository.url; + rev = revision; + # hash = hash; + }; + + mkPyPiSource = { + url, + hash, + ... + }: + builtins.fetchurl { + inherit url; + sha256 = hash; + }; + + mkChannelSource = { + url, + hash, + ... + }: + builtins.fetchTarball { + inherit url; + sha256 = hash; + }; +in + if version == 3 + then builtins.mapAttrs (_: mkSource) data.pins + else throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`" diff --git a/nyx/flake/npins/sources.json b/nyx/flake/npins/sources.json new file mode 100644 index 0000000..2222bb8 --- /dev/null +++ b/nyx/flake/npins/sources.json @@ -0,0 +1,53 @@ +{ + "pins": { + "hmts.nvim": { + "type": "GitRelease", + "repository": { + "type": "GitHub", + "owner": "calops", + "repo": "hmts.nvim" + }, + "pre_releases": false, + "version_upper_bound": null, + "version": "v1.2.2", + "revision": "14fd941d7ec2bb98314a1aacaa2573d97f1629ab", + "url": "https://api.github.com/repos/calops/hmts.nvim/tarball/v1.2.2", + "hash": "09f403w6gglfycghjzx4dc5gv71wqb6ywnmcvm15n1ldxasb6jwd" + }, + "nixpkgs": { + "type": "Channel", + "name": "nixpkgs-unstable", + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.05pre562963.e1fa12d4f6c6/nixexprs.tar.xz", + "hash": "16wdn7j17y9yradygdbdlhlcpqa432hp5ah49cm3b0caqymbgw6h" + }, + "slides.nvim": { + "type": "GitRelease", + "repository": { + "type": "GitHub", + "owner": "notashelf", + "repo": "slides.nvim" + }, + "pre_releases": false, + "version_upper_bound": null, + "version": "v0.1.0", + "revision": "768fde54ac9de657887b605ee93f11993b26c9c2", + "url": "https://api.github.com/repos/notashelf/slides.nvim/tarball/v0.1.0", + "hash": "19pzmwpjdsmyy9ygk6ln1i18qihdffp6dgx4vvccyvvz3shabvhx" + }, + "smart-splits.nvim": { + "type": "GitRelease", + "repository": { + "type": "GitHub", + "owner": "mrjones2014", + "repo": "smart-splits.nvim" + }, + "pre_releases": false, + "version_upper_bound": null, + "version": "v1.2.4", + "revision": "c8a9173d70cbbd1f6e4a414e49e31df2b32a1362", + "url": "https://api.github.com/repos/mrjones2014/smart-splits.nvim/tarball/v1.2.4", + "hash": "0hxy3fv6qp7shwh9wgf20q5i8ba2pzng2dd1dvw27aabibk43ba3" + } + }, + "version": 3 +} diff --git a/nyx/flake/pkgs/anime4k.nix b/nyx/flake/pkgs/anime4k.nix new file mode 100644 index 0000000..ee9a9c5 --- /dev/null +++ b/nyx/flake/pkgs/anime4k.nix @@ -0,0 +1,26 @@ +{ + lib, + stdenvNoCC, + fetchzip, +}: +stdenvNoCC.mkDerivation rec { + pname = "anime4k"; + version = "4.0.1"; + + src = fetchzip { + url = "https://github.com/bloc97/Anime4K/releases/download/v${version}/Anime4K_v4.0.zip"; + stripRoot = false; + sha256 = "18x5q7zvkf5l0b2phh70ky6m99fx1pi6mhza4041b5hml7w987pl"; + }; + + installPhase = '' + mkdir $out + cp *.glsl $out + ''; + + meta = { + description = "A High-Quality Real Time Upscaler for Anime Video"; + homepage = "https://github.com/bloc97/Anime4K"; + license = lib.licenses.mit; + }; +} diff --git a/nyx/flake/pkgs/box64-wrapper.nix b/nyx/flake/pkgs/box64-wrapper.nix new file mode 100644 index 0000000..c5afa4c --- /dev/null +++ b/nyx/flake/pkgs/box64-wrapper.nix @@ -0,0 +1,38 @@ +{ + stdenv, + lib, + makeWrapper, + box64, + x64-bash, + pkg, + deps, + bins ? "${lib.getBin pkg}/bin/*", + entry ? "${box64}/bin/box64", + extraWrapperArgs ? [], +}: +stdenv.mkDerivation rec { + name = "box64-wrapped-${pkg.name}"; + + dontUnpack = true; + dontConfigure = true; + dontBuild = true; + + nativeBuildInputs = [makeWrapper]; + + buildInputs = deps; + + installPhase = '' + runHook preInstall + + for bin in ${bins}; do + mkdir -p $out/bin + makeWrapper ${entry} $out/bin/"$(basename "$bin")" \ + --set BOX64_BASH ${lib.getBin x64-bash}/bin/bash \ + --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath buildInputs} \ + ${lib.strings.concatStringsSep " " extraWrapperArgs}\ + --add-flags "$bin" + done + + runHook postInstall + ''; +} diff --git a/nyx/flake/pkgs/default.nix b/nyx/flake/pkgs/default.nix new file mode 100644 index 0000000..913153d --- /dev/null +++ b/nyx/flake/pkgs/default.nix @@ -0,0 +1,21 @@ +{inputs, ...}: { + systems = [ + "x86_64-linux" + "aarch64-linux" + ]; + + perSystem = {pkgs, ...}: let + inherit (pkgs) callPackage; + in { + packages = { + schizofox-startpage = callPackage ./startpage {}; + plymouth-themes = callPackage ./plymouth-themes.nix {}; + anime4k = callPackage ./anime4k.nix {}; + spotify-wrapped = callPackage ./spotify-wrapped.nix {}; + nicksfetch = callPackage ./nicksfetch.nix {}; + present = callPackage ./present.nix {}; + modprobed-db = callPackage ./modprobed-db.nix {}; + nixfmt-rfc = callPackage ./nixfmt-rfc.nix {inherit inputs;}; + }; + }; +} diff --git a/nyx/flake/pkgs/modprobed-db.nix b/nyx/flake/pkgs/modprobed-db.nix new file mode 100644 index 0000000..b600538 --- /dev/null +++ b/nyx/flake/pkgs/modprobed-db.nix @@ -0,0 +1,45 @@ +{ + lib, + stdenv, + fetchFromGitHub, + pkg-config, + libevdev, + kmod, + sudo, + withSudo ? false, +}: +stdenv.mkDerivation rec { + pname = "modprobed-db"; + version = "2.44"; + + src = fetchFromGitHub { + owner = "graysky2"; + repo = pname; + rev = "v${version}"; + sha256 = "sha256-APvA96NoYPtUyuzqGWCqOpB73Vz3qhkMvHWExHXhkKM="; + }; + + nativeBuildInputs = [pkg-config]; + + buildInputs = + [kmod libevdev] + ++ lib.optional withSudo sudo; + + postPatch = '' + substituteInPlace ./common/modprobed-db.in --replace "/usr/share" "$out/share" + ''; + + installFlags = ["DESTDIR=$(out)" "PREFIX="]; + + meta = { + homepage = "https://github.com/graysky2/modprobed-db"; + description = "useful utility for users wishing to build a minimal kernel via a make localmodconfig"; + longDescription = '' + Keeps track of EVERY kernel module that has ever been probed. + + Useful for those of us who make localmodconfig :)''; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [NotAShelf]; + platforms = lib.platforms.linux; + }; +} diff --git a/nyx/flake/pkgs/nicksfetch.nix b/nyx/flake/pkgs/nicksfetch.nix new file mode 100644 index 0000000..371725a --- /dev/null +++ b/nyx/flake/pkgs/nicksfetch.nix @@ -0,0 +1,53 @@ +{ + lib, + stdenvNoCC, + fetchFromGitHub, + bash, + makeWrapper, + pciutils, + x11Support ? true, + ueberzug, +}: +stdenvNoCC.mkDerivation { + pname = "nicksfetch"; + version = "unstable-2021-12-10"; + + src = fetchFromGitHub { + owner = "dylanaraps"; + repo = "neofetch"; + rev = "ccd5d9f52609bbdcd5d8fa78c4fdb0f12954125f"; + sha256 = "sha256-9MoX6ykqvd2iB0VrZCfhSyhtztMpBTukeKejfAWYW1w="; + }; + + patches = [ + ./patches/0002-nicksfetch.patch + ]; + + outputs = ["out" "man"]; + + strictDeps = true; + buildInputs = [bash]; + nativeBuildInputs = [makeWrapper]; + postPatch = '' + patchShebangs --host neofetch + ''; + + postInstall = '' + wrapProgram $out/bin/neofetch \ + --prefix PATH : ${lib.makeBinPath ([pciutils] ++ lib.optional x11Support ueberzug)} + ''; + + makeFlags = [ + "PREFIX=${placeholder "out"}" + "SYSCONFDIR=${placeholder "out"}/etc" + ]; + + meta = { + description = "A fast, highly customizable system info script"; + homepage = "https://github.com/dylanaraps/neofetch"; + license = lib.licenses.mit; + platforms = lib.platforms.all; + maintainers = with lib.maintainers; [alibabzo konimex notashelf]; + mainProgram = "neofetch"; + }; +} diff --git a/nyx/flake/pkgs/nixfmt-rfc.nix b/nyx/flake/pkgs/nixfmt-rfc.nix new file mode 100644 index 0000000..c6f5086 --- /dev/null +++ b/nyx/flake/pkgs/nixfmt-rfc.nix @@ -0,0 +1,12 @@ +{ + inputs, + nixfmt-rfc-style, + ... +}: +nixfmt-rfc-style.overrideAttrs (self: let + pname = "nixfmt-rfc"; + version = "${self.version}-${inputs.nixfmt.shortRev}"; +in { + inherit pname version; + src = inputs.nixfmt; +}) diff --git a/nyx/flake/pkgs/patches/0001-patch-plugindir-to-output.patch b/nyx/flake/pkgs/patches/0001-patch-plugindir-to-output.patch new file mode 100644 index 0000000..197d134 --- /dev/null +++ b/nyx/flake/pkgs/patches/0001-patch-plugindir-to-output.patch @@ -0,0 +1,25 @@ +From 0eaef67b683683fb423fcb2d5096b3cdf9a4a9cd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= +Date: Sun, 22 Mar 2020 12:26:10 +0100 +Subject: [PATCH] Patch plugindir to output + +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 50edb74..639ee86 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -50,7 +50,7 @@ PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40 gio-unix-2.0 gmodule-2.0 ]) + PKG_CHECK_MODULES([cairo], [cairo]) + PKG_CHECK_MODULES([rofi], [rofi >= 1.5.4]) + +-[rofi_PLUGIN_INSTALL_DIR]="`$PKG_CONFIG --variable=pluginsdir rofi`" ++[rofi_PLUGIN_INSTALL_DIR]="`echo $out/lib/rofi`" + AC_SUBST([rofi_PLUGIN_INSTALL_DIR]) + + LT_INIT([disable-static]) +-- +2.25.1 + diff --git a/nyx/flake/pkgs/patches/0002-nicksfetch.patch b/nyx/flake/pkgs/patches/0002-nicksfetch.patch new file mode 100644 index 0000000..d316d53 --- /dev/null +++ b/nyx/flake/pkgs/patches/0002-nicksfetch.patch @@ -0,0 +1,90 @@ +diff --git a/neofetch b/neofetch +index 48b96d21..a2270c9a 100755 +--- a/neofetch ++++ b/neofetch +@@ -46,7 +46,7 @@ LC_ALL=C + LANG=C + + # Fix issues with gsettings. +-export GIO_EXTRA_MODULES=/usr/lib/x86_64-linux-gnu/gio/modules/ ++[[ -z $GIO_EXTRA_MODULES ]] && export GIO_EXTRA_MODULES=/usr/lib/x86_64-linux-gnu/gio/modules/ + + # Neofetch default config. + read -rd '' config <<'EOF' +@@ -999,6 +999,13 @@ get_distro() { + *) distro="OS Elbrus $(< /etc/mcst_version)" + esac + ++ elif [[ -f /etc/NIXOS ]]; then ++ case $distro_shorthand in ++ on) distro="Nick's OS $(nixos-version | awk '{print substr($1,0,5),$2}')" ;; ++ tiny) distro="NixOS" ;; ++ *) distro="Nick's OS $(nixos-version)" ;; ++ esac ++ + elif type -p pveversion >/dev/null; then + case $distro_shorthand in + on|tiny) distro="Proxmox VE" ;; +@@ -8951,29 +8958,38 @@ EOF + "nixos_old"*) + set_colors 4 6 + read -rd '' ascii_data <<'EOF' +-${c1} ::::. ${c2}'::::: ::::' +-${c1} '::::: ${c2}':::::. ::::' +-${c1} ::::: ${c2}'::::.::::: +-${c1} .......:::::..... ${c2}:::::::: +-${c1} ::::::::::::::::::. ${c2}:::::: ${c1}::::. +- ::::::::::::::::::::: ${c2}:::::. ${c1}.::::' +-${c2} ..... ::::' ${c1}:::::' +-${c2} ::::: '::' ${c1}:::::' +-${c2} ........::::: ' ${c1}:::::::::::. +-${c2}::::::::::::: ${c1}::::::::::::: +-${c2} ::::::::::: ${c1}.. ${c1}::::: +-${c2} .::::: ${c1}.::: ${c1}::::: +-${c2} .::::: ${c1}::::: ${c1}''''' ${c2}..... +- ::::: ${c1}':::::. ${c2}......:::::::::::::' +- ::: ${c1}::::::. ${c2}':::::::::::::::::' +-${c1} .:::::::: ${c2}':::::::::: +-${c1} .::::''::::. ${c2}'::::. +-${c1} .::::' ::::. ${c2}'::::. +-${c1} .:::: :::: ${c2}'::::. +-EOF +- ;; +- +- "NixOS"*) ++${c1} ____ ${c2}_______ ____ ++${c1} /####\ ${c2}\######\ /####\ ++${c1} ######\ ${c2}\######\ /#####/ ++${c1} \######\ ${c2}\######\ /#####/ ++${c1} \######\ ${c2}\######\/#####/ ${c1}/\ ++${c1} \######\ ${c2}\###########/ ${c1}/##\ ++${c1} ________\######\______${c2}\#########/ ${c1}/####\ ++${c1} /#######################${c2}\#######/ ${c1}/###### ++${c1} /#########################${c2}\######\ ${c1}/######/ ++${c1} /###########################${c2}\######\ ${c1}/######/ ++${c1} ¯¯¯¯¯¯¯¯¯¯¯¯${c2}/######/${c1}¯¯¯¯¯¯¯¯¯${c2}\######${c1}/######/ ++${c2} /######/ ${c2}\####${c1}/######/________ ++${c2} _____________/######/ ${c2}\##${c1}/################\ ++${c2} /###################/ ${c2}\${c1}/##################\ ++${c2} \##################/${c1}\ /###################/ ++${c2} \################/${c1}##\ /######/¯¯¯¯¯¯¯¯¯¯¯¯¯ ++${c2} ¯¯¯¯¯¯¯¯/######/${c1}####\ /######/ ++${c2} /######/${c1}######\${c2}_________${c1}/######/${c2}____________ ++${c2} /######/ ${c1}\######\${c2}###########################/ ++${c2} /######/ ${c1}\######\${c2}#########################/ ++${c2} ######/ ${c1}/#######\${c2}#######################/ ++${c2} \####/ ${c1}/#########\${c2}¯¯¯¯¯¯\######\¯¯¯¯¯¯¯¯ ++${c2} \##/ ${c1}/###########\${c2} \######\ ++${c2} \/ ${c1}/#####/\######\${c2} \######\ ++${c1} ${c1}/#####/ \######\${c2} \######\ ++${c1} ${c1}/#####/ \######\${c2} \###### ++${c1} ${c1}\####/ \######\${c2} \####/ ++${c1} ${c1}¯¯¯¯ ¯¯¯¯¯¯¯${c2} ¯¯¯¯ ++EOF ++ ;; ++ ++ "Nicks OS"*) + set_colors 4 6 + read -rd '' ascii_data <<'EOF' + ${c1} ▗▄▄▄ ${c2}▗▄▄▄▄ ▄▄▄▖ + diff --git a/nyx/flake/pkgs/plymouth-themes.nix b/nyx/flake/pkgs/plymouth-themes.nix new file mode 100644 index 0000000..19eabbf --- /dev/null +++ b/nyx/flake/pkgs/plymouth-themes.nix @@ -0,0 +1,42 @@ +{ + lib, + stdenv, + fetchFromGitHub, + pack ? 2, + theme ? "green_blocks", + ... +}: +stdenv.mkDerivation rec { + pname = "plymouth-themes"; + version = "1.0.0"; + + strictDeps = true; + + src = fetchFromGitHub { + owner = "adi1090x"; + repo = "plymouth-themes"; + rev = "bf2f570bee8e84c5c20caac353cbe1d811a4745f"; + sha256 = "sha256-VNGvA8ujwjpC2rTVZKrXni2GjfiZk7AgAn4ZB4Baj2k="; + }; + + configurePhase = '' + runHook preConfigure + mkdir -p $out/share/plymouth/themes + runHook postConfigure + ''; + + installPhase = '' + runHook preInstall + cp -r ./pack_${toString pack}/${theme} $out/share/plymouth/themes + sed -i 's;/usr/share;${placeholder "out"}/share;g' \ + $out/share/plymouth/themes/${theme}/${theme}.plymouth + runHook postInstall + ''; + + meta = { + description = "A collection of plymouth themes ported from Android."; + inherit (src.meta) homepage; + license = lib.licenses.gpl3; + platforms = lib.platforms.linux; + }; +} diff --git a/nyx/flake/pkgs/present.nix b/nyx/flake/pkgs/present.nix new file mode 100644 index 0000000..43ae72c --- /dev/null +++ b/nyx/flake/pkgs/present.nix @@ -0,0 +1,15 @@ +# yoinked from https://github.com/viperML/dotfiles because it's funny +# sue me +{runCommandLocal}: +runCommandLocal "present" { +} '' + mkdir -p $out + for ((i=0;i + + + + Startpage + + +
+
notashelf@nyx ~ $ > ls
+ + + +
+ + + + diff --git a/nyx/flake/pkgs/startpage/src/search.js b/nyx/flake/pkgs/startpage/src/search.js new file mode 100644 index 0000000..f89dfac --- /dev/null +++ b/nyx/flake/pkgs/startpage/src/search.js @@ -0,0 +1,78 @@ +String.prototype.replaceChars = function (character, replacement) { + return this.split(character).join(replacement); +}; + +function search(query) { + const searchPrefix = query.substring(0, 2); + query = query.substring(3); + + switch (searchPrefix) { + case "-a": + window.location = `http://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=${query.replaceChars( + " ", + "+", + )}`; + break; + + case "-y": + window.location = `https://www.youtube.com/results?search_query=${query.replaceChars( + " ", + "+", + )}`; + break; + + case "-w": + window.location = `https://en.wikipedia.org/w/index.php?search=${query.replaceChars( + " ", + "%20", + )}`; + break; + + case "-m": + window.location = `http://www.wolframalpha.com/input/?i=${query.replaceChars( + "+", + "%2B", + )}`; + break; + + case "-h": + window.location = `http://alpha.wallhaven.cc/search?q=${query}&categories=111&purity=100&resolutions=1920x1080&sorting=relevance&order=desc`; + break; + + default: + window.location = `https://search.notashelf.dev/search?q=${query.replaceChars( + " ", + "+", + )}&categories=general`; + } +} + +window.onload = function () { + const searchInput = document.getElementById("searchbox"); + if (searchInput) { + searchInput.addEventListener("keypress", function (event) { + if (event.keyCode === 13) { + search(this.value); + } + }); + } +}; + +// +// To add a new search provider, paste the following between the last "break;" and "default:" (Line 39 & 40) +// +// case "-a": +// query = query.substr(3); +// window.location = +// "https://en.website.com/" + +// query.replaceChars(" ", "%20"); +// break; +// +// -a on ln68 should be replaced with a "-letter" of your choice. You can also change it to !a, .a, /a etc. +// https://en.website.com/ on ln70 should be replaced with the search page of the website. To find this, make a few searches on your website. +//Try to identify where your search is in the URL. If you're not sure, post in the thread and someone should help you out +// +// You can use the above two to modify an existing rule +// +// If you wish to change the number of characters in a "case", you need to change the line below, changing query.substr() to n+1, n being the number of characters. +// This ensures that when you search for something, the whole of your idenfier and the space between the identifier and query are removed. diff --git a/nyx/flake/pkgs/startpage/src/style.css b/nyx/flake/pkgs/startpage/src/style.css new file mode 100644 index 0000000..77e344d --- /dev/null +++ b/nyx/flake/pkgs/startpage/src/style.css @@ -0,0 +1,130 @@ +body { + background-color: #11111b; + color: #cdd6f4; +} + +#Title { + font-family: "Malgun Gothic"; + text-align: center; + color: #cdd6f4; + margin-top: 75px; +} + +#searchbox { + width: 500; + height: 4%; + border: none; + border-radius: 2px; + outline: none; + padding-left: 15px; + text-align: left; + background-color: #1e1e2e; + color: #cdd6f4; + font-size: 15px; + font-family: "Malgun Gothic", sans-serif; + display: block; + margin: auto; + margin-top: 50px; +} + +#stripe { + width: 100%; + vertical-align: middle; +} + +#mainframe { + text-align: center; + position: absolute; + top: 25%; + left: 16%; + right: 11%; +} + +#footer { + position: absolute; + bottom: 0; + right: 0; + text-align: right; + padding: 10px; + font-size: 30%; +} + +#linkblock { + width: 20%; + height: 140px; + margin-left: 25px; + margin-right: 30px; + margin-top: 30px; + margin-bottom: 40px; + padding-left: 67px; + padding-right: 1px; + padding-top: 0px; + padding-bottom: 5px; + color: #cdd6f4; + text-align: left; + background-position: top 0px left 0px; + background-repeat: no-repeat; + font-family: "Malgun Gothic"; + font-size: 100%; + display: inline-block; + vertical-align: top; + border-left: 3px solid #181825; + transition: 0.5s; +} + +ul { + list-style-type: none; + padding-left: 0; +} + +a:link { + text-decoration: none; + font-weight: normal; + color: #89b4fa; +} +a:visited { + text-decoration: none; + font-weight: normal; + color: #89b4fa; +} +a:hover { + text-decoration: none; + font-weight: normal; + color: #b4befe; +} +a:active { + text-decoration: none; + font-weight: normal; + color: #89b4fa; +} +a:focus { + text-decoration: none; + font-weight: normal; + color: #89b4fa; +} + +#footer a:link { + text-decoration: none; + font-weight: normal; + color: #101010; +} +#footer a:visited { + text-decoration: none; + font-weight: normal; + color: #101010; +} +#footer a:hover { + text-decoration: none; + font-weight: normal; + color: #101010; +} +#footer a:active { + text-decoration: none; + font-weight: normal; + color: #101010; +} +#footer a:focus { + text-decoration: none; + font-weight: normal; + color: #101010; +} diff --git a/nyx/flake/pre-commit.nix b/nyx/flake/pre-commit.nix new file mode 100644 index 0000000..651cdc6 --- /dev/null +++ b/nyx/flake/pre-commit.nix @@ -0,0 +1,53 @@ +{inputs, ...}: { + imports = [inputs.pre-commit-hooks.flakeModule]; + + perSystem = { + config, + pkgs, + ... + }: let + # configure a general exclude list + excludes = ["flake.lock" "r'.+\.age$'" "r'.+\.sh$'"]; + + # mkHook just defaults failfast to true + # and sets the description from the name + mkHook = name: prev: + { + inherit excludes; + description = "pre-commit hook for ${name}"; + fail_fast = true; # running hooks if this hook fails + verbose = true; + } + // prev; + in { + pre-commit = { + check.enable = true; + + settings = { + # inherit the global exclude list + inherit excludes; + + # hooks that we want to enable + hooks = { + alejandra = mkHook "Alejandra" {enable = true;}; + actionlint = mkHook "actionlint" {enable = true;}; + luacheck = mkHook "luacheck" {enable = true;}; + treefmt = mkHook "treefmt" {enable = true;}; + + editorconfig-checker = mkHook "editorconfig" { + enable = false; + always_run = true; + }; + + prettier = mkHook "prettier" { + enable = true; + settings = { + binPath = "${pkgs.prettierd}/bin/prettierd"; + write = true; + }; + }; + }; + }; + }; + }; +} diff --git a/nyx/flake/shell.nix b/nyx/flake/shell.nix new file mode 100644 index 0000000..4d2f496 --- /dev/null +++ b/nyx/flake/shell.nix @@ -0,0 +1,42 @@ +{ + perSystem = { + inputs', + config, + pkgs, + ... + }: { + devShells.default = pkgs.mkShell { + name = "nyx"; + meta.description = "The default development shell for my NixOS configuration"; + + shellHook = '' + ${config.pre-commit.installationScript} + ''; + + # tell direnv to shut up + DIRENV_LOG_FORMAT = ""; + + # packages available in the dev shell + packages = with pkgs; [ + inputs'.agenix.packages.default # provide agenix CLI within flake shell + inputs'.deploy-rs.packages.default # provide deploy-rs CLI within flake shell + config.treefmt.build.wrapper # treewide formatter + nil # nix ls + alejandra # nix formatter + git # flakes require git, and so do I + glow # markdown viewer + statix # lints and suggestions + deadnix # clean up unused nix code + nodejs # for ags and eslint_d + (pkgs.writeShellApplication { + name = "update"; + text = '' + nix flake update && git commit flake.lock -m "flake: bump inputs" + ''; + }) + ]; + + inputsFrom = [config.treefmt.build.devShell]; + }; + }; +} diff --git a/nyx/flake/templates/c/.editorconfig b/nyx/flake/templates/c/.editorconfig new file mode 100644 index 0000000..f267605 --- /dev/null +++ b/nyx/flake/templates/c/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.c] +ident_style = space +ident_size = 4 + +[Makefile*] +ident_style = tab +ident_size = 4 diff --git a/nyx/flake/templates/c/.gitignore b/nyx/flake/templates/c/.gitignore new file mode 100644 index 0000000..c7efe2a --- /dev/null +++ b/nyx/flake/templates/c/.gitignore @@ -0,0 +1,3 @@ +# ignore build artifacts +result +build diff --git a/nyx/flake/templates/c/default.nix b/nyx/flake/templates/c/default.nix new file mode 100644 index 0000000..f019868 --- /dev/null +++ b/nyx/flake/templates/c/default.nix @@ -0,0 +1,9 @@ +{clangStdenv}: +clangStdenv.mkDerivation { + pname = "sample-c-cpp"; + version = "0.0.1"; + + src = ./.; + + makeFlags = ["PREFIX=$(out)"]; +} diff --git a/nyx/flake/templates/c/flake.nix b/nyx/flake/templates/c/flake.nix new file mode 100644 index 0000000..2d30939 --- /dev/null +++ b/nyx/flake/templates/c/flake.nix @@ -0,0 +1,25 @@ +{ + description = "C/C++ Project Template"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + ... + }: let + systems = ["x86_64-linux" "aarch64-linux"]; + forEachSystem = nixpkgs.lib.genAttrs systems; + + pkgsForEach = nixpkgs.legacyPackages; + in { + packages = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./default.nix {}; + }); + + devShells = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./shell.nix {}; + }); + }; +} diff --git a/nyx/flake/templates/c/makefile b/nyx/flake/templates/c/makefile new file mode 100644 index 0000000..01a94a9 --- /dev/null +++ b/nyx/flake/templates/c/makefile @@ -0,0 +1,42 @@ +PREFIX ?= /usr/local # this is overriden by the derivation makeFlags +BIN_DIR ?= $(PREFIX)/bin + + +TARGET_EXEC ?= foo-bar +BUILD_DIR ?= ./build +SRC_DIRS ?= ./src + +SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c) +OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) +DEPS := $(OBJS:.o=.d) + +INC_DIRS := $(shell find $(SRC_DIRS) -type d) +INC_FLAGS := $(addprefix -I,$(INC_DIRS)) + +CPPFLAGS ?= $(INC_FLAGS) -MMD -MP + +$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS) + $(CXX) $(OBJS) -o $@ $(LDFLAGS) + +# c source +$(BUILD_DIR)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# c++ source +$(BUILD_DIR)/%.cpp.o: %.cpp + mkdir -p $(dir $@) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ + +.PHONY: clean install run + +clean: + rm -r $(BUILD_DIR) + +install: $(BUILD_DIR)/$(TARGET_EXEC) + install -Dt $(BIN_DIR) $< + +run: $(BUILD_DIR)/$(TARGET_EXEC) + ./$< + +-include $(DEPS) diff --git a/nyx/flake/templates/c/shell.nix b/nyx/flake/templates/c/shell.nix new file mode 100644 index 0000000..ddbb899 --- /dev/null +++ b/nyx/flake/templates/c/shell.nix @@ -0,0 +1,36 @@ +{ + callPackage, + clang-tools, + gnumake, + cmake, + bear, + libcxx, + cppcheck, + llvm, + gdb, + glm, + SDL2, + SDL2_gfx, +}: let + mainPkg = callPackage ./default.nix {}; +in + mainPkg.overrideAttrs (oa: { + nativeBuildInputs = + [ + clang-tools # fix headers not found + gnumake # builder + cmake # another builder + bear # bear. + libcxx # stdlib for cpp + cppcheck # static analysis + llvm.lldb # debugger + gdb # another debugger + llvm.libstdcxxClang # LSP and compiler + llvm.libcxx # stdlib for C++ + # libs + glm + SDL2 + SDL2_gfx + ] + ++ (oa.nativeBuildInputs or []); + }) diff --git a/nyx/flake/templates/c/src/main.cpp b/nyx/flake/templates/c/src/main.cpp new file mode 100644 index 0000000..027a273 --- /dev/null +++ b/nyx/flake/templates/c/src/main.cpp @@ -0,0 +1,7 @@ +#include + +int main() { + std::cout << "Hello, World!"; + + return 0; +} diff --git a/nyx/flake/templates/default.nix b/nyx/flake/templates/default.nix new file mode 100644 index 0000000..e05dd80 --- /dev/null +++ b/nyx/flake/templates/default.nix @@ -0,0 +1,23 @@ +_: { + flake.templates = { + c = { + path = ./c; # C/C++ + description = "Development environment for C/C++"; + }; + + rust = { + path = ./rust; # Rust + description = "Development environment for Rust"; + }; + + node = { + path = ./node; # NodeJS + description = "Development environment for NodeJS"; + }; + + go = { + path = ./go; # golang + description = "Development environment for Golang"; + }; + }; +} diff --git a/nyx/flake/templates/go/default.nix b/nyx/flake/templates/go/default.nix new file mode 100644 index 0000000..8e52f83 --- /dev/null +++ b/nyx/flake/templates/go/default.nix @@ -0,0 +1,11 @@ +{buildGoModule}: +buildGoModule { + pname = "sample-go"; + version = "0.0.1"; + + src = ./.; + + vendorHash = ""; + + ldflags = ["-s" "-w"]; +} diff --git a/nyx/flake/templates/go/flake.nix b/nyx/flake/templates/go/flake.nix new file mode 100644 index 0000000..0a3b2e2 --- /dev/null +++ b/nyx/flake/templates/go/flake.nix @@ -0,0 +1,26 @@ +{ + description = "Golang Project Template"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + }: let + systems = ["x86_64-linux" "aarch64-linux"]; + forEachSystem = nixpkgs.lib.genAttrs systems; + + pkgsForEach = nixpkgs.legacyPackages; + in rec { + packages = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./default.nix {}; + }); + + devShells = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./shell.nix {}; + }); + + hydraJobs = packages; + }; +} diff --git a/nyx/flake/templates/go/go.mod b/nyx/flake/templates/go/go.mod new file mode 100644 index 0000000..51af470 --- /dev/null +++ b/nyx/flake/templates/go/go.mod @@ -0,0 +1,3 @@ +module notashelf.dev/sample + +go 1.20 diff --git a/nyx/flake/templates/go/main.go b/nyx/flake/templates/go/main.go new file mode 100644 index 0000000..a3dd973 --- /dev/null +++ b/nyx/flake/templates/go/main.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("Hello, World!") +} diff --git a/nyx/flake/templates/go/shell.nix b/nyx/flake/templates/go/shell.nix new file mode 100644 index 0000000..57104c6 --- /dev/null +++ b/nyx/flake/templates/go/shell.nix @@ -0,0 +1,15 @@ +{ + callPackage, + gopls, + go, +}: let + mainPkg = callPackage ./default.nix {}; +in + mainPkg.overrideAttrs (oa: { + nativeBuildInputs = + [ + gopls + go + ] + ++ (oa.nativeBuildInputs or []); + }) diff --git a/nyx/flake/templates/node/.gitignore b/nyx/flake/templates/node/.gitignore new file mode 100644 index 0000000..d539751 --- /dev/null +++ b/nyx/flake/templates/node/.gitignore @@ -0,0 +1,3 @@ +result +build +node_modules diff --git a/nyx/flake/templates/node/default.nix b/nyx/flake/templates/node/default.nix new file mode 100644 index 0000000..5bb53bc --- /dev/null +++ b/nyx/flake/templates/node/default.nix @@ -0,0 +1,12 @@ +{ + lib, + buildNpmPackage, +}: +buildNpmPackage { + pname = "foo-bar"; + version = "0.1.0"; + + src = ./.; + + npmDepsHash = lib.fakeSha256; +} diff --git a/nyx/flake/templates/node/flake.nix b/nyx/flake/templates/node/flake.nix new file mode 100644 index 0000000..d12fe4e --- /dev/null +++ b/nyx/flake/templates/node/flake.nix @@ -0,0 +1,26 @@ +{ + description = "NodeJS Project Template"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + }: let + systems = ["x86_64-linux" "aarch64-linux"]; + forEachSystem = nixpkgs.lib.genAttrs systems; + + pkgsForEach = nixpkgs.legacyPackages; + in rec { + packages = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./default.nix {}; + }); + + devShells = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./shell.nix {}; + }); + + hydraJobs = packages; + }; +} diff --git a/nyx/flake/templates/node/package.json b/nyx/flake/templates/node/package.json new file mode 100644 index 0000000..d362ca6 --- /dev/null +++ b/nyx/flake/templates/node/package.json @@ -0,0 +1,19 @@ +{ + "name": "sample-nodejs", + "version": "0.0.1", + "description": "Sample node program", + "bin": { + "sample-node": "build/index.js" + }, + "scripts": { + "build": "tsc", + "start": "npm run build && node build/index.js" + }, + "author": "NotAShelf", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.1.2", + "typescript": "^5.0.4", + "typescript-language-server": "^3.3.2" + } +} diff --git a/nyx/flake/templates/node/shell.nix b/nyx/flake/templates/node/shell.nix new file mode 100644 index 0000000..58ec4b3 --- /dev/null +++ b/nyx/flake/templates/node/shell.nix @@ -0,0 +1,24 @@ +{ + callPackage, + writeShellScriptBin, + eslint_d, + prettierd, +}: let + mainPkg = callPackage ./default.nix {}; + mkNpxAlias = name: writeShellScriptBin name "npx ${name} \"$@\""; +in + mainPkg.overrideAttrs (oa: { + nativeBuildInputs = + [ + eslint_d + prettierd + (mkNpxAlias "tsc") + (mkNpxAlias "tsserver") + ] + ++ (oa.nativeBuildInputs or []); + + shellHook = '' + eslint_d start # start eslint daemon + eslint_d status # inform user about eslint daemon status + ''; + }) diff --git a/nyx/flake/templates/node/src/index.ts b/nyx/flake/templates/node/src/index.ts new file mode 100644 index 0000000..940a3ff --- /dev/null +++ b/nyx/flake/templates/node/src/index.ts @@ -0,0 +1 @@ +console.log("Hello world!"); diff --git a/nyx/flake/templates/node/tsconfig.json b/nyx/flake/templates/node/tsconfig.json new file mode 100644 index 0000000..0e48dd3 --- /dev/null +++ b/nyx/flake/templates/node/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es2016", + "lib": ["es6"], + "module": "commonjs", + "rootDir": "src", + "resolveJsonModule": true, + "allowJs": true, + "outDir": "build", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "skipLibCheck": true + } +} diff --git a/nyx/flake/templates/python/.envrc b/nyx/flake/templates/python/.envrc new file mode 100644 index 0000000..fcffbd5 --- /dev/null +++ b/nyx/flake/templates/python/.envrc @@ -0,0 +1 @@ +use flake . --builders "" diff --git a/nyx/flake/templates/python/default.nix b/nyx/flake/templates/python/default.nix new file mode 100644 index 0000000..b7c0313 --- /dev/null +++ b/nyx/flake/templates/python/default.nix @@ -0,0 +1,24 @@ +{ + lib, + python3Packages, + doCheck ? false, + ... +}: +python3Packages.buildPythonApplication { + pname = "sample-python-project"; + version = "0.0.1"; + + src = ./.; + + propagatedBuildInputs = with python3Packages; []; + + nativeCheckInputs = [ + python3Packages.pytest + ]; + + checkPhase = lib.optionals doCheck '' + runHook preCheck + pytest + runHook postCheck + ''; +} diff --git a/nyx/flake/templates/python/flake.nix b/nyx/flake/templates/python/flake.nix new file mode 100644 index 0000000..47d3b28 --- /dev/null +++ b/nyx/flake/templates/python/flake.nix @@ -0,0 +1,26 @@ +{ + description = "Python Project Template"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + }: let + systems = ["x86_64-linux" "aarch64-linux"]; + forEachSystem = nixpkgs.lib.genAttrs systems; + + pkgsForEach = nixpkgs.legacyPackages; + in rec { + packages = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./default.nix {}; + }); + + devShells = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./shell.nix {}; + }); + + hydraJobs = packages; + }; +} diff --git a/nyx/flake/templates/python/shell.nix b/nyx/flake/templates/python/shell.nix new file mode 100644 index 0000000..9fa8a12 --- /dev/null +++ b/nyx/flake/templates/python/shell.nix @@ -0,0 +1,13 @@ +{ + callPackage, + mkShellNoCC, + python3, + ... +}: let + defaultPackage = callPackage ./default.nix; +in + mkShellNoCC { + packages = [ + (python3.withPackages defaultPackage.propagatedBuildInputs) + ]; + } diff --git a/nyx/flake/templates/rust/Cargo.toml b/nyx/flake/templates/rust/Cargo.toml new file mode 100644 index 0000000..c0a1285 --- /dev/null +++ b/nyx/flake/templates/rust/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "sample-rust" +version = "0.0.1" +license = "MIT" +edition = "2021" diff --git a/nyx/flake/templates/rust/default.nix b/nyx/flake/templates/rust/default.nix new file mode 100644 index 0000000..58798a6 --- /dev/null +++ b/nyx/flake/templates/rust/default.nix @@ -0,0 +1,8 @@ +{rustPlatform}: +rustPlatform.buildRustPackage { + pname = "sample-rust"; + version = "0.0.1"; + + src = ./.; + cargoLock.lockFile = ./Cargo.lock; +} diff --git a/nyx/flake/templates/rust/flake.nix b/nyx/flake/templates/rust/flake.nix new file mode 100644 index 0000000..0b7a0dd --- /dev/null +++ b/nyx/flake/templates/rust/flake.nix @@ -0,0 +1,26 @@ +{ + description = "Rust Project Template"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + }: let + systems = ["x86_64-linux" "aarch64-linux"]; + forEachSystem = nixpkgs.lib.genAttrs systems; + + pkgsForEach = nixpkgs.legacyPackages; + in rec { + packages = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./default.nix {}; + }); + + devShells = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./shell.nix {}; + }); + + hydraJobs = packages; + }; +} diff --git a/nyx/flake/templates/rust/shell.nix b/nyx/flake/templates/rust/shell.nix new file mode 100644 index 0000000..8150363 --- /dev/null +++ b/nyx/flake/templates/rust/shell.nix @@ -0,0 +1,20 @@ +{ + callPackage, + rust-analyzer, + rustfmt, + clippy, + cargo, +}: let + mainPkg = callPackage ./default.nix {}; +in + mainPkg.overrideAttrs (oa: { + nativeBuildInputs = + [ + # Additional rust tooling + rust-analyzer + rustfmt + clippy + cargo + ] + ++ (oa.nativeBuildInputs or []); + }) diff --git a/nyx/flake/templates/rust/src/main.rs b/nyx/flake/templates/rust/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/nyx/flake/templates/rust/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/nyx/homes/default.nix b/nyx/homes/default.nix new file mode 100644 index 0000000..43bea19 --- /dev/null +++ b/nyx/homes/default.nix @@ -0,0 +1,49 @@ +{ + inputs', + self', + self, + config, + lib, + ... +}: let + inherit (self) inputs; + inherit (lib.modules) mkIf; + inherit (lib.attrsets) genAttrs; + inherit (config) modules; + + env = modules.usrEnv; + sys = modules.system; + defaults = sys.programs.default; + + specialArgs = {inherit inputs self inputs' self' defaults;}; +in { + home-manager = mkIf env.useHomeManager { + # tell home-manager to be as verbose as possible + verbose = true; + + # use the system configuration’s pkgs argument + # this ensures parity between nixos' pkgs and hm's pkgs + useGlobalPkgs = true; + + # enable the usage user packages through + # the users.users..packages option + useUserPackages = true; + + # move existing files to the .hm.old suffix rather than failing + # with a very long error message about it + backupFileExtension = "hm.old"; + + # extra specialArgs passed to Home Manager + # for reference, the config argument in nixos can be accessed + # in home-manager through osConfig without us passing it + extraSpecialArgs = specialArgs; + + # per-user Home Manager configuration + # the genAttrs function generates an attribute set of users + # as `user = ./user` where user is picked from a list of + # users in modules.system.users + # the system expects user directories to be found in the present + # directory, or will exit with directory not found errors + users = genAttrs config.modules.system.users (name: ./${name}); + }; +} diff --git a/nyx/homes/notashelf/default.nix b/nyx/homes/notashelf/default.nix new file mode 100644 index 0000000..4df65f5 --- /dev/null +++ b/nyx/homes/notashelf/default.nix @@ -0,0 +1,52 @@ +{ + self, + lib, + ... +}: let + inherit (lib) mkDefault; +in { + imports = [ + # imported home-manager modules + self.homeManagerModules.gtklock # a home-manager module for gtklock, gotta upstream it eventually + + # home package sets + ./packages + + # programs and services that I use + ./programs + ./services + + # declarative system and program themes (qt/gtk) + ./themes + + # things that don't fint anywhere else + ./misc + ]; + + config = { + home = { + username = "notashelf"; + homeDirectory = "/home/notashelf"; + extraOutputsToInstall = ["doc" "devdoc"]; + + # + # I will personally strangle every moron who just puts nothing but "DONT CHANGE" next + # to this value + # NOTE: this is and should remain the version on which you have initiated your config + stateVersion = mkDefault "23.05"; + }; + + manual = { + # the docs suck, so we disable them to save space + html.enable = false; + json.enable = false; + manpages.enable = true; + }; + + # let HM manage itself when in standalone mode + programs.home-manager.enable = true; + + # reload system units when changing configs + systemd.user.startServices = mkDefault "sd-switch"; # or "legacy" if "sd-switch" breaks again + }; +} diff --git a/nyx/homes/notashelf/misc/dconf.nix b/nyx/homes/notashelf/misc/dconf.nix new file mode 100644 index 0000000..4768d57 --- /dev/null +++ b/nyx/homes/notashelf/misc/dconf.nix @@ -0,0 +1,16 @@ +{ + dconf.settings = { + # this is like a system-wide dark mode switch that some apps respect + # equivalent of the following dconf command: + # `conf write /org/gnome/desktop/interface/color-scheme "'prefer-dark'"` + "org/gnome/desktop/interface" = { + color-scheme = "prefer-dark"; + }; + + # tell virt-manager to use the system connection + "org/virt-manager/virt-manager/connections" = { + autoconnect = ["qemu:///system"]; + uris = ["qemu:///system"]; + }; + }; +} diff --git a/nyx/homes/notashelf/misc/default.nix b/nyx/homes/notashelf/misc/default.nix new file mode 100644 index 0000000..2ee2ac0 --- /dev/null +++ b/nyx/homes/notashelf/misc/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./dconf.nix # dconf settings, courtesy of the dconf module + ./rnnoise.nix # rnnoise plugin for pipewire + ]; +} diff --git a/nyx/homes/notashelf/misc/rnnoise.nix b/nyx/homes/notashelf/misc/rnnoise.nix new file mode 100644 index 0000000..adcec98 --- /dev/null +++ b/nyx/homes/notashelf/misc/rnnoise.nix @@ -0,0 +1,56 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig.modules) device; + + format = pkgs.formats.json {}; + + acceptedTypes = ["desktop" "laptop"]; +in { + config = mkIf (builtins.elem device.type acceptedTypes) { + # Write a PipeWire userspace configuration based on werman's noise-supression-for-voice + # for usage instructions, see: + # + xdg.configFile."pipewire/pipewire.conf.d/99-input-denoising.conf".source = format.generate "99-input-denoising.conf" { + "context.modules" = [ + { + "name" = "libpipewire-module-filter-chain"; + "args" = { + "node.description" = "Noise Canceling source"; + "media.name" = "Noise Canceling source"; + "filter.graph" = { + "nodes" = [ + { + "type" = "ladspa"; + "name" = "rnnoise"; + "plugin" = "${pkgs.rnnoise-plugin}/lib/ladspa/librnnoise_ladspa.so"; + "label" = "noise_suppressor_mono"; # or "noise_suppressor_stereo", consumes twice the resources + "control" = { + "VAD Threshold (%)" = 50.0; + "VAD Grace Period (ms)" = 200; + "Retroactive VAD Grace (ms)" = 0; + }; + } + ]; + }; + "audio.position" = ["FL" "FR"]; + "capture.props" = { + "node.name" = "effect_input.rnnoise"; + "node.passive" = true; + "audio.rate" = 48000; + }; + "playback.props" = { + "node.name" = "effect_output.rnnoise"; + "media.class" = "Audio/Source"; + "audio.rate" = 48000; + }; + }; + } + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/packages/cli/default.nix b/nyx/homes/notashelf/packages/cli/default.nix new file mode 100644 index 0000000..4bc5cfb --- /dev/null +++ b/nyx/homes/notashelf/packages/cli/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./shared.nix + ./desktop.nix + ./wayland.nix + ./whitehat.nix + ./server.nix + ]; +} diff --git a/nyx/homes/notashelf/packages/cli/desktop.nix b/nyx/homes/notashelf/packages/cli/desktop.nix new file mode 100644 index 0000000..ef00d9d --- /dev/null +++ b/nyx/homes/notashelf/packages/cli/desktop.nix @@ -0,0 +1,29 @@ +{ + osConfig, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + prg = modules.system.programs; + dev = modules.device; + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + config = mkIf ((builtins.elem dev.type acceptedTypes) && prg.cli.enable) { + home.packages = with pkgs; [ + # CLI + libnotify + imagemagick + gcc + cmake + bitwarden-cli + trash-cli + slides + brightnessctl + tesseract5 + pamixer + ]; + }; +} diff --git a/nyx/homes/notashelf/packages/cli/server.nix b/nyx/homes/notashelf/packages/cli/server.nix new file mode 100644 index 0000000..f2a8382 --- /dev/null +++ b/nyx/homes/notashelf/packages/cli/server.nix @@ -0,0 +1,18 @@ +{ + pkgs, + lib, + osConfig, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + prg = modules.system.programs; + dev = modules.device; +in { + config = mkIf (prg.cli.enable && (builtins.elem dev.type ["server" "hybrid"])) { + home.packages = with pkgs; [ + wireguard-tools + ]; + }; +} diff --git a/nyx/homes/notashelf/packages/cli/shared.nix b/nyx/homes/notashelf/packages/cli/shared.nix new file mode 100644 index 0000000..cf67cbb --- /dev/null +++ b/nyx/homes/notashelf/packages/cli/shared.nix @@ -0,0 +1,40 @@ +{ + osConfig, + lib, + pkgs, + inputs', + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + prg = modules.system.programs; +in { + config = mkIf prg.cli.enable { + home.packages = with pkgs; [ + # packages from inputs + inputs'.agenix.packages.default + inputs'.nyxpkgs.packages.cloneit + + # CLI packages from nixpkgs + catimg + duf + todo + hyperfine + fzf + file + unzip + ripgrep + rsync + fd + jq + figlet + lm_sensors + dconf + nitch + skim + p7zip + btop + ]; + }; +} diff --git a/nyx/homes/notashelf/packages/cli/wayland.nix b/nyx/homes/notashelf/packages/cli/wayland.nix new file mode 100644 index 0000000..780f3f1 --- /dev/null +++ b/nyx/homes/notashelf/packages/cli/wayland.nix @@ -0,0 +1,50 @@ +{ + osConfig, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + dev = osConfig.modules.device; + env = osConfig.modules.usrEnv; + acceptedTypes = ["laptop" "desktop" "hybrid" "lite"]; +in { + config = mkIf ((builtins.elem dev.type acceptedTypes) && env.isWayland) { + home.packages = with pkgs; [ + # CLI + grim + slurp + grim + wl-clipboard + pngquant + wf-recorder + (pkgs.writeShellApplication { + name = "ocr"; + runtimeInputs = with pkgs; [tesseract grim slurp]; + text = '' + set -x + + echo "Generating a random ID..." + id=$(tr -dc 'a-zA-Z0-9' + # + # get overriden idiot + /* + (gnome.gnome-control-center.overrideAttrs + (old: { + # gnome-control-center does not start without XDG_CURRENT_DESKTOP=gnome + preFixup = + '' + gappsWrapperArgs+=( + --set XDG_CURRENT_DESKTOP "gnome" + ); + '' + + old.preFixup; + })) + */ + ]; + }; +} diff --git a/nyx/homes/notashelf/packages/gui/wayland.nix b/nyx/homes/notashelf/packages/gui/wayland.nix new file mode 100644 index 0000000..5f5ce2c --- /dev/null +++ b/nyx/homes/notashelf/packages/gui/wayland.nix @@ -0,0 +1,19 @@ +{ + osConfig, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + env = osConfig.modules.usrEnv; + sys = osConfig.modules.system; + prg = sys.programs; +in { + config = mkIf (prg.gui.enable && (sys.video.enable && env.isWayland)) { + home.packages = with pkgs; [ + wlogout + swappy + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/default.nix b/nyx/homes/notashelf/programs/default.nix new file mode 100644 index 0000000..4c80ac8 --- /dev/null +++ b/nyx/homes/notashelf/programs/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./graphical + ./media + ./terminal + ]; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/chromium/default.nix b/nyx/homes/notashelf/programs/graphical/apps/chromium/default.nix new file mode 100644 index 0000000..bd7199a --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/chromium/default.nix @@ -0,0 +1,88 @@ +{ + lib, + pkgs, + osConfig, + ... +}: let + inherit (lib) mkIf optionals concatStringsSep; + inherit (osConfig) modules; + + env = modules.usrEnv; + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.chromium.enable { + programs.chromium = { + enable = true; + extensions = [ + {id = "mnjggcdmjocbbbhaepdhchncahnbgone";} # sponsor block + {id = "cjpalhdlnbpafiamejdnhcphjbkeiagm";} # ublock + {id = "nngceckbapebfimnlniiiahkandclblb";} # bitwarden + {id = "iaiomicjabeggjcfkbimgmglanimpnae";} # tab manager + ]; + + package = pkgs.ungoogled-chromium.override { + nss = pkgs.nss_latest; + commandLineArgs = + [ + # Ungoogled features + "--disable-search-engine-collection" + "--extension-mime-request-handling=always-prompt-for-install" + "--fingerprinting-canvas-image-data-noise" + "--fingerprinting-canvas-measuretext-noise" + "--fingerprinting-client-rects-noise" + "--popups-to-tabs" + "--show-avatar-button=incognito-and-guest" + + # Experimental features + "--enable-features=${ + concatStringsSep "," [ + "BackForwardCache:enable_same_site/true" + "CopyLinkToText" + "OverlayScrollbar" + "TabHoverCardImages" + "VaapiVideoDecoder" + ] + }" + + # Aesthetics + "--force-dark-mode" + + # Performance + "--enable-gpu-rasterization" + "--enable-oop-rasterization" + "--enable-zero-copy" + "--ignore-gpu-blocklist" + + # Etc + # "--gtk-version=4" + "--disk-cache=$XDG_RUNTIME_DIR/chromium-cache" + "--no-default-browser-check" + "--no-service-autorun" + "--disable-features=PreloadMediaEngagementData,MediaEngagementBypassAutoplayPolicies" + "--disable-reading-from-canvas" + "--no-pings" + "--no-first-run" + "--no-experiments" + "--no-crash-upload" + "--disable-wake-on-wifi" + "--disable-breakpad" + "--disable-sync" + "--disable-speech-api" + "--disable-speech-synthesis-api" + ] + ++ optionals env.isWayland [ + # Wayland + + # Disabled because hardware acceleration doesn't work + # when disabling --use-gl=egl, it's not gonna show any emoji + # and it's gonna be slow as hell + # "--use-gl=egl" + + "--ozone-platform=wayland" + "--enable-features=UseOzonePlatform" + ]; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/default.nix b/nyx/homes/notashelf/programs/graphical/apps/default.nix new file mode 100644 index 0000000..2059d7a --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/default.nix @@ -0,0 +1,15 @@ +{ + imports = [ + ./chromium + ./discord + ./element + ./obs + ./office + ./schizofox + ./spotify + ./thunderbird + ./vscode + ./webcord + ./zathura + ]; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/discord/default.nix b/nyx/homes/notashelf/programs/graphical/apps/discord/default.nix new file mode 100644 index 0000000..a92392b --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/discord/default.nix @@ -0,0 +1,32 @@ +{ + osConfig, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; + + discord-wrapped = + (pkgs.discord-canary.override { + nss = pkgs.nss_latest; + withOpenASAR = true; + withVencord = true; + }) + .overrideAttrs (old: { + libPath = old.libPath + ":${pkgs.libglvnd}/lib"; + nativeBuildInputs = old.nativeBuildInputs ++ [pkgs.makeWrapper]; + + postFixup = '' + wrapProgram $out/opt/DiscordCanary/DiscordCanary \ + --add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform=wayland}}" + ''; + }); +in { + config = mkIf prg.discord.enable { + home.packages = [discord-wrapped]; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/element/default.nix b/nyx/homes/notashelf/programs/graphical/apps/element/default.nix new file mode 100644 index 0000000..68c1917 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/element/default.nix @@ -0,0 +1,32 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.element.enable { + home.packages = [pkgs.element-desktop]; + + xdg.configFile = { + "Element/config.json".text = builtins.toJSON { + default_server_config = { + "m.homeserver" = { + base_url = "https://notashelf.dev"; + server_name = "notashelf.dev"; + }; + + "m.identity_server" = {base_url = "";}; + }; + + show_labs_settings = true; + default_theme = "dark"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/obs/default.nix b/nyx/homes/notashelf/programs/graphical/apps/obs/default.nix new file mode 100644 index 0000000..7f93a9d --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/obs/default.nix @@ -0,0 +1,26 @@ +{ + lib, + pkgs, + osConfig, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.obs.enable { + programs.obs-studio = { + enable = true; + plugins = with pkgs.obs-studio-plugins; + [ + obs-gstreamer + obs-pipewire-audio-capture + obs-vkcapture + ] + ++ optional env.isWayland + pkgs.obs-studio-plugins.wlrobs; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/office/default.nix b/nyx/homes/notashelf/programs/graphical/apps/office/default.nix new file mode 100644 index 0000000..1556e12 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/office/default.nix @@ -0,0 +1,22 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.libreoffice.enable { + home.packages = with pkgs; [ + libreoffice-qt + hyphen # text hyphenation library + hunspell + hunspellDicts.en_US-large + hunspellDicts.en_GB-large + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/schizofox/default.nix b/nyx/homes/notashelf/programs/graphical/apps/schizofox/default.nix new file mode 100644 index 0000000..1ed567c --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/schizofox/default.nix @@ -0,0 +1,97 @@ +{ + self', + inputs, + osConfig, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + sys = modules.system; + prg = sys.programs; +in { + imports = [inputs.schizofox.homeManagerModule]; + config = mkIf prg.firefox.enable { + programs.schizofox = { + enable = true; + + theme = { + font = "Inter"; + colors = { + background-darker = "181825"; + background = "1e1e2e"; + foreground = "cdd6f4"; + }; + }; + + search = rec { + defaultSearchEngine = "Searxng"; + removeEngines = ["Bing" "Amazon.com" "eBay" "Twitter" "Wikipedia" "LibRedirect" "DuckDuckGo"]; + searxUrl = "https://search.notashelf.dev"; + searxQuery = "${searxUrl}/search?q={searchTerms}&categories=general"; + addEngines = [ + { + Name = "Searxng"; + Description = "Decentralized search engine"; + Alias = "sx"; + Method = "GET"; + URLTemplate = "${searxQuery}"; + } + ]; + }; + + security = { + sanitizeOnShutdown = false; + sandbox = true; + noSessionRestore = false; + userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0"; + }; + + misc = { + drmFix = true; + disableWebgl = false; + startPageURL = "file://${self'.packages.schizofox-startpage.outPath}/index.html"; + bookmarks = [ + { + Title = "Nyx"; + URL = "https://github.com/NotAShelf/nyx"; + Placement = "toolbar"; + Folder = "Github"; + } + ]; + }; + + extensions = { + simplefox.enable = true; + darkreader.enable = true; + extraExtensions = let + mkUrl = name: "https://addons.mozilla.org/firefox/downloads/latest/${name}/latest.xpi"; + extensions = [ + { + id = "1018e4d6-728f-4b20-ad56-37578a4de76"; + name = "flagfox"; + } + { + id = "{c2c003ee-bd69-42a2-b0e9-6f34222cb046}"; + name = "auto-tab-discard"; + } + { + id = "{a4c4eda4-fb84-4a84-b4a1-f7c1cbf2a1ad}"; + name = "refined-github-"; + } + { + id = "sponsorBlocker@ajay.app"; + name = "sponsorblock"; + } + { + id = "{446900e4-71c2-419f-a6a7-df9c091e268b}"; + name = "bitwarden-password-manager"; + } + ]; + extraExtensions = builtins.foldl' (acc: ext: acc // {ext.id = {install_url = mkUrl ext.name;};}) {} extensions; + in + extraExtensions; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/spotify/default.nix b/nyx/homes/notashelf/programs/graphical/apps/spotify/default.nix new file mode 100644 index 0000000..00aefa2 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/spotify/default.nix @@ -0,0 +1,50 @@ +{ + lib, + osConfig, + inputs, + self', + pkgs, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; + + spicePkgs = inputs.spicetify.packages.${pkgs.system}.default; +in { + imports = [inputs.spicetify.homeManagerModule]; + config = mkIf prg.spotify.enable { + programs.spicetify = { + spotifyPackage = self'.packages.spotify-wrapped; + enable = true; + injectCss = true; + replaceColors = true; + + overwriteAssets = true; + sidebarConfig = true; + enabledCustomApps = with spicePkgs.apps; [ + lyrics-plus + new-releases + ]; + + theme = spicePkgs.themes.catppuccin; + colorScheme = "mocha"; + + enabledExtensions = with spicePkgs.extensions; [ + fullAppDisplay + shuffle # shuffle+ (special characters are sanitized out of ext names) + hidePodcasts + playlistIcons + lastfm + genre + historyShortcut + bookmark + fullAlbumDate + groupSession + popupLyrics + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/thunderbird/default.nix b/nyx/homes/notashelf/programs/graphical/apps/thunderbird/default.nix new file mode 100644 index 0000000..7955cd9 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/thunderbird/default.nix @@ -0,0 +1,53 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (lib.meta) getExe'; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.thunderbird.enable { + home.packages = with pkgs; [birdtray thunderbird]; + + programs.thunderbird = { + enable = true; + profiles."notashelf" = { + isDefault = true; + userChrome = ""; + userContent = ""; + withExternalGnupg = true; + }; + }; + + /* + systemd.user.services = { + "birdtray" = { + Install.WantedBy = ["graphical-session.target"]; + + Service = { + ExecStart = "${getExe' pkgs.birdtray "birdtray"}"; + Restart = "always"; + # runtime + RuntimeDirectory = "ags"; + ProtectSystem = "strict"; + ProtectHome = "read-only"; + }; + + Unit = { + Description = "mail system tray notification icon for Thunderbird "; + After = ["graphical-session-pre.target"]; + PartOf = [ + "tray.target" + "graphical-session.target" + ]; + }; + }; + }; + */ + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/thunderbird/settings.nix b/nyx/homes/notashelf/programs/graphical/apps/thunderbird/settings.nix new file mode 100644 index 0000000..630b33d --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/thunderbird/settings.nix @@ -0,0 +1,49 @@ +{lib, ...}: let + inherit (lib.generators) toJSON; + extensions = toJSON {} { + "default-theme@mozilla.org" = "5787f490-29b8-436e-a111-640da8590790"; + "google@search.mozilla.org" = "cc340383-7068-4b32-a10f-9f19334bfebc"; + "ddg@search.mozilla.org" = "0c340210-f7ab-48e8-9778-600ed5d00160"; + "amazondotcom@search.mozilla.org" = "881d8fdf-5772-4e33-81ff-faac2d1fa92c"; + "wikipedia@search.mozilla.org" = "7ea3d39d-3eea-430f-9bd7-f902d8124d45"; + "bing@search.mozilla.org" = "f480cce8-68af-4082-908e-f8996153352b"; + "addon@darkreader.org" = "71d6c69d-55f9-4c56-888c-abdcf6efd73d"; + "lightningcalendartabs@jlx.84" = "12d48e41-412e-4d09-835a-fa6fb8c180eb"; + }; +in { + programs.thunderbird.profiles."notashelf".settings = { + "calendar.timezone.useSystemTimezone" = true; + "datareporting.healthreport.uploadEnabled" = false; + "extensions.ui.locale.hidden" = true; + "extensions.webextensions.ExtensionStorageIDB.migrated.addon@darkreader.org" = true; + "extensions.webextensions.uuids" = extensions; + "mail.account.lastKey" = 5; + "mail.close_message_window.on_delete.disabled" = false; + "mail.e2ee.auto_enable" = true; + "mail.imap.chunk_size" = 106496; + "mail.imap.min_chunk_size_threshold" = 159744; + "mail.mdn.report.enabled" = false; + "mail.openMessageBehavior.version" = 1; + "mail.pane_config.dynamic" = 2; + "mail.purge_threshhold_mb" = 20; + "mail.purge_threshold_migrated" = true; + "mail.spam.manualMark" = true; + "mail.spam.version" = 1; + "mail.startup.enabledMailCheckOnce" = true; + "mailnews.mark_message_read.delay" = true; + "mailnews.mark_message_read.delay.interval" = 3; + "mailnews.tags.$label1.color" = "#FF0000"; + "mailnews.tags.$label1.tag" = "Important"; + "mailnews.tags.$label2.color" = "#FF9900"; + "mailnews.tags.$label2.tag" = "Work"; + "mailnews.tags.$label3.color" = "#009900"; + "mailnews.tags.$label3.tag" = "Personal"; + "mailnews.tags.$label4.color" = "#3333FF"; + "mailnews.tags.$label4.tag" = "To Do"; + "mailnews.tags.$label5.color" = "#993399"; + "mailnews.tags.$label5.tag" = "Later"; + "pdfjs.enabledCache.state" = true; + "privacy.donottrackheader.enabled" = true; + "privacy.purge_trackers.date_in_cookie_database" = "0"; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/vscode/default.nix b/nyx/homes/notashelf/programs/graphical/apps/vscode/default.nix new file mode 100644 index 0000000..967f546 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/vscode/default.nix @@ -0,0 +1,139 @@ +{ + lib, + pkgs, + osConfig, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.vscode.enable { + programs.vscode = { + enable = true; + enableExtensionUpdateCheck = true; + enableUpdateCheck = true; + extensions = with pkgs.vscode-extensions; + [ + arrterian.nix-env-selector + bbenoist.nix + catppuccin.catppuccin-vsc + christian-kohler.path-intellisense + dbaeumer.vscode-eslint + eamodio.gitlens + esbenp.prettier-vscode + formulahendry.code-runner + golang.go + ibm.output-colorizer + kamadorueda.alejandra + ms-azuretools.vscode-docker + ms-python.python + ms-python.vscode-pylance + ms-vscode-remote.remote-ssh + ms-vscode.cpptools + naumovs.color-highlight + svelte.svelte-vscode + ms-vsliveshare.vsliveshare + oderwat.indent-rainbow + pkief.material-icon-theme + rust-lang.rust-analyzer + shardulm94.trailing-spaces + sumneko.lua + timonwong.shellcheck + usernamehw.errorlens + xaver.clang-format + yzhang.markdown-all-in-one + james-yu.latex-workshop + redhat.vscode-yaml + ms-azuretools.vscode-docker + irongeek.vscode-env + github.vscode-pull-request-github + github.codespaces + astro-build.astro-vscode + WakaTime.vscode-wakatime + ] + ++ [ + pkgs.vscode-extensions."2gua".rainbow-brackets + ] + ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [ + { + name = "copilot-nightly"; + publisher = "github"; + version = "1.67.7949"; + sha256 = "sha256-ZtUqQeWjXmTz49DUeYkuqSTdVHRC8OfgWv8fuhlHDVc="; + } + { + name = "volar"; + publisher = "vue"; + version = "1.0.12"; + sha256 = "sha256-D9E3KRUOlNVXH4oMv1W0+/mbqO8Se7+6E2F5P/KvCro="; + } + { + name = "vscode-typescript-vue-plugin"; + publisher = "vue"; + version = "1.0.12"; + sha256 = "sha256-WiL+gc9+U861ubLlY/acR+ZcrFT7TdIDR0K1XNNidX8="; + } + { + name = "decay"; + publisher = "decaycs"; + version = "1.0.6"; + sha256 = "sha256-Jtxj6LmHgF7UNaXtXxHkq881BbuPtIJGxR7kdhKr0Uo="; + } + { + name = "vscode-typescript-next"; + publisher = "ms-vscode"; + version = "5.0.202301100"; + sha256 = "sha256-8d/L9F06ZaS9dTOXV6Q40ivI499nfZLQURcLdHXoTSM="; + } + { + name = "vscode-chromium-vector-icons"; + publisher = "adolfdaniel"; + version = "1.0.2"; + sha256 = "sha256-Meo53e/3jUP6YDEXOA/40xghI77jj4iAQus3/S8RPZI="; + } + ]; + userSettings = { + "workbench.iconTheme" = "material-icon-theme"; + "workbench.colorTheme" = "Catppuccin Macchiato"; + "catppuccin.accentColor" = "mauve"; + "editor.fontFamily" = "JetBrainsMono Nerd Font, Material Design Icons, 'monospace', monospace"; + "editor.fontSize" = 16; + "editor.fontLigatures" = true; + "workbench.fontAliasing" = "antialiased"; + "files.trimTrailingWhitespace" = true; + "terminal.integrated.fontFamily" = "JetBrainsMono Nerd Font Mono"; + "window.titleBarStyle" = "custom"; + "terminal.integrated.automationShell.linux" = "nix-shell"; + "terminal.integrated.defaultProfile.linux" = "zsh"; + "terminal.integrated.cursorBlinking" = true; + "terminal.integrated.enableBell" = false; + "editor.formatOnPaste" = true; + "editor.formatOnSave" = true; + "editor.formatOnType" = false; + "editor.minimap.enabled" = false; + "editor.minimap.renderCharacters" = false; + "editor.overviewRulerBorder" = false; + "editor.renderLineHighlight" = "all"; + "editor.inlineSuggest.enabled" = true; + "editor.smoothScrolling" = true; + "editor.suggestSelection" = "first"; + "editor.guides.indentation" = true; + "editor.guides.bracketPairs" = true; + "editor.bracketPairColorization.enabled" = true; + "window.nativeTabs" = true; + "window.restoreWindows" = "all"; + "window.menuBarVisibility" = "toggle"; + "workbench.panel.defaultLocation" = "right"; + "workbench.editor.tabCloseButton" = "left"; + "workbench.startupEditor" = "none"; + "workbench.list.smoothScrolling" = true; + "security.workspace.trust.enabled" = false; + "explorer.confirmDelete" = false; + "breadcrumbs.enabled" = true; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/webcord/default.nix b/nyx/homes/notashelf/programs/graphical/apps/webcord/default.nix new file mode 100644 index 0000000..2f55b45 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/webcord/default.nix @@ -0,0 +1,49 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; + + catppuccin-mocha = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "discord"; + rev = "20abe29b3f0f7c59c4878b1bf6ceae41aeac9afd"; + hash = "sha256-Gjrv1VayPfjcsfSmGJdJTA8xEX6gXhpgTLJ2xrSNcEo="; + }; +in { + config = mkIf prg.webcord.enable { + home.packages = [ + pkgs.webcord-vencord # webcord with vencord extension installed + ]; + + xdg.configFile = { + "WebCord/Themes/mocha" = { + source = "${catppuccin-mocha}/themes/mocha.theme.css"; + }; + }; + + # TODO: maybe this should be under services/global because technically it's not an app + # however arrpc is useless on its own (i.e. without webcord) and here it's merely a + # companion app that we enable for rich presence. + services.arrpc = { + enable = true; + package = pkgs.arrpc.overrideAttrs (_: { + pname = "arrpc"; + version = "3.3.1"; + + src = pkgs.fetchFromGitHub { + owner = "OpenAsar"; + repo = "arrpc"; + rev = "b4796fffe3bf1b1361cc4781024349f7a4f9400e"; + hash = "sha256-iEfV85tRl2KyjodoaSxVHiqweBpLeiCAYWc8+afl/sA="; + }; + }); + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/apps/zathura/default.nix b/nyx/homes/notashelf/programs/graphical/apps/zathura/default.nix new file mode 100644 index 0000000..b7009a2 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/apps/zathura/default.nix @@ -0,0 +1,37 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.zathura.enable { + xdg.configFile."zathura/catppuccin-mocha".source = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/catppuccin/zathura/main/src/catppuccin-mocha"; + hash = "sha256-/HXecio3My2eXTpY7JoYiN9mnXsps4PAThDPs4OCsAk="; + }; + + programs.zathura = { + enable = true; + extraConfig = "include catppuccin-mocha"; + + options = { + font = "Iosevka 15"; + selection-clipboard = "clipboard"; + adjust-open = "best-fit"; + pages-per-row = "1"; + scroll-page-aware = "true"; + scroll-full-overlap = "0.01"; + scroll-step = "100"; + smooth-scroll = true; + zoom-min = "10"; + guioptions = "none"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/default.nix b/nyx/homes/notashelf/programs/graphical/default.nix new file mode 100644 index 0000000..f794608 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/default.nix @@ -0,0 +1,10 @@ +{ + imports = [ + ./apps + ./gaming + ./launchers + ./misc + ./screenlock + ./wms + ]; +} diff --git a/nyx/homes/notashelf/programs/graphical/gaming/chess.nix b/nyx/homes/notashelf/programs/graphical/gaming/chess.nix new file mode 100644 index 0000000..ba179cb --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/gaming/chess.nix @@ -0,0 +1,23 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; +in { + config = mkIf prg.gaming.chess.enable { + home.packages = with pkgs; [ + knights + fairymax + gnome.gnome-chess + stockfish + fishnet + uchess + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/gaming/default.nix b/nyx/homes/notashelf/programs/graphical/gaming/default.nix new file mode 100644 index 0000000..a989e18 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/gaming/default.nix @@ -0,0 +1,34 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; +in { + imports = [ + ./minecraft.nix + ./mangohud.nix + ./chess.nix + ]; + + config = mkIf prg.gaming.enable { + home.packages = with pkgs; [ + legendary-gl # epic games launcher + mangohud # fps counter & vulkan overlay + lutris # alternative game launcher + + # emulators + # dolphin-emu # general console + + # runtime + dotnet-runtime_6 # for running terraria manually, from binary + mono # general dotnet apps + winetricks # wine helper utility + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/gaming/mangohud.nix b/nyx/homes/notashelf/programs/graphical/gaming/mangohud.nix new file mode 100644 index 0000000..025e210 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/gaming/mangohud.nix @@ -0,0 +1,38 @@ +{ + osConfig, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; +in { + config = mkIf prg.gaming.mangohud.enable { + programs.mangohud = { + enable = true; + settings = { + fps_limit = "60,0"; + vsync = 1; + cpu_stats = true; + cpu_temp = true; + gpu_stats = true; + gpu_temp = true; + vulkan_driver = false; + fps = true; + frametime = true; + frame_timing = true; + enableSessionWide = true; + font_size = 24; + position = "top-left"; + engine_version = true; + wine = true; + no_display = true; + background_alpha = "0.5"; + toggle_hud = "Shift_R+F12"; + toggle_fps_limit = "Shift_R+F1"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/gaming/minecraft.nix b/nyx/homes/notashelf/programs/graphical/gaming/minecraft.nix new file mode 100644 index 0000000..e7a56e0 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/gaming/minecraft.nix @@ -0,0 +1,76 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; + + catppuccin-mocha = pkgs.fetchzip { + url = "https://raw.githubusercontent.com/catppuccin/prismlauncher/main/themes/Mocha/Catppuccin-Mocha.zip"; + sha256 = "sha256-8uRqCoe9iSIwNnK13d6S4XSX945g88mVyoY+LZSPBtQ="; + }; +in { + config = mkIf prg.gaming.minecraft.enable { + home = { + # copy the catppuccin theme to the themes directory of PrismLauncher + file.".local/share/PrismLauncher/themes/mocha" = { + source = catppuccin-mocha; + recursive = true; + }; + + packages = let + # java packages that are needed by various versions or modpacks + # different distributions of java may yield different results in performance + # and thus I recommend testing them one by one to remove those that you do not + # need in your configuration + jdks = with pkgs; [ + # Java 8 + temurin-jre-bin-8 + zulu8 + + # Java 11 + temurin-jre-bin-11 + + # Java 17 + temurin-jre-bin-17 + + # Latest + temurin-jre-bin + zulu + graalvm-ce + ]; + + additionalPrograms = with pkgs; [ + gamemode + mangohud + jprofiler + ]; + + glfw = + if env.isWayland + then pkgs.glfw-wayland-minecraft + else pkgs.glfw; + in [ + # the successor to polyMC, which is now mostly abandoned + (pkgs.prismlauncher.override { + # get java versions required by various minecraft versions + # "write once run everywhere" my ass + inherit jdks; + + # wrap Prismlauncher with programs in may need for workarounds + # or client features + inherit additionalPrograms; + + # wrap Prismlauncher with the nixpkgs glfw, or optionally the wayland patched + # version of glfw while we're on Wayland. + inherit glfw; + }) + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/launchers/anyrun/default.nix b/nyx/homes/notashelf/programs/graphical/launchers/anyrun/default.nix new file mode 100644 index 0000000..457a781 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/launchers/anyrun/default.nix @@ -0,0 +1,126 @@ +{ + inputs, + inputs', + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; +in { + imports = [inputs.anyrun.homeManagerModules.default]; + config = mkIf env.programs.launchers.anyrun.enable { + programs.anyrun = { + enable = true; + config = { + plugins = with inputs'.anyrun.packages; [ + applications + rink + translate + randr + shell + symbols + translate + + inputs'.anyrun-nixos-options.packages.default + ]; + + # the x coordinate of the runner + #x.relative = 800; + # the y coordinate of the runner + #y.absolute = 500.0; + y.fraction = 0.02; + + # Hide match and plugin info icons + hideIcons = false; + + # ignore exclusive zones, i.e. Waybar + ignoreExclusiveZones = false; + + # Layer shell layer: Background, Bottom, Top, Overlay + layer = "overlay"; + + # Hide the plugin info panel + hidePluginInfo = false; + + # Close window when a click outside the main box is received + closeOnClick = false; + + # Show search results immediately when Anyrun starts + showResultsImmediately = false; + + # Limit amount of entries shown in total + maxEntries = 10; + }; + + extraConfigFiles = { + "applications.ron".text = '' + Config( + // Also show the Desktop Actions defined in the desktop files, e.g. "New Window" from LibreWolf + desktop_actions: true, + max_entries: 10, + // The terminal used for running terminal based desktop entries, if left as `None` a static list of terminals is used + // to determine what terminal to use. + terminal: Some("footclient"), + ) + ''; + + "randr.ron".text = '' + Config( + prefix: ":ra", + max_entries: 5, + ) + ''; + + "symbols.ron".text = '' + Config( + // The prefix that the search needs to begin with to yield symbol results + prefix: ":sy", + + // Custom user defined symbols to be included along the unicode symbols + symbols: { + // "name": "text to be copied" + "shrug": "¯\\_(ツ)_/¯", + }, + + // The number of entries to be displayed + max_entries: 5, + ) + ''; + + "translate.ron".text = '' + Config( + prefix: ":tr", + language_delimiter: ">", + max_entries: 3, + ) + ''; + + "nixos-options.ron".text = let + nixos-options = osConfig.system.build.manual.optionsJSON + "/share/doc/nixos/options.json"; + neovim-flake-options = inputs'.neovim-flake.packages.docs-json + "/share/doc/neovim-flake/options.json"; + options = builtins.toJSON { + ":nix" = [nixos-options]; + ":vim" = [neovim-flake-options]; + }; + in '' + Config( + options: ${options}, + min_score: 5, + max_entries: Some(3), + ) + ''; + }; + + # this compiles the SCSS file from the given path into CSS + # by default, `-t expanded` as the args to the sass compiler + extraCss = builtins.readFile (lib.compileSCSS pkgs { + name = "style-dark"; + source = ./styles/dark.scss; + }); + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/launchers/anyrun/styles/dark.scss b/nyx/homes/notashelf/programs/graphical/launchers/anyrun/styles/dark.scss new file mode 100644 index 0000000..df52bd4 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/launchers/anyrun/styles/dark.scss @@ -0,0 +1,43 @@ +$fontSize: 1.3rem; +$fontFamily: Lexend; +$transparentColor: transparent; +$rgbaColor: rgba(203, 166, 247, 0.7); +$bgColor: rgba(30, 30, 46, 1); +$borderColor: #28283d; +$borderRadius: 16px; +$paddingValue: 8px; + +* { + transition: 200ms ease; + font-family: $fontFamily; + font-size: $fontSize; +} + +#window, +#match, +#entry, +#plugin, +#main { + background: $transparentColor; +} + +#match:selected { + background: $rgbaColor; +} + +#match { + padding: 3px; + border-radius: $borderRadius; +} + +#entry, +#plugin:hover { + border-radius: $borderRadius; +} + +box#main { + background: $bgColor; + border: 1px solid $borderColor; + border-radius: $borderRadius; + padding: $paddingValue; +} diff --git a/nyx/homes/notashelf/programs/graphical/launchers/default.nix b/nyx/homes/notashelf/programs/graphical/launchers/default.nix new file mode 100644 index 0000000..4ea8e69 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/launchers/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./rofi + ./tofi + ./anyrun + ]; +} diff --git a/nyx/homes/notashelf/programs/graphical/launchers/rofi/default.nix b/nyx/homes/notashelf/programs/graphical/launchers/rofi/default.nix new file mode 100644 index 0000000..4b8e576 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/launchers/rofi/default.nix @@ -0,0 +1,219 @@ +{ + config, + lib, + pkgs, + osConfig, + inputs', + ... +}: let + inherit (lib) mkIf optionals; + inherit (osConfig) modules meta; + + env = modules.usrEnv; + rofiPackage = with pkgs; + if meta.isWayland + then rofi-wayland + else rofi; +in { + config = mkIf env.programs.launchers.rofi.enable { + programs.rofi = { + enable = true; + package = rofiPackage.override { + plugins = + [ + pkgs.rofi-rbw + ] + ++ optionals meta.isWayland (with inputs'.nyxpkgs.packages; [ + rofi-rbw-wayland + rofi-calc-wayland + rofi-emoji-wayland + ]); + }; + font = "Iosevka Nerd Font 14"; + extraConfig = { + modi = "drun,filebrowser,calc,emoji"; + drun-display-format = " {name} "; + sidebar-mode = true; + matching = "prefix"; + scroll-method = 0; + disable-history = false; + show-icons = true; + + display-drun = " Run"; + display-run = " Run"; + display-filebrowser = " Files"; + display-calc = "󰃬 Calculator"; + display-emoji = "💀 Emoji"; + }; + + theme = let + inherit (osConfig.modules.style.colorScheme) colors; + inherit (config.lib.formats.rasi) mkLiteral; + in { + "*" = { + background = mkLiteral "#${colors.base02}"; + background-alt = mkLiteral "#${colors.base02}"; + foreground = mkLiteral "#${colors.base05}"; + selected = mkLiteral "#${colors.base00}"; + active = mkLiteral "#${colors.base0D}"; + urgent = mkLiteral "#${colors.base00}"; + }; + "window" = { + transparency = "real"; + location = mkLiteral "center"; + anchor = mkLiteral "center"; + fullscreen = mkLiteral "false"; + width = mkLiteral "600px"; + x-offset = mkLiteral "0px"; + y-offset = mkLiteral "0px"; + enabled = mkLiteral "true"; + border-radius = mkLiteral "20px"; + border = mkLiteral "4px"; + border-color = mkLiteral "#${colors.base02}"; + cursor = "default"; + background-color = mkLiteral "@background"; + }; + "mainbox" = { + enabled = true; + spacing = mkLiteral "0px"; + background-color = mkLiteral "transparent"; + orientation = mkLiteral "vertical"; + children = mkLiteral "[inputbar,listbox]"; + }; + "listbox" = { + spacing = mkLiteral "10px"; + padding = mkLiteral "10px 10px 10px 15px"; + background-color = mkLiteral "transparent"; + orientation = mkLiteral "vertical"; + children = mkLiteral "[message,listview]"; + }; + "inputbar" = { + enabled = true; + spacing = mkLiteral "10px"; + padding = mkLiteral "30px 20px 30px 20px"; + background-color = mkLiteral "@selected"; + text-color = mkLiteral "@foreground"; + orientation = mkLiteral "horizontal"; + children = mkLiteral "[prompt,entry]"; + }; + "entry" = { + enabled = true; + expand = true; + width = mkLiteral "300px"; + padding = mkLiteral "12px 15px"; + border-radius = mkLiteral "15px"; + background-color = mkLiteral "@background-alt"; + text-color = mkLiteral "inherit"; + cursor = mkLiteral "text"; + placeholder = "Search"; + placeholder-color = mkLiteral "inherit"; + }; + "prompt" = { + width = mkLiteral "64px"; + font = "Iosevka Nerd Font 13"; + padding = mkLiteral "10px 20px 10px 20px"; + border-radius = mkLiteral "15px"; + background-color = mkLiteral "@background-alt"; + text-color = mkLiteral "inherit"; + cursor = mkLiteral "pointer"; + }; + "mode-switcher" = { + enabled = true; + spacing = mkLiteral "10px"; + background-color = mkLiteral "transparent"; + text-color = mkLiteral "@foreground"; + }; + "button" = { + width = mkLiteral "48px"; + font = "Iosevka Nerd Font 14"; + padding = mkLiteral "8px 5px 8px 8px"; + border-radius = mkLiteral "15px"; + background-color = mkLiteral "@background-alt"; + text-color = mkLiteral "inherit"; + cursor = mkLiteral "pointer"; + }; + "button selected" = { + background-color = mkLiteral "@selected"; + text-color = mkLiteral "@foreground"; + }; + "listview" = { + enabled = true; + columns = 2; + lines = 7; + cycle = true; + dynamic = true; + srollbar = false; + layout = mkLiteral "vertical"; + reverse = false; + fixed-height = true; + fixed-columns = false; + spacing = mkLiteral "5px"; + background-color = mkLiteral "transparent"; + text-color = mkLiteral "@foreground"; + cursor = mkLiteral "default"; + }; + "element" = { + enabled = true; + spacing = mkLiteral "15px"; + padding = mkLiteral "7px"; + border-radius = mkLiteral "100%"; + background-color = mkLiteral "transparent"; + text-color = mkLiteral "@foreground"; + cursor = mkLiteral "pointer"; + }; + "element normal.normal" = { + background-color = mkLiteral "inherit"; + text-color = mkLiteral "inherit"; + }; + "element normal.urgent" = { + background-color = mkLiteral "@urgent"; + text-color = mkLiteral "@foreground"; + }; + "element normal.active" = { + background-color = mkLiteral "@background"; + text-color = mkLiteral "@active"; + }; + "element selected.normal" = { + background-color = mkLiteral "@selected"; + text-color = mkLiteral "@foreground"; + }; + "element selected.urgent" = { + background-color = mkLiteral "@urgent"; + text-color = mkLiteral "@foreground"; + }; + "element selected.active" = { + background-color = mkLiteral "@urgent"; + text-color = mkLiteral "@active"; + }; + "element-icon" = { + background-color = mkLiteral "transparent"; + text-color = mkLiteral "inherit"; + size = mkLiteral "32px"; + cursor = mkLiteral "inherit"; + }; + "element-text" = { + background-color = mkLiteral "transparent"; + text-color = mkLiteral "inherit"; + cursor = mkLiteral "inherit"; + vertical-align = mkLiteral "0.5"; + horizontal-align = mkLiteral "0.0"; + }; + "message" = {background-color = mkLiteral "transparent";}; + "textbox" = { + padding = mkLiteral "12px"; + border-radius = mkLiteral "100%"; + background-color = mkLiteral "@background-alt"; + text-color = mkLiteral "@foreground"; + vertical-align = mkLiteral "0.5"; + horizontal-align = mkLiteral "0.0"; + }; + "error-message" = { + padding = mkLiteral "12px"; + border-radius = mkLiteral "20px"; + background-color = mkLiteral "@background"; + text-color = mkLiteral "@foreground"; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/launchers/tofi/default.nix b/nyx/homes/notashelf/programs/graphical/launchers/tofi/default.nix new file mode 100644 index 0000000..86ccb4f --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/launchers/tofi/default.nix @@ -0,0 +1,61 @@ +{ + config, + lib, + pkgs, + osConfig, + ... +}: let + inherit (lib) mkIf getExe; + inherit (osConfig) modules; + + env = modules.usrEnv; +in { + config = mkIf env.programs.launchers.tofi.enable { + home.packages = with pkgs; [ + # for compatibility sake + (pkgs.writeScriptBin "dmenu" ''exec ${getExe tofi}'') + tofi + wtype + ]; + + xdg.configFile."tofi/config".text = let + inherit (osConfig.modules.style.colorScheme) colors; + in '' + font = Iosevka Nerd Font + font-size = 13 + horizontal = true + anchor = top + width = 100% + height = 40 + outline-width = 0 + border-width = 0 + min-input-width = 120 + result-spacing = 30 + padding-top = 10 + padding-bottom = 10 + padding-left = 20 + padding-right = 0 + margin-top = 0 + margin-bottom = 0 + margin-left = 15 + margin-right = 0 + prompt-text = " " + prompt-padding = 30 + background-color = ${colors.base00} + text-color = ${colors.base05} + prompt-color = ${colors.base00} + prompt-background = ${colors.base0D} + prompt-background-padding = 4, 10 + prompt-background-corner-radius = 12 + input-background = ${colors.base02} + input-background-padding = 4, 10 + input-background-corner-radius = 12 + selection-color = ${colors.base01} + selection-background = ${colors.base0D} + selection-background-padding = 4, 10 + selection-background-corner-radius = 12 + selection-match-color = ${colors.base05} + clip-to-padding = false + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/launchers/tofi/emoji b/nyx/homes/notashelf/programs/graphical/launchers/tofi/emoji new file mode 100644 index 0000000..ec6318d --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/launchers/tofi/emoji @@ -0,0 +1,1631 @@ +😀 grinning face +😃 grinning face with big eyes +😄 grinning face with smiling eyes +😁 beaming face with smiling eyes +😆 grinning squinting face +😅 grinning face with sweat +🤣 rolling on the floor laughing +😂 face with tears of joy +🙂 slightly smiling face +🙃 upside-down face +🫠 melting face +😉 winking face +😊 smiling face with smiling eyes +😇 smiling face with halo +🥰 smiling face with hearts +😍 smiling face with heart-eyes +🤩 star-struck +😘 face blowing a kiss +😗 kissing face +☺️ smiling face +😚 kissing face with closed eyes +😙 kissing face with smiling eyes +🥲 smiling face with tear +😋 face savoring food +😛 face with tongue +😜 winking face with tongue +🤪 zany face +😝 squinting face with tongue +🤑 money-mouth face +🤗 smiling face with open hands +🤭 face with hand over mouth +🫢 face with open eyes and hand over mouth +🫣 face with peeking eye +🤫 shushing face +🤔 thinking face +🫡 saluting face +🤐 zipper-mouth face +🤨 face with raised eyebrow +😐 neutral face +😑 expressionless face +😶 face without mouth +🫥 dotted line face +😏 smirking face +😒 unamused face +🙄 face with rolling eyes +😬 grimacing face +🤥 lying face +😌 relieved face +😔 pensive face +😪 sleepy face +🤤 drooling face +😴 sleeping face +😷 face with medical mask +🤒 face with thermometer +🤕 face with head-bandage +🤢 nauseated face +🤮 face vomiting +🤧 sneezing face +🥵 hot face +🥶 cold face +🥴 woozy face +😵 face with crossed-out eyes +🤯 exploding head +🤠 cowboy hat face +🥳 partying face +🥸 disguised face +😎 smiling face with sunglasses +🤓 nerd face +🧐 face with monocle +😕 confused face +🫤 face with diagonal mouth +😟 worried face +🙁 slightly frowning face +☹️ frowning face +😮 face with open mouth +😯 hushed face +😲 astonished face +😳 flushed face +🥺 pleading face +🥹 face holding back tears +😦 frowning face with open mouth +😧 anguished face +😨 fearful face +😰 anxious face with sweat +😥 sad but relieved face +😢 crying face +😭 loudly crying face +😱 face screaming in fear +😖 confounded face +😣 persevering face +😞 disappointed face +😓 downcast face with sweat +😩 weary face +😫 tired face +🥱 yawning face +😤 face with steam from nose +😡 pouting face +😠 angry face +🤬 face with symbols on mouth +😈 smiling face with horns +👿 angry face with horns +💀 skull +☠️ skull and crossbones +💩 pile of poo +🤡 clown face +👹 ogre +👺 goblin +👻 ghost +👽 alien +👾 alien monster +🤖 robot +😺 grinning cat +😸 grinning cat with smiling eyes +😹 cat with tears of joy +😻 smiling cat with heart-eyes +😼 cat with wry smile +😽 kissing cat +🙀 weary cat +😿 crying cat +😾 pouting cat +🙈 see-no-evil monkey +🙉 hear-no-evil monkey +🙊 speak-no-evil monkey +💋 kiss mark +💌 love letter +💘 heart with arrow +💝 heart with ribbon +💖 sparkling heart +💗 growing heart +💓 beating heart +💞 revolving hearts +💕 two hearts +💟 heart decoration +❣️ heart exclamation +💔 broken heart +❤️ red heart +🧡 orange heart +💛 yellow heart +💚 green heart +💙 blue heart +💜 purple heart +🤎 brown heart +🖤 black heart +🤍 white heart +💯 hundred points +💢 anger symbol +💥 collision +💫 dizzy +💦 sweat droplets +💨 dashing away +🕳️ hole +💣 bomb +💬 speech balloon +🗨️ left speech bubble +🗯️ right anger bubble +💭 thought balloon +💤 zzz +👋 waving hand +🤚 raised back of hand +🖐️ hand with fingers splayed +✋ raised hand +🖖 vulcan salute +🫱 rightwards hand +🫲 leftwards hand +🫳 palm down hand +🫴 palm up hand +👌 OK hand +🤌 pinched fingers +🤏 pinching hand +✌️ victory hand +🤞 crossed fingers +🫰 hand with index finger and thumb crossed +🤟 love-you gesture +🤘 sign of the horns +🤙 call me hand +👈 backhand index pointing left +👉 backhand index pointing right +👆 backhand index pointing up +🖕 middle finger +👇 backhand index pointing down +☝️ index pointing up +🫵 index pointing at the viewer +👍 thumbs up +👎 thumbs down +✊ raised fist +👊 oncoming fist +🤛 left-facing fist +🤜 right-facing fist +👏 clapping hands +🙌 raising hands +🫶 heart hands +👐 open hands +🤲 palms up together +🤝 handshake +🙏 folded hands +✍️ writing hand +💅 nail polish +🤳 selfie +💪 flexed biceps +🦾 mechanical arm +🦿 mechanical leg +🦵 leg +🦶 foot +👂 ear +🦻 ear with hearing aid +👃 nose +🧠 brain +🫀 anatomical heart +🫁 lungs +🦷 tooth +🦴 bone +👀 eyes +👁️ eye +👅 tongue +👄 mouth +🫦 biting lip +👶 baby +🧒 child +👦 boy +👧 girl +🧑 person +👱 person: blond hair +👨 man +🧔 person: beard +👩 woman +🧓 older person +👴 old man +👵 old woman +🙍 person frowning +🙎 person pouting +🙅 person gesturing NO +🙆 person gesturing OK +💁 person tipping hand +🙋 person raising hand +🧏 deaf person +🙇 person bowing +🤦 person facepalming +🤷 person shrugging +👮 police officer +🕵️ detective +💂 guard +🥷 ninja +👷 construction worker +🫅 person with crown +🤴 prince +👸 princess +👳 person wearing turban +👲 person with skullcap +🧕 woman with headscarf +🤵 person in tuxedo +👰 person with veil +🤰 pregnant woman +🫃 pregnant man +🫄 pregnant person +🤱 breast-feeding +👼 baby angel +🎅 Santa Claus +🤶 Mrs. Claus +🦸 superhero +🦹 supervillain +🧙 mage +🧚 fairy +🧛 vampire +🧜 merperson +🧝 elf +🧞 genie +🧟 zombie +🧌 troll +💆 person getting massage +💇 person getting haircut +🚶 person walking +🧍 person standing +🧎 person kneeling +🏃 person running +💃 woman dancing +🕺 man dancing +🕴️ person in suit levitating +👯 people with bunny ears +🧖 person in steamy room +🧗 person climbing +🤺 person fencing +🏇 horse racing +⛷️ skier +🏂 snowboarder +🏌️ person golfing +🏄 person surfing +🚣 person rowing boat +🏊 person swimming +⛹️ person bouncing ball +🏋️ person lifting weights +🚴 person biking +🚵 person mountain biking +🤸 person cartwheeling +🤼 people wrestling +🤽 person playing water polo +🤾 person playing handball +🤹 person juggling +🧘 person in lotus position +🛀 person taking bath +🛌 person in bed +👭 women holding hands +👫 woman and man holding hands +👬 men holding hands +💏 kiss +💑 couple with heart +👪 family +🗣️ speaking head +👤 bust in silhouette +👥 busts in silhouette +🫂 people hugging +👣 footprints +🐵 monkey face +🐒 monkey +🦍 gorilla +🦧 orangutan +🐶 dog face +🐕 dog +🦮 guide dog +🐩 poodle +🐺 wolf +🦊 fox +🦝 raccoon +🐱 cat face +🐈 cat +🦁 lion +🐯 tiger face +🐅 tiger +🐆 leopard +🐴 horse face +🐎 horse +🦄 unicorn +🦓 zebra +🦌 deer +🦬 bison +🐮 cow face +🐂 ox +🐃 water buffalo +🐄 cow +🐷 pig face +🐖 pig +🐗 boar +🐽 pig nose +🐏 ram +🐑 ewe +🐐 goat +🐪 camel +🐫 two-hump camel +🦙 llama +🦒 giraffe +🐘 elephant +🦣 mammoth +🦏 rhinoceros +🦛 hippopotamus +🐭 mouse face +🐁 mouse +🐀 rat +🐹 hamster +🐰 rabbit face +🐇 rabbit +🐿️ chipmunk +🦫 beaver +🦔 hedgehog +🦇 bat +🐻 bear +🐨 koala +🐼 panda +🦥 sloth +🦦 otter +🦨 skunk +🦘 kangaroo +🦡 badger +🐾 paw prints +🦃 turkey +🐔 chicken +🐓 rooster +🐣 hatching chick +🐤 baby chick +🐥 front-facing baby chick +🐦 bird +🐧 penguin +🕊️ dove +🦅 eagle +🦆 duck +🦢 swan +🦉 owl +🦤 dodo +🪶 feather +🦩 flamingo +🦚 peacock +🦜 parrot +🐸 frog +🐊 crocodile +🐢 turtle +🦎 lizard +🐍 snake +🐲 dragon face +🐉 dragon +🦕 sauropod +🦖 T-Rex +🐳 spouting whale +🐋 whale +🐬 dolphin +🦭 seal +🐟 fish +🐠 tropical fish +🐡 blowfish +🦈 shark +🐙 octopus +🐚 spiral shell +🪸 coral +🐌 snail +🦋 butterfly +🐛 bug +🐜 ant +🐝 honeybee +🪲 beetle +🐞 lady beetle +🦗 cricket +🪳 cockroach +🕷️ spider +🕸️ spider web +🦂 scorpion +🦟 mosquito +🪰 fly +🪱 worm +🦠 microbe +💐 bouquet +🌸 cherry blossom +💮 white flower +🪷 lotus +🏵️ rosette +🌹 rose +🥀 wilted flower +🌺 hibiscus +🌻 sunflower +🌼 blossom +🌷 tulip +🌱 seedling +🪴 potted plant +🌲 evergreen tree +🌳 deciduous tree +🌴 palm tree +🌵 cactus +🌾 sheaf of rice +🌿 herb +☘️ shamrock +🍀 four leaf clover +🍁 maple leaf +🍂 fallen leaf +🍃 leaf fluttering in wind +🪹 empty nest +🪺 nest with eggs +🍇 grapes +🍈 melon +🍉 watermelon +🍊 tangerine +🍋 lemon +🍌 banana +🍍 pineapple +🥭 mango +🍎 red apple +🍏 green apple +🍐 pear +🍑 peach +🍒 cherries +🍓 strawberry +🫐 blueberries +🥝 kiwi fruit +🍅 tomato +🫒 olive +🥥 coconut +🥑 avocado +🍆 eggplant +🥔 potato +🥕 carrot +🌽 ear of corn +🌶️ hot pepper +🫑 bell pepper +🥒 cucumber +🥬 leafy green +🥦 broccoli +🧄 garlic +🧅 onion +🍄 mushroom +🥜 peanuts +🫘 beans +🌰 chestnut +🍞 bread +🥐 croissant +🥖 baguette bread +🫓 flatbread +🥨 pretzel +🥯 bagel +🥞 pancakes +🧇 waffle +🧀 cheese wedge +🍖 meat on bone +🍗 poultry leg +🥩 cut of meat +🥓 bacon +🍔 hamburger +🍟 french fries +🍕 pizza +🌭 hot dog +🥪 sandwich +🌮 taco +🌯 burrito +🫔 tamale +🥙 stuffed flatbread +🧆 falafel +🥚 egg +🍳 cooking +🥘 shallow pan of food +🍲 pot of food +🫕 fondue +🥣 bowl with spoon +🥗 green salad +🍿 popcorn +🧈 butter +🧂 salt +🥫 canned food +🍱 bento box +🍘 rice cracker +🍙 rice ball +🍚 cooked rice +🍛 curry rice +🍜 steaming bowl +🍝 spaghetti +🍠 roasted sweet potato +🍢 oden +🍣 sushi +🍤 fried shrimp +🍥 fish cake with swirl +🥮 moon cake +🍡 dango +🥟 dumpling +🥠 fortune cookie +🥡 takeout box +🦀 crab +🦞 lobster +🦐 shrimp +🦑 squid +🦪 oyster +🍦 soft ice cream +🍧 shaved ice +🍨 ice cream +🍩 doughnut +🍪 cookie +🎂 birthday cake +🍰 shortcake +🧁 cupcake +🥧 pie +🍫 chocolate bar +🍬 candy +🍭 lollipop +🍮 custard +🍯 honey pot +🍼 baby bottle +🥛 glass of milk +☕ hot beverage +🫖 teapot +🍵 teacup without handle +🍶 sake +🍾 bottle with popping cork +🍷 wine glass +🍸 cocktail glass +🍹 tropical drink +🍺 beer mug +🍻 clinking beer mugs +🥂 clinking glasses +🥃 tumbler glass +🫗 pouring liquid +🥤 cup with straw +🧋 bubble tea +🧃 beverage box +🧉 mate +🧊 ice +🥢 chopsticks +🍽️ fork and knife with plate +🍴 fork and knife +🥄 spoon +🔪 kitchen knife +🫙 jar +🏺 amphora +🌍 globe showing Europe-Africa +🌎 globe showing Americas +🌏 globe showing Asia-Australia +🌐 globe with meridians +🗺️ world map +🗾 map of Japan +🧭 compass +🏔️ snow-capped mountain +⛰️ mountain +🌋 volcano +🗻 mount fuji +🏕️ camping +🏖️ beach with umbrella +🏜️ desert +🏝️ desert island +🏞️ national park +🏟️ stadium +🏛️ classical building +🏗️ building construction +🧱 brick +🪨 rock +🪵 wood +🛖 hut +🏘️ houses +🏚️ derelict house +🏠 house +🏡 house with garden +🏢 office building +🏣 Japanese post office +🏤 post office +🏥 hospital +🏦 bank +🏨 hotel +🏩 love hotel +🏪 convenience store +🏫 school +🏬 department store +🏭 factory +🏯 Japanese castle +🏰 castle +💒 wedding +🗼 Tokyo tower +🗽 Statue of Liberty +⛪ church +🕌 mosque +🛕 hindu temple +🕍 synagogue +⛩️ shinto shrine +🕋 kaaba +⛲ fountain +⛺ tent +🌁 foggy +🌃 night with stars +🏙️ cityscape +🌄 sunrise over mountains +🌅 sunrise +🌆 cityscape at dusk +🌇 sunset +🌉 bridge at night +♨️ hot springs +🎠 carousel horse +🛝 playground slide +🎡 ferris wheel +🎢 roller coaster +💈 barber pole +🎪 circus tent +🚂 locomotive +🚃 railway car +🚄 high-speed train +🚅 bullet train +🚆 train +🚇 metro +🚈 light rail +🚉 station +🚊 tram +🚝 monorail +🚞 mountain railway +🚋 tram car +🚌 bus +🚍 oncoming bus +🚎 trolleybus +🚐 minibus +🚑 ambulance +🚒 fire engine +🚓 police car +🚔 oncoming police car +🚕 taxi +🚖 oncoming taxi +🚗 automobile +🚘 oncoming automobile +🚙 sport utility vehicle +🛻 pickup truck +🚚 delivery truck +🚛 articulated lorry +🚜 tractor +🏎️ racing car +🏍️ motorcycle +🛵 motor scooter +🦽 manual wheelchair +🦼 motorized wheelchair +🛺 auto rickshaw +🚲 bicycle +🛴 kick scooter +🛹 skateboard +🛼 roller skate +🚏 bus stop +🛣️ motorway +🛤️ railway track +🛢️ oil drum +⛽ fuel pump +🛞 wheel +🚨 police car light +🚥 horizontal traffic light +🚦 vertical traffic light +🛑 stop sign +🚧 construction +⚓ anchor +🛟 ring buoy +⛵ sailboat +🛶 canoe +🚤 speedboat +🛳️ passenger ship +⛴️ ferry +🛥️ motor boat +🚢 ship +✈️ airplane +🛩️ small airplane +🛫 airplane departure +🛬 airplane arrival +🪂 parachute +💺 seat +🚁 helicopter +🚟 suspension railway +🚠 mountain cableway +🚡 aerial tramway +🛰️ satellite +🚀 rocket +🛸 flying saucer +🛎️ bellhop bell +🧳 luggage +⌛ hourglass done +⏳ hourglass not done +⌚ watch +⏰ alarm clock +⏱️ stopwatch +⏲️ timer clock +🕰️ mantelpiece clock +🕛 twelve o’clock +🕧 twelve-thirty +🕐 one o’clock +🕜 one-thirty +🕑 two o’clock +🕝 two-thirty +🕒 three o’clock +🕞 three-thirty +🕓 four o’clock +🕟 four-thirty +🕔 five o’clock +🕠 five-thirty +🕕 six o’clock +🕡 six-thirty +🕖 seven o’clock +🕢 seven-thirty +🕗 eight o’clock +🕣 eight-thirty +🕘 nine o’clock +🕤 nine-thirty +🕙 ten o’clock +🕥 ten-thirty +🕚 eleven o’clock +🕦 eleven-thirty +🌑 new moon +🌒 waxing crescent moon +🌓 first quarter moon +🌔 waxing gibbous moon +🌕 full moon +🌖 waning gibbous moon +🌗 last quarter moon +🌘 waning crescent moon +🌙 crescent moon +🌚 new moon face +🌛 first quarter moon face +🌜 last quarter moon face +🌡️ thermometer +☀️ sun +🌝 full moon face +🌞 sun with face +🪐 ringed planet +⭐ star +🌟 glowing star +🌠 shooting star +🌌 milky way +☁️ cloud +⛅ sun behind cloud +⛈️ cloud with lightning and rain +🌤️ sun behind small cloud +🌥️ sun behind large cloud +🌦️ sun behind rain cloud +🌧️ cloud with rain +🌨️ cloud with snow +🌩️ cloud with lightning +🌪️ tornado +🌫️ fog +🌬️ wind face +🌀 cyclone +🌈 rainbow +🌂 closed umbrella +☂️ umbrella +☔ umbrella with rain drops +⛱️ umbrella on ground +⚡ high voltage +❄️ snowflake +☃️ snowman +⛄ snowman without snow +☄️ comet +🔥 fire +💧 droplet +🌊 water wave +🎃 jack-o-lantern +🎄 Christmas tree +🎆 fireworks +🎇 sparkler +🧨 firecracker +✨ sparkles +🎈 balloon +🎉 party popper +🎊 confetti ball +🎋 tanabata tree +🎍 pine decoration +🎎 Japanese dolls +🎏 carp streamer +🎐 wind chime +🎑 moon viewing ceremony +🧧 red envelope +🎀 ribbon +🎁 wrapped gift +🎗️ reminder ribbon +🎟️ admission tickets +🎫 ticket +🎖️ military medal +🏆 trophy +🏅 sports medal +🥇 1st place medal +🥈 2nd place medal +🥉 3rd place medal +⚽ soccer ball +⚾ baseball +🥎 softball +🏀 basketball +🏐 volleyball +🏈 american football +🏉 rugby football +🎾 tennis +🥏 flying disc +🎳 bowling +🏏 cricket game +🏑 field hockey +🏒 ice hockey +🥍 lacrosse +🏓 ping pong +🏸 badminton +🥊 boxing glove +🥋 martial arts uniform +🥅 goal net +⛳ flag in hole +⛸️ ice skate +🎣 fishing pole +🤿 diving mask +🎽 running shirt +🎿 skis +🛷 sled +🥌 curling stone +🎯 bullseye +🪀 yo-yo +🪁 kite +🎱 pool 8 ball +🔮 crystal ball +🪄 magic wand +🧿 nazar amulet +🪬 hamsa +🎮 video game +🕹️ joystick +🎰 slot machine +🎲 game die +🧩 puzzle piece +🧸 teddy bear +🪅 piñata +🪩 mirror ball +🪆 nesting dolls +♠️ spade suit +♥️ heart suit +♦️ diamond suit +♣️ club suit +♟️ chess pawn +🃏 joker +🀄 mahjong red dragon +🎴 flower playing cards +🎭 performing arts +🖼️ framed picture +🎨 artist palette +🧵 thread +🪡 sewing needle +🧶 yarn +🪢 knot +👓 glasses +🕶️ sunglasses +🥽 goggles +🥼 lab coat +🦺 safety vest +👔 necktie +👕 t-shirt +👖 jeans +🧣 scarf +🧤 gloves +🧥 coat +🧦 socks +👗 dress +👘 kimono +🥻 sari +🩱 one-piece swimsuit +🩲 briefs +🩳 shorts +👙 bikini +👚 woman’s clothes +👛 purse +👜 handbag +👝 clutch bag +🛍️ shopping bags +🎒 backpack +🩴 thong sandal +👞 man’s shoe +👟 running shoe +🥾 hiking boot +🥿 flat shoe +👠 high-heeled shoe +👡 woman’s sandal +🩰 ballet shoes +👢 woman’s boot +👑 crown +👒 woman’s hat +🎩 top hat +🎓 graduation cap +🧢 billed cap +🪖 military helmet +⛑️ rescue worker’s helmet +📿 prayer beads +💄 lipstick +💍 ring +💎 gem stone +🔇 muted speaker +🔈 speaker low volume +🔉 speaker medium volume +🔊 speaker high volume +📢 loudspeaker +📣 megaphone +📯 postal horn +🔔 bell +🔕 bell with slash +🎼 musical score +🎵 musical note +🎶 musical notes +🎙️ studio microphone +🎚️ level slider +🎛️ control knobs +🎤 microphone +🎧 headphone +📻 radio +🎷 saxophone +🪗 accordion +🎸 guitar +🎹 musical keyboard +🎺 trumpet +🎻 violin +🪕 banjo +🥁 drum +🪘 long drum +📱 mobile phone +📲 mobile phone with arrow +☎️ telephone +📞 telephone receiver +📟 pager +📠 fax machine +🔋 battery +🪫 low battery +🔌 electric plug +💻 laptop +🖥️ desktop computer +🖨️ printer +⌨️ keyboard +🖱️ computer mouse +🖲️ trackball +💽 computer disk +💾 floppy disk +💿 optical disk +📀 dvd +🧮 abacus +🎥 movie camera +🎞️ film frames +📽️ film projector +🎬 clapper board +📺 television +📷 camera +📸 camera with flash +📹 video camera +📼 videocassette +🔍 magnifying glass tilted left +🔎 magnifying glass tilted right +🕯️ candle +💡 light bulb +🔦 flashlight +🏮 red paper lantern +🪔 diya lamp +📔 notebook with decorative cover +📕 closed book +📖 open book +📗 green book +📘 blue book +📙 orange book +📚 books +📓 notebook +📒 ledger +📃 page with curl +📜 scroll +📄 page facing up +📰 newspaper +🗞️ rolled-up newspaper +📑 bookmark tabs +🔖 bookmark +🏷️ label +💰 money bag +🪙 coin +💴 yen banknote +💵 dollar banknote +💶 euro banknote +💷 pound banknote +💸 money with wings +💳 credit card +🧾 receipt +💹 chart increasing with yen +✉️ envelope +📧 e-mail +📨 incoming envelope +📩 envelope with arrow +📤 outbox tray +📥 inbox tray +📦 package +📫 closed mailbox with raised flag +📪 closed mailbox with lowered flag +📬 open mailbox with raised flag +📭 open mailbox with lowered flag +📮 postbox +🗳️ ballot box with ballot +✏️ pencil +✒️ black nib +🖋️ fountain pen +🖊️ pen +🖌️ paintbrush +🖍️ crayon +📝 memo +💼 briefcase +📁 file folder +📂 open file folder +🗂️ card index dividers +📅 calendar +📆 tear-off calendar +🗒️ spiral notepad +🗓️ spiral calendar +📇 card index +📈 chart increasing +📉 chart decreasing +📊 bar chart +📋 clipboard +📌 pushpin +📍 round pushpin +📎 paperclip +🖇️ linked paperclips +📏 straight ruler +📐 triangular ruler +✂️ scissors +🗃️ card file box +🗄️ file cabinet +🗑️ wastebasket +🔒 locked +🔓 unlocked +🔏 locked with pen +🔐 locked with key +🔑 key +🗝️ old key +🔨 hammer +🪓 axe +⛏️ pick +⚒️ hammer and pick +🛠️ hammer and wrench +🗡️ dagger +⚔️ crossed swords +🔫 water pistol +🪃 boomerang +🏹 bow and arrow +🛡️ shield +🪚 carpentry saw +🔧 wrench +🪛 screwdriver +🔩 nut and bolt +⚙️ gear +🗜️ clamp +⚖️ balance scale +🦯 white cane +🔗 link +⛓️ chains +🪝 hook +🧰 toolbox +🧲 magnet +🪜 ladder +⚗️ alembic +🧪 test tube +🧫 petri dish +🧬 dna +🔬 microscope +🔭 telescope +📡 satellite antenna +💉 syringe +🩸 drop of blood +💊 pill +🩹 adhesive bandage +🩼 crutch +🩺 stethoscope +🩻 x-ray +🚪 door +🛗 elevator +🪞 mirror +🪟 window +🛏️ bed +🛋️ couch and lamp +🪑 chair +🚽 toilet +🪠 plunger +🚿 shower +🛁 bathtub +🪤 mouse trap +🪒 razor +🧴 lotion bottle +🧷 safety pin +🧹 broom +🧺 basket +🧻 roll of paper +🪣 bucket +🧼 soap +🫧 bubbles +🪥 toothbrush +🧽 sponge +🧯 fire extinguisher +🛒 shopping cart +🚬 cigarette +⚰️ coffin +🪦 headstone +⚱️ funeral urn +🗿 moai +🪧 placard +🪪 identification card +🏧 ATM sign +🚮 litter in bin sign +🚰 potable water +♿ wheelchair symbol +🚹 men’s room +🚺 women’s room +🚻 restroom +🚼 baby symbol +🚾 water closet +🛂 passport control +🛃 customs +🛄 baggage claim +🛅 left luggage +⚠️ warning +🚸 children crossing +⛔ no entry +🚫 prohibited +🚳 no bicycles +🚭 no smoking +🚯 no littering +🚱 non-potable water +🚷 no pedestrians +📵 no mobile phones +🔞 no one under eighteen +☢️ radioactive +☣️ biohazard +⬆️ up arrow +↗️ up-right arrow +➡️ right arrow +↘️ down-right arrow +⬇️ down arrow +↙️ down-left arrow +⬅️ left arrow +↖️ up-left arrow +↕️ up-down arrow +↔️ left-right arrow +↩️ right arrow curving left +↪️ left arrow curving right +⤴️ right arrow curving up +⤵️ right arrow curving down +🔃 clockwise vertical arrows +🔄 counterclockwise arrows button +🔙 BACK arrow +🔚 END arrow +🔛 ON! arrow +🔜 SOON arrow +🔝 TOP arrow +🛐 place of worship +⚛️ atom symbol +🕉️ om +✡️ star of David +☸️ wheel of dharma +☯️ yin yang +✝️ latin cross +☦️ orthodox cross +☪️ star and crescent +☮️ peace symbol +🕎 menorah +🔯 dotted six-pointed star +♈ Aries +♉ Taurus +♊ Gemini +♋ Cancer +♌ Leo +♍ Virgo +♎ Libra +♏ Scorpio +♐ Sagittarius +♑ Capricorn +♒ Aquarius +♓ Pisces +⛎ Ophiuchus +🔀 shuffle tracks button +🔁 repeat button +🔂 repeat single button +▶️ play button +⏩ fast-forward button +⏭️ next track button +⏯️ play or pause button +◀️ reverse button +⏪ fast reverse button +⏮️ last track button +🔼 upwards button +⏫ fast up button +🔽 downwards button +⏬ fast down button +⏸️ pause button +⏹️ stop button +⏺️ record button +⏏️ eject button +🎦 cinema +🔅 dim button +🔆 bright button +📶 antenna bars +📳 vibration mode +📴 mobile phone off +♀️ female sign +♂️ male sign +⚧️ transgender symbol +✖️ multiply +➕ plus +➖ minus +➗ divide +🟰 heavy equals sign +♾️ infinity +‼️ double exclamation mark +⁉️ exclamation question mark +❓ red question mark +❔ white question mark +❕ white exclamation mark +❗ red exclamation mark +〰️ wavy dash +💱 currency exchange +💲 heavy dollar sign +⚕️ medical symbol +♻️ recycling symbol +⚜️ fleur-de-lis +🔱 trident emblem +📛 name badge +🔰 Japanese symbol for beginner +⭕ hollow red circle +✅ check mark button +☑️ check box with check +✔️ check mark +❌ cross mark +❎ cross mark button +➰ curly loop +➿ double curly loop +〽️ part alternation mark +✳️ eight-spoked asterisk +✴️ eight-pointed star +❇️ sparkle +©️ copyright +®️ registered +™️ trade mark +#️⃣ keycap: # +*️⃣ keycap: * +0️⃣ keycap: 0 +1️⃣ keycap: 1 +2️⃣ keycap: 2 +3️⃣ keycap: 3 +4️⃣ keycap: 4 +5️⃣ keycap: 5 +6️⃣ keycap: 6 +7️⃣ keycap: 7 +8️⃣ keycap: 8 +9️⃣ keycap: 9 +🔟 keycap: 10 +🔠 input latin uppercase +🔡 input latin lowercase +🔢 input numbers +🔣 input symbols +🔤 input latin letters +🅰️ A button (blood type) +🆎 AB button (blood type) +🅱️ B button (blood type) +🆑 CL button +🆒 COOL button +🆓 FREE button +ℹ️ information +🆔 ID button +Ⓜ️ circled M +🆕 NEW button +🆖 NG button +🅾️ O button (blood type) +🆗 OK button +🅿️ P button +🆘 SOS button +🆙 UP! button +🆚 VS button +🈁 Japanese “here” button +🈂️ Japanese “service charge” button +🈷️ Japanese “monthly amount” button +🈶 Japanese “not free of charge” button +🈯 Japanese “reserved” button +🉐 Japanese “bargain” button +🈹 Japanese “discount” button +🈚 Japanese “free of charge” button +🈲 Japanese “prohibited” button +🉑 Japanese “acceptable” button +🈸 Japanese “application” button +🈴 Japanese “passing grade” button +🈳 Japanese “vacancy” button +㊗️ Japanese “congratulations” button +㊙️ Japanese “secret” button +🈺 Japanese “open for business” button +🈵 Japanese “no vacancy” button +🔴 red circle +🟠 orange circle +🟡 yellow circle +🟢 green circle +🔵 blue circle +🟣 purple circle +🟤 brown circle +⚫ black circle +⚪ white circle +🟥 red square +🟧 orange square +🟨 yellow square +🟩 green square +🟦 blue square +🟪 purple square +🟫 brown square +⬛ black large square +⬜ white large square +◼️ black medium square +◻️ white medium square +◾ black medium-small square +◽ white medium-small square +▪️ black small square +▫️ white small square +🔶 large orange diamond +🔷 large blue diamond +🔸 small orange diamond +🔹 small blue diamond +🔺 red triangle pointed up +🔻 red triangle pointed down +💠 diamond with a dot +🔘 radio button +🔳 white square button +🔲 black square button +🏁 chequered flag +🚩 triangular flag +🎌 crossed flags +🏴 black flag +🏳️ white flag +🇦🇨 flag: Ascension Island +🇦🇩 flag: Andorra +🇦🇪 flag: United Arab Emirates +🇦🇫 flag: Afghanistan +🇦🇬 flag: Antigua & Barbuda +🇦🇮 flag: Anguilla +🇦🇱 flag: Albania +🇦🇲 flag: Armenia +🇦🇴 flag: Angola +🇦🇶 flag: Antarctica +🇦🇷 flag: Argentina +🇦🇸 flag: American Samoa +🇦🇹 flag: Austria +🇦🇺 flag: Australia +🇦🇼 flag: Aruba +🇦🇽 flag: Åland Islands +🇦🇿 flag: Azerbaijan +🇧🇦 flag: Bosnia & Herzegovina +🇧🇧 flag: Barbados +🇧🇩 flag: Bangladesh +🇧🇪 flag: Belgium +🇧🇫 flag: Burkina Faso +🇧🇬 flag: Bulgaria +🇧🇭 flag: Bahrain +🇧🇮 flag: Burundi +🇧🇯 flag: Benin +🇧🇱 flag: St. Barthélemy +🇧🇲 flag: Bermuda +🇧🇳 flag: Brunei +🇧🇴 flag: Bolivia +🇧🇶 flag: Caribbean Netherlands +🇧🇷 flag: Brazil +🇧🇸 flag: Bahamas +🇧🇹 flag: Bhutan +🇧🇻 flag: Bouvet Island +🇧🇼 flag: Botswana +🇧🇾 flag: Belarus +🇧🇿 flag: Belize +🇨🇦 flag: Canada +🇨🇨 flag: Cocos (Keeling) Islands +🇨🇩 flag: Congo - Kinshasa +🇨🇫 flag: Central African Republic +🇨🇬 flag: Congo - Brazzaville +🇨🇭 flag: Switzerland +🇨🇮 flag: Côte d’Ivoire +🇨🇰 flag: Cook Islands +🇨🇱 flag: Chile +🇨🇲 flag: Cameroon +🇨🇳 flag: China +🇨🇴 flag: Colombia +🇨🇵 flag: Clipperton Island +🇨🇷 flag: Costa Rica +🇨🇺 flag: Cuba +🇨🇻 flag: Cape Verde +🇨🇼 flag: Curaçao +🇨🇽 flag: Christmas Island +🇨🇾 flag: Cyprus +🇨🇿 flag: Czechia +🇩🇪 flag: Germany +🇩🇬 flag: Diego Garcia +🇩🇯 flag: Djibouti +🇩🇰 flag: Denmark +🇩🇲 flag: Dominica +🇩🇴 flag: Dominican Republic +🇩🇿 flag: Algeria +🇪🇦 flag: Ceuta & Melilla +🇪🇨 flag: Ecuador +🇪🇪 flag: Estonia +🇪🇬 flag: Egypt +🇪🇭 flag: Western Sahara +🇪🇷 flag: Eritrea +🇪🇸 flag: Spain +🇪🇹 flag: Ethiopia +🇪🇺 flag: European Union +🇫🇮 flag: Finland +🇫🇯 flag: Fiji +🇫🇰 flag: Falkland Islands +🇫🇲 flag: Micronesia +🇫🇴 flag: Faroe Islands +🇫🇷 flag: France +🇬🇦 flag: Gabon +🇬🇧 flag: United Kingdom +🇬🇩 flag: Grenada +🇬🇪 flag: Georgia +🇬🇫 flag: French Guiana +🇬🇬 flag: Guernsey +🇬🇭 flag: Ghana +🇬🇮 flag: Gibraltar +🇬🇱 flag: Greenland +🇬🇲 flag: Gambia +🇬🇳 flag: Guinea +🇬🇵 flag: Guadeloupe +🇬🇶 flag: Equatorial Guinea +🇬🇷 flag: Greece +🇬🇸 flag: South Georgia & South Sandwich Islands +🇬🇹 flag: Guatemala +🇬🇺 flag: Guam +🇬🇼 flag: Guinea-Bissau +🇬🇾 flag: Guyana +🇭🇰 flag: Hong Kong SAR China +🇭🇲 flag: Heard & McDonald Islands +🇭🇳 flag: Honduras +🇭🇷 flag: Croatia +🇭🇹 flag: Haiti +🇭🇺 flag: Hungary +🇮🇨 flag: Canary Islands +🇮🇩 flag: Indonesia +🇮🇪 flag: Ireland +🇮🇱 flag: Israel +🇮🇲 flag: Isle of Man +🇮🇳 flag: India +🇮🇴 flag: British Indian Ocean Territory +🇮🇶 flag: Iraq +🇮🇷 flag: Iran +🇮🇸 flag: Iceland +🇮🇹 flag: Italy +🇯🇪 flag: Jersey +🇯🇲 flag: Jamaica +🇯🇴 flag: Jordan +🇯🇵 flag: Japan +🇰🇪 flag: Kenya +🇰🇬 flag: Kyrgyzstan +🇰🇭 flag: Cambodia +🇰🇮 flag: Kiribati +🇰🇲 flag: Comoros +🇰🇳 flag: St. Kitts & Nevis +🇰🇵 flag: North Korea +🇰🇷 flag: South Korea +🇰🇼 flag: Kuwait +🇰🇾 flag: Cayman Islands +🇰🇿 flag: Kazakhstan +🇱🇦 flag: Laos +🇱🇧 flag: Lebanon +🇱🇨 flag: St. Lucia +🇱🇮 flag: Liechtenstein +🇱🇰 flag: Sri Lanka +🇱🇷 flag: Liberia +🇱🇸 flag: Lesotho +🇱🇹 flag: Lithuania +🇱🇺 flag: Luxembourg +🇱🇻 flag: Latvia +🇱🇾 flag: Libya +🇲🇦 flag: Morocco +🇲🇨 flag: Monaco +🇲🇩 flag: Moldova +🇲🇪 flag: Montenegro +🇲🇫 flag: St. Martin +🇲🇬 flag: Madagascar +🇲🇭 flag: Marshall Islands +🇲🇰 flag: North Macedonia +🇲🇱 flag: Mali +🇲🇲 flag: Myanmar (Burma) +🇲🇳 flag: Mongolia +🇲🇴 flag: Macao SAR China +🇲🇵 flag: Northern Mariana Islands +🇲🇶 flag: Martinique +🇲🇷 flag: Mauritania +🇲🇸 flag: Montserrat +🇲🇹 flag: Malta +🇲🇺 flag: Mauritius +🇲🇻 flag: Maldives +🇲🇼 flag: Malawi +🇲🇽 flag: Mexico +🇲🇾 flag: Malaysia +🇲🇿 flag: Mozambique +🇳🇦 flag: Namibia +🇳🇨 flag: New Caledonia +🇳🇪 flag: Niger +🇳🇫 flag: Norfolk Island +🇳🇬 flag: Nigeria +🇳🇮 flag: Nicaragua +🇳🇱 flag: Netherlands +🇳🇴 flag: Norway +🇳🇵 flag: Nepal +🇳🇷 flag: Nauru +🇳🇺 flag: Niue +🇳🇿 flag: New Zealand +🇴🇲 flag: Oman +🇵🇦 flag: Panama +🇵🇪 flag: Peru +🇵🇫 flag: French Polynesia +🇵🇬 flag: Papua New Guinea +🇵🇭 flag: Philippines +🇵🇰 flag: Pakistan +🇵🇱 flag: Poland +🇵🇲 flag: St. Pierre & Miquelon +🇵🇳 flag: Pitcairn Islands +🇵🇷 flag: Puerto Rico +🇵🇸 flag: Palestinian Territories +🇵🇹 flag: Portugal +🇵🇼 flag: Palau +🇵🇾 flag: Paraguay +🇶🇦 flag: Qatar +🇷🇪 flag: Réunion +🇷🇴 flag: Romania +🇷🇸 flag: Serbia +🇷🇺 flag: Russia +🇷🇼 flag: Rwanda +🇸🇦 flag: Saudi Arabia +🇸🇧 flag: Solomon Islands +🇸🇨 flag: Seychelles +🇸🇩 flag: Sudan +🇸🇪 flag: Sweden +🇸🇬 flag: Singapore +🇸🇭 flag: St. Helena +🇸🇮 flag: Slovenia +🇸🇯 flag: Svalbard & Jan Mayen +🇸🇰 flag: Slovakia +🇸🇱 flag: Sierra Leone +🇸🇲 flag: San Marino +🇸🇳 flag: Senegal +🇸🇴 flag: Somalia +🇸🇷 flag: Suriname +🇸🇸 flag: South Sudan +🇸🇹 flag: São Tomé & Príncipe +🇸🇻 flag: El Salvador +🇸🇽 flag: Sint Maarten +🇸🇾 flag: Syria +🇸🇿 flag: Eswatini +🇹🇦 flag: Tristan da Cunha +🇹🇨 flag: Turks & Caicos Islands +🇹🇩 flag: Chad +🇹🇫 flag: French Southern Territories +🇹🇬 flag: Togo +🇹🇭 flag: Thailand +🇹🇯 flag: Tajikistan +🇹🇰 flag: Tokelau +🇹🇱 flag: Timor-Leste +🇹🇲 flag: Turkmenistan +🇹🇳 flag: Tunisia +🇹🇴 flag: Tonga +🇹🇷 flag: Turkey +🇹🇹 flag: Trinidad & Tobago +🇹🇻 flag: Tuvalu +🇹🇼 flag: Taiwan +🇹🇿 flag: Tanzania +🇺🇦 flag: Ukraine +🇺🇬 flag: Uganda +🇺🇲 flag: U.S. Outlying Islands +🇺🇳 flag: United Nations +🇺🇸 flag: United States +🇺🇾 flag: Uruguay +🇺🇿 flag: Uzbekistan +🇻🇦 flag: Vatican City +🇻🇨 flag: St. Vincent & Grenadines +🇻🇪 flag: Venezuela +🇻🇬 flag: British Virgin Islands +🇻🇮 flag: U.S. Virgin Islands +🇻🇳 flag: Vietnam +🇻🇺 flag: Vanuatu +🇼🇫 flag: Wallis & Futuna +🇼🇸 flag: Samoa +🇽🇰 flag: Kosovo +🇾🇪 flag: Yemen +🇾🇹 flag: Mayotte +🇿🇦 flag: South Africa +🇿🇲 flag: Zambia +🇿🇼 flag: Zimbabwe +🏴󠁧󠁢󠁥󠁮󠁧󠁿 flag: England +🏴󠁧󠁢󠁳󠁣󠁴󠁿 flag: Scotland +🏴󠁧󠁢󠁷󠁬󠁳󠁿 flag: Wales + diff --git a/nyx/homes/notashelf/programs/graphical/misc/default.nix b/nyx/homes/notashelf/programs/graphical/misc/default.nix new file mode 100644 index 0000000..91d0a5c --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/misc/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./wlogout # wlogout configuration + ]; +} diff --git a/nyx/homes/notashelf/programs/graphical/misc/wlogout/default.nix b/nyx/homes/notashelf/programs/graphical/misc/wlogout/default.nix new file mode 100644 index 0000000..b38d78d --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/misc/wlogout/default.nix @@ -0,0 +1,86 @@ +{pkgs, ...}: { + xdg.configFile = { + "wlogout/layout".text = '' + { + "label" : "lock", + "action" : "loginctl lock-session", + "text" : "Lock", + "keybind" : "l" + } + { + "label" : "hibernate", + "action" : "systemctl hibernate", + "text" : "Hibernate", + "keybind" : "h" + } + { + "label" : "logout", + "action" : "loginctl terminate-user $USER", + "text" : "Logout", + "keybind" : "e" + } + { + "label" : "shutdown", + "action" : "systemctl poweroff", + "text" : "Shutdown", + "keybind" : "s" + } + { + "label" : "suspend", + "action" : "systemctl suspend", + "text" : "Suspend", + "keybind" : "u" + } + { + "label" : "reboot", + "action" : "systemctl reboot", + "text" : "Reboot", + "keybind" : "r" + } + ''; + "wlogout/style.css".text = let + iconPath = "${pkgs.wlogout}/share/wlogout/icons"; + in '' + button { + color: @theme_text_color; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.25); + background-repeat: no-repeat; + background-position: center; + background-size: 24px; + margin: 5px; + } + + button:focus, button:active, button:hover { + box-shadow: 0 0 0 1px @theme_selected_bg_color; + } + + #lock { + background-image: image(url("${iconPath}/lock.png")); + } + + #logout { + background-image: image(url("${iconPath}/logout.png")); + } + + #suspend { + background-image: image(url("${iconPath}/suspend.png")); + } + + #hibernate { + background-image: image(url("${iconPath}/hibernate.png")); + } + + #shutdown { + background-image: image(url("${iconPath}/shutdown.png")); + } + + #reboot { + background-image: image(url("${iconPath}/reboot.png")); + } + + #firmware { + background-image: image(url("${iconPath}/reboot.png")); + } + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/screenlock/default.nix b/nyx/homes/notashelf/programs/graphical/screenlock/default.nix new file mode 100644 index 0000000..d3eea29 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/screenlock/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./gtklock + ./swaylock + ]; +} diff --git a/nyx/homes/notashelf/programs/graphical/screenlock/gtklock/default.nix b/nyx/homes/notashelf/programs/graphical/screenlock/gtklock/default.nix new file mode 100644 index 0000000..f2b0c3b --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/screenlock/gtklock/default.nix @@ -0,0 +1,31 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; +in { + config = mkIf env.programs.screenlock.gtklock.enable { + programs.gtklock = { + enable = true; + package = pkgs.gtklock; + + config = { + modules = [ + "${pkgs.gtklock-powerbar-module.outPath}/lib/gtklock/powerbar-module.so" + ]; + + style = builtins.readFile (lib.compileSCSS pkgs { + name = "gtklock-dark"; + path = ./styles/dark.scss; + }); + }; + + extraConfig = {}; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/screenlock/gtklock/styles/dark.scss b/nyx/homes/notashelf/programs/graphical/screenlock/gtklock/styles/dark.scss new file mode 100644 index 0000000..029a684 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/screenlock/gtklock/styles/dark.scss @@ -0,0 +1,40 @@ +window { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + + #clock-label { + margin-bottom: 30px; + font-size: 800%; + font-weight: bold; + color: white; + text-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1); + } + + #body { + margin-top: 50px; + } + + #unlock-button { + all: unset; + color: transparent; + } + + entry { + border-radius: 12px; + margin: 1px; + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.1); + } + + #input-label { + color: transparent; + margin: -20rem; + } + + #powerbar-box { + * { + border-radius: 12px; + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.1); + } + } +} diff --git a/nyx/homes/notashelf/programs/graphical/screenlock/swaylock/default.nix b/nyx/homes/notashelf/programs/graphical/screenlock/swaylock/default.nix new file mode 100644 index 0000000..5bcf4dc --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/screenlock/swaylock/default.nix @@ -0,0 +1,55 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + inherit (osConfig.modules.style.colorScheme) colors; + + env = modules.usrEnv; +in { + config = mkIf env.programs.screenlock.swaylock.enable { + programs.swaylock = { + enable = true; + package = with pkgs; swaylock-effects; + settings = { + clock = true; + color = "${colors.base00}"; + font = "Work Sans"; + show-failed-attempts = false; + indicator = true; + indicator-radius = 200; + indicator-thickness = 20; + line-color = "${colors.base00}"; + ring-color = "${colors.base04}"; + inside-color = "${colors.base00}"; + key-hl-color = "${colors.base0F}"; + separator-color = "00000000"; + text-color = "${colors.base05}"; + text-caps-lock-color = ""; + line-ver-color = "${colors.base0F}"; + ring-ver-color = "${colors.base0F}"; + inside-ver-color = "${colors.base00}"; + text-ver-color = "${colors.base05}"; + ring-wrong-color = "${colors.base08}"; + text-wrong-color = "${colors.base08}"; + inside-wrong-color = "${colors.base00}"; + inside-clear-color = "${colors.base00}"; + text-clear-color = "${colors.base05}"; + ring-clear-color = "${colors.base0B}"; + line-clear-color = "${colors.base00}"; + line-wrong-color = "${colors.base00}"; + bs-hl-color = "${colors.base08}"; + line-uses-ring = false; + grace = 3; + grace-no-mouse = true; + grace-no-touch = true; + datestr = "%d/%m/%Y"; + fade-in = "0.1"; + ignore-empty-password = true; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/default.nix b/nyx/homes/notashelf/programs/graphical/wms/default.nix new file mode 100644 index 0000000..5f1f03e --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./i3 + ./hyprland + ./sway + ]; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/binds.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/binds.nix new file mode 100644 index 0000000..9b2a4a4 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/binds.nix @@ -0,0 +1,117 @@ +{ + inputs', + osConfig, + defaults, + pkgs, + lib, + ... +}: let + inherit (lib.meta) getExe; + inherit (osConfig) modules; + env = modules.usrEnv; + + # nix advantages + inherit (import ../packages {inherit inputs' pkgs;}) propaganda; + + terminal = + if (defaults.terminal == "foot") + then "footclient" + else "${defaults.terminal}"; + + locker = getExe env.programs.screenlock.package; +in { + wayland.windowManager.hyprland.settings = { + # define the mod key + "$MOD" = "SUPER"; + + # keyword to toggle "monocle" - a.k.a no_gaps_when_only + "$kw" = "dwindle:no_gaps_when_only"; + "$disable" = ''act_opa=$(hyprctl getoption "decoration:active_opacity" -j | jq -r ".float");inact_opa=$(hyprctl getoption "decoration:inactive_opacity" -j | jq -r ".float");hyprctl --batch "keyword decoration:active_opacity 1;keyword decoration:inactive_opacity 1"''; + "$enable" = ''hyprctl --batch "keyword decoration:active_opacity $act_opa;keyword decoration:inactive_opacity $inact_opa"''; + #"$screenshotarea" = ''hyprctl keyword animation "fadeOut,0,0,default"; grimblast --notify copysave area; hyprctl keyword animation "fadeOut,1,4,default"'' + + bind = [ + # Misc + "$MODSHIFT, Escape, exec, wlogout -p layer-shell" # logout menu + "$MODSHIFT, L, exec, ${locker}" # lock the screen with swaylock + "$MODSHIFT,E,exit," # exit Hyprland session + ''$MODSHIFT,H,exec,cat ${propaganda} | ${pkgs.wl-clipboard}/bin/wl-copy && ${pkgs.libnotify}/bin/notify-send "Propaganda" "ready to spread!" && sleep 0.3 && ${lib.getExe pkgs.wtype} -M ctrl -M shift -k v -m shift -m ctrl -s 300 -k Return'' # spread hyprland propaganda + + # Daily Applications + "$MOD,F1,exec,firefox" # browser + ''$MOD,F2,exec,run-as-service "${defaults.fileManager}"'' # file manager + ''$MOD,RETURN,exec,run-as-service "${terminal}"'' # terminal + ''$MODSHIFT,RETURN,exec,run-as-service "${terminal}"'' # floating terminal (TODO) + ''$MOD,D,exec, killall rofi || run-as-service $(rofi -show drun)'' # application launcher + "$MOD,equal,exec, killall rofi || rofi -show calc" # calc plugin for rofi + "$MOD,period,exec, killall rofi || rofi -show emoji" # emoji plugin for rofi + ''$MOD,R,exec, killall tofi || run-as-service $(tofi-drun --prompt-text " Run")'' # alternative app launcher + ''$MODSHIFT,R,exec, killall anyrun || run-as-service $(anyrun)'' # alternative application launcher with more features + + # window operators + "$MODSHIFT,Q,killactive," # kill focused window + "$MOD,T,togglegroup," # group focused window + "$MODSHIFT,G,changegroupactive," # switch within the active group + "$MOD,V,togglefloating," # toggle floating for the focused window + "$MOD,P,pseudo," # pseudotile focused window + "$MOD,F,fullscreen," # fullscreen focused window + "$MOD,M,exec,hyprctl keyword $kw $(($(hyprctl getoption $kw -j | jaq -r '.int') ^ 1))" # toggle no_gaps_when_only + + # workspace controls + "$MODSHIFT,right,movetoworkspace,+1" # move focused window to the next ws + "$MODSHIFT,left,movetoworkspace,-1" # move focused window to the previous ws + "$MOD,mouse_down,workspace,e+1" # move to the next ws + "$MOD,mouse_up,workspace,e-1" # move to the previous ws + + # focus controls + "$MOD, left, movefocus, l" # move focus to the window on the left + "$MOD, right, movefocus, r" # move focus to the window on the right + "$MOD, up, movefocus, u" # move focus to the window above + "$MOD, down, movefocus, d" # move focus to the window below + + # screenshot and receording binds + ''$MODSHIFT,P,exec,$disable; grim - | wl-copy --type image/png && notify-send "Screenshot" "Screenshot copied to clipboard"; $enable'' + "$MODSHIFT,S,exec,$disable; hyprshot; $enable" # screenshot and then pipe it to swappy + "$MOD, Print, exec, grimblast --notify --cursor copysave output" # copy all active outputs + "$ALTSHIFT, S, exec, grimblast --notify --cursor copysave screen" # copy active screen + "$ALTSHIFT, R, exec, grimblast --notify --cursor copysave area" # copy selection area + + # OCR + "$MODSHIFT,O,exec,ocr" + + # Toggle Statusbar + "$MODSHIFT,B,exec, ags -t bar" + + /* + , Print, exec, $screenshotarea + $ALTSHIFT, S, exec, $screenshotarea + */ + ]; + + bindm = [ + "$MOD,mouse:272,movewindow" + "$MOD,mouse:273,resizewindow" + ]; + # binds that will be repeated, a.k.a can be held to toggle multiple times + binde = [ + # volume controls + ",XF86AudioRaiseVolume, exec, wpctl set-volume -l '1.0' @DEFAULT_AUDIO_SINK@ 6%+" + ",XF86AudioLowerVolume, exec, wpctl set-volume -l '1.0' @DEFAULT_AUDIO_SINK@ 6%-" + + # brightness controls + '',XF86MonBrightnessUp,exec,ags --run-js "brightness.screen += 0.05"'' + '',XF86MonBrightnessDown,exec, ags --run-js "brightness.screen -= 0.05"'' + ]; + + # binds that are locked, a.k.a will activate even while an input inhibitor is active + bindl = [ + # media controls + ",XF86AudioPlay,exec,playerctl play-pause" + ",XF86AudioPrev,exec,playerctl previous" + ",XF86AudioNext,exec,playerctl next" + + ", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" + ", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle" + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/decorations.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/decorations.nix new file mode 100644 index 0000000..f69a0fa --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/decorations.nix @@ -0,0 +1,72 @@ +{ + wayland.windowManager.hyprland.settings = { + decoration = { + # fancy corners + rounding = 7; + + # blur + blur = { + enabled = true; + size = 5; + passes = 3; + ignore_opacity = true; + new_optimizations = 1; + xray = true; + contrast = 0.7; + brightness = 0.8; + vibrancy = 0.2; + special = true; # expensive, but helps distinguish special workspaces + }; + + # shadow config + drop_shadow = "yes"; + shadow_range = 10; + shadow_render_power = 3; + "col.shadow" = "rgba(292c3cee)"; + }; + + group = { + # new windows in a group spawn after current or at group tail + insert_after_current = true; + # focus on the window that has just been moved out of the group + focus_removed_window = true; + + "col.border_active" = "rgba(88888888)"; + "col.border_inactive" = "rgba(00000088)"; + + groupbar = { + # groupbar stuff + # this removes the ugly gradient around grouped windows - which sucks + gradients = false; + font_size = 14; + + # titles look ugly, and I usually know what I'm looking at + render_titles = false; + + # scrolling in the groupbar changes group active window + scrolling = true; + }; + }; + + animations = { + enabled = true; # we want animations, half the reason why we're on Hyprland innit + first_launch_animation = true; # fade in on first launch + + bezier = [ + "smoothOut, 0.36, 0, 0.66, -0.56" + "smoothIn, 0.25, 1, 0.5, 1" + "overshot, 0.4,0.8,0.2,1.2" + ]; + + animation = [ + "windows, 1, 4, overshot, slide" + "windowsOut, 1, 4, smoothOut, slide" + "border,1,10,default" + + "fade, 1, 10, smoothIn" + "fadeDim, 1, 10, smoothIn" + "workspaces,1,4,overshot,slidevert" + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/exec.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/exec.nix new file mode 100644 index 0000000..317f263 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/exec.nix @@ -0,0 +1,13 @@ +{osConfig, ...}: let + inherit (osConfig) modules; + + # theming + inherit (modules.style) pointerCursor; +in { + wayland.windowManager.hyprland.settings = { + exec-once = [ + # set cursor for HL itself + "hyprctl setcursor ${pointerCursor.name} ${toString pointerCursor.size}" + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/extraConfig.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/extraConfig.nix new file mode 100644 index 0000000..b421c9d --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/extraConfig.nix @@ -0,0 +1,81 @@ +{ + osConfig, + lib, + ... +}: let + inherit (lib) imap0; + inherit (osConfig) modules; + inherit (modules.device) monitors; +in { + wayland.windowManager.hyprland.extraConfig = let + # divide workspaces between monitors + mapMonitorsToWs = builtins.concatStringsSep "\n" ( + builtins.genList ( + x: '' + workspace = ${toString (x + 1)}, monitor:${ + if (x + 1) <= 5 + then "${builtins.elemAt monitors 0} ${ + if (x + 1) == 1 + then ", default:true" + else "" + }" + else "${builtins.elemAt monitors 1}" + } + + '' + ) + 10 + ); + + # generate monitor config strings + mapMonitors = builtins.concatStringsSep "\n" (imap0 (i: monitor: ''monitor=${monitor},${ + if monitor == "DP-1" + then "1920x1080@144" + else "preferred" + }, ${toString (i * 1920)}x0,1'') + monitors); + in '' + # generate a list of monitors automatically, like so + #monitor=HDMI-A-1,preferred,0x0,1 + # monitor=DP-1,preferred,1920x0,1 + ${mapMonitors} + + # if I have a second monitor, indicated by the element count of the monitors list, divide the workspaces + # inbetween two workspaces -> 1-5 on mon1 and 6-10 on mon2 + # if not, then don't divide workspaces + # P.S. I really don't know what I will do if I get a third monitor + ${lib.optionalString (builtins.length monitors != 1) "${mapMonitorsToWs}"} + + # a submap for resizing windows + bind = $MOD, S, submap, resize # enter resize window to resize the active window + submap=resize + binde=,right,resizeactive,10 0 + binde=,left,resizeactive,-10 0 + binde=,up,resizeactive,0 -10 + binde=,down,resizeactive,0 10 + bind=,escape,submap,reset + submap=reset + + # workspace binds + # binds * (asterisk) to special workspace + bind = $MOD, KP_Multiply, togglespecialworkspace + bind = $MODSHIFT, KP_Multiply, movetoworkspace, special + + # and mod + [shift +] {1..10} to [move to] ws {1..10} + ${ + builtins.concatStringsSep "\n" + (builtins.genList ( + x: let + ws = let + c = (x + 1) / 10; + in + builtins.toString (x + 1 - (c * 10)); + in '' + bind = $MOD, ${ws}, workspace, ${toString (x + 1)} + bind = $MOD SHIFT, ${ws}, movetoworkspace, ${toString (x + 1)} + '' + ) + 10) + } + ''; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/general.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/general.nix new file mode 100644 index 0000000..3d5611d --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/general.nix @@ -0,0 +1,27 @@ +{osConfig, ...}: let + inherit (osConfig) modules; + + # theming + inherit (modules.style) colorScheme; + inherit (colorScheme) colors; +in { + wayland.windowManager.hyprland.settings = { + general = { + # sensitivity of the mouse cursor + sensitivity = 0.8; + + # gaps + gaps_in = 4; + gaps_out = 8; + + # border thiccness + border_size = 2; + + # active border color + "col.active_border" = "0xff${colors.base07}"; + + # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse) + apply_sens_to_raw = 0; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/gestures.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/gestures.nix new file mode 100644 index 0000000..84b6686 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/gestures.nix @@ -0,0 +1,8 @@ +{ + wayland.windowManager.hyprland.settings = { + gestures = { + workspace_swipe = true; + workspace_swipe_forever = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/input.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/input.nix new file mode 100644 index 0000000..72e0536 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/input.nix @@ -0,0 +1,14 @@ +{ + wayland.windowManager.hyprland.settings = { + input = { + # keyboard layout + kb_layout = "tr"; + # self explanatory, I hope? + follow_mouse = 1; + # do not imitate natural scroll + touchpad.natural_scroll = "no"; + # ez numlock enable + numlock_by_default = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/layout.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/layout.nix new file mode 100644 index 0000000..c48b03f --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/layout.nix @@ -0,0 +1,10 @@ +{ + wayland.windowManager.hyprland.settings = { + dwindle = { + pseudotile = false; + preserve_split = "yes"; + no_gaps_when_only = false; + special_scale_factor = 0.9; # restore old special workspace behaviour + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/misc.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/misc.nix new file mode 100644 index 0000000..173a35b --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/misc.nix @@ -0,0 +1,18 @@ +{ + wayland.windowManager.hyprland.settings = { + misc = { + # disable redundant renders + disable_hyprland_logo = true; # wallpaper covers it anyway + disable_splash_rendering = true; # " + + # window swallowing + enable_swallow = true; # hide windows that spawn other windows + swallow_regex = "foot|thunar|nemo|wezterm"; # windows for which swallow is applied + + # dpms + mouse_move_enables_dpms = true; # enable dpms on mouse/touchpad action + key_press_enables_dpms = true; # enable dpms on keyboard action + disable_autoreload = true; # autoreload is unnecessary on nixos, because the config is readonly anyway + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/windowrules.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/windowrules.nix new file mode 100644 index 0000000..cd23fd1 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/config/windowrules.nix @@ -0,0 +1,64 @@ +{ + wayland.windowManager.hyprland.settings = { + windowrulev2 = [ + # only allow shadows for floating windows + "noshadow, floating:0" + + "float,class:udiskie" + + # wlogout + "fullscreen,class:wlogout" + "fullscreen,title:wlogout" + "noanim, title:wlogout" + + # spotify + "tile, title:Spotify" + "tile, class:^(Spotify)$" + + # steam settings window + "float, title:^(Steam Settings)$" + + # telegram media viewer + "float, title:^(Media viewer)$" + + # bitwarden + "float,class:Bitwarden" + "size 800 600,class:Bitwarden" + + "idleinhibit focus, class:^(mpv)$" + "idleinhibit focus,class:foot" + + # firefox + "idleinhibit fullscreen, class:^(firefox)$" + "float,title:^(Firefox — Sharing Indicator)$" + "move 0 0,title:^(Firefox — Sharing Indicator)$" + "float, title:^(Picture-in-Picture)$" + "pin, title:^(Picture-in-Picture)$" + + # thunderbird + "workspace special silent, title:^(Write.*- Thunderbird)$" + + # pavucontrol + "float,class:pavucontrol" + "float,title:^(Volume Control)$" + "size 800 600,title:^(Volume Control)$" + "move 75 44%,title:^(Volume Control)$" + "float, class:^(imv)$" + + # Helldivers 2 + "forceinput,class:^(steam_app_553850)$" + + # throw sharing indicators away + "workspace special silent, title:^(Firefox — Sharing Indicator)$" + "workspace special silent, title:^(.*is sharing (your screen|a window)\.)$" + + # EA launcher puts a tiny window in the current workspae + # throw it away + "workspace special silent, title:^(title:Wine System Tray)$" + + "workspace 3 silent, class:^(Spotify)$" + "workspace 4, title:^(.*(Disc|WebC)ord.*)$" + "workspace 10 silent, class:^(Nextcloud)$" + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/default.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/default.nix new file mode 100644 index 0000000..fb037e0 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/default.nix @@ -0,0 +1,40 @@ +{ + inputs', + osConfig, + pkgs, + lib, + ... +}: let + inherit (builtins) filter map toString; + inherit (lib.filesystem) listFilesRecursive; + inherit (lib.modules) mkIf; + inherit (lib.strings) hasSuffix; + inherit (osConfig) modules; + + inherit (import ./packages {inherit inputs' pkgs;}) grimblast hyprshot dbus-hyprland-env hyprpicker wrapper; + + env = modules.usrEnv; +in { + imports = filter (hasSuffix ".nix") ( + map toString (filter (p: p != ./default.nix) (listFilesRecursive ./config)) + ); + config = mkIf env.desktops.hyprland.enable { + home.packages = [ + inputs'.hyprland.packages.hyprland + hyprshot + grimblast + hyprpicker + dbus-hyprland-env + ]; + + wayland.windowManager.hyprland = { + enable = true; + package = wrapper; + xwayland.enable = true; + systemd = { + enable = true; + variables = ["--all"]; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/dbus-hyprland-env.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/dbus-hyprland-env.nix new file mode 100644 index 0000000..8fef3e5 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/dbus-hyprland-env.nix @@ -0,0 +1,11 @@ +{pkgs, ...}: +pkgs.writeTextFile { + name = "dbus-hyprland-env"; + destination = "/bin/dbus-hyprland-environment"; + executable = true; + text = '' + dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=hyprland + systemctl --user stop pipewire pipewire-media-session xdg-desktop-portal xdg-desktop-portal-wlr + systemctl --user start pipewire wireplumber pipewire-media-session xdg-desktop-portal xdg-desktop-portal-hyprland + ''; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/default.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/default.nix new file mode 100644 index 0000000..9e6adc0 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/default.nix @@ -0,0 +1,16 @@ +{ + inputs', + pkgs, + ... +}: let + packages = { + inherit (inputs'.hyprland-contrib.packages) grimblast; + inherit (inputs'.hyprpicker.packages) hyprpicker; + + wrapper = pkgs.callPackage ./wrapper {inherit (inputs') hyprland;}; + hyprshot = pkgs.callPackage ./hyprshot.nix {}; + dbus-hyprland-env = pkgs.callPackage ./dbus-hyprland-env.nix {}; + propaganda = pkgs.callPackage ./propaganda.nix {}; + }; +in + packages diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/hyprshot.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/hyprshot.nix new file mode 100644 index 0000000..7a30aee --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/hyprshot.nix @@ -0,0 +1,10 @@ +{pkgs, ...}: +pkgs.writeShellApplication { + name = "hyprshot"; + runtimeInputs = with pkgs; [grim slurp swappy]; + text = '' + hyprctl keyword animation "fadeOut,0,8,slow" && \ + grim -g "$(slurp -w 0 -b 5e81acd2)" - | swappy -f -; \ + hyprctl keyword animation "fadeOut,1,8,slow" + ''; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/propaganda.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/propaganda.nix new file mode 100644 index 0000000..feb1198 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/propaganda.nix @@ -0,0 +1,38 @@ +{pkgs, ...}: +pkgs.writeTextFile { + name = "propaganda"; + text = '' + ## Nix advantages: + - Correct and complete packaging + - Immutable & reproducible results + - Easy to cross and static compile + - Source-based (you can alter packages without forking anything) + - Single package manager to rule them all! (C, Python, Docker, NodeJS, etc) + - Great for development, easily switches between dev envs with direnv + - Easy to try out packages without installing using `nix shell` or `nix run` + - allows to create scripts that can do and depend on anything, so long as the host has nix, it'll download things automatically for them + - Uses binary caches so you almost never need to compile anything + - Easy to set up a binary cache + - Easy to set up remote building + - Distribute your builds accross an unlimited number of machines, without any hassle + - Excellent testing infrastructure + - Portable - runs on Linux and macOS + - Can be built statically and run anywhere without root permissions + - Mix and match different package versions without conflicts + - Want to have a package with openssl1.1 and another with openssl 3.0? No problem! + - Flakes let you pin versions to specific revisions + - Various alternatives for Flakes for version pinning, such as npins and niv + + ## NixOS advantages: + - Declarative configuration + - Meaning easier to configure your system(s) + - Easier to change, manage and maintain the configuration + - Easier to back up and share with people + - Easy to deploy machines and their configuration + - Out of the box Rollbacks. + - Configuration options for many programs & services + - Free of side effects - Actually uninstalls packages and their dependencies + - Easy to set up VMs + - People can test each other's configurations using `nix run` and `nix shell` by just having access to the source + ''; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/wrapper/default.nix b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/wrapper/default.nix new file mode 100644 index 0000000..e5478be --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/wrapper/default.nix @@ -0,0 +1,12 @@ +{ + hyprland, + pkgs, + lib, + ... +}: let + inherit (lib.meta) getExe'; +in + pkgs.writeShellScriptBin "hyprland" '' + ${builtins.readFile ./session.sh} + ${getExe' hyprland.packages.default "Hyprland"} $@ + '' diff --git a/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/wrapper/session.sh b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/wrapper/session.sh new file mode 100644 index 0000000..dd3b33e --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/hyprland/packages/wrapper/session.sh @@ -0,0 +1,41 @@ +# disable shellcheck's shell check +# it'll be provided by writeShellScript +# shellcheck disable=2148 + +# session +export XDG_SESSION_TYPE=wayland +export XDG_SESSION_DESKTOP=hyprland +export XDG_CURRENT_DESKTOP=hyprland + +# firefox +export MOZ_ENABLE_WAYLAND=1 +export MOZ_DBUS_REMOTE=1 + +# qt +export QT_QPA_PLATFORM=wayland +export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 + +# gtk +export GDK_BACKEND=wayland + +# sdl +export SDL_VIDEODRIVER=wayland + +# java +export _JAVA_AWT_WM_NONREPARENTING=1 +export JDK_JAVA_OPTIONS="-Dawt.useSystemAAFontSettings=on -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Dswing.crossplatformlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel" + +# other +export CLUTTER_BACKEND=wayland +export XCURSOR_SIZE=24 +export NIXOS_OZONE_WL=1 + +# cursed dbus + +dbus-update-activation-environment --systemd MOZ_ENABLE_WAYLAND MOZ_DBUS_REMOTE QT_QPA_PLATFORM QT_QPA_PLATFORMTHEME QT_WAYLAND_DISABLE_WINDOWDECORATION SDL_VIDEODRIVER _JAVA_AWT_WM_NONREPARENTING JDK_JAVA_OPTIONS XCURSOR_SIZE XCURSOR_THEME + +# theme in dbus: +# QT_PLUGIN_PATH=/lib/qt-ver/plugins + breeze will correctly set the theme. +# HOWEVER it won't find thumbnailers. For now the easiest way to deal with this, though definitely not +# the right one, is to just throw $PATH into dbus. +dbus-update-activation-environment --systemd PATH diff --git a/nyx/homes/notashelf/programs/graphical/wms/i3/default.nix b/nyx/homes/notashelf/programs/graphical/wms/i3/default.nix new file mode 100644 index 0000000..7535d82 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/i3/default.nix @@ -0,0 +1,195 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; +in { + config = mkIf env.desktops.i3.enable { + home.packages = [pkgs.maim]; + + # enable i3status for the bar + programs.i3status-rust = { + enable = true; + bars = { + bottom = { + theme = "modern"; + icons = "awesome6"; + + blocks = [ + { + block = "custom"; + command = "${pkgs.rsstail}/bin/rsstail rsstail -n 1 -1 -N -u https://github.com/nixos/nixpkgs/commits/master.atom"; + interval = 60; + } + { + block = "memory"; + format = " $icon $mem_used_percents "; + format_alt = " $icon $swap_used_percents "; + } + { + block = "cpu"; + interval = 1; + format = " CPU $barchart $utilization "; + format_alt = " CPU $frequency{ $boost|} "; + merge_with_next = true; + } + { + block = "load"; + format = " Avg $5m "; + interval = 10; + merge_with_next = true; + } + { + block = "memory"; + format = " MEM $mem_used_percents "; + format_alt = " MEM $swap_used_percents "; + } + { + block = "battery"; + device = "BAT1"; + format = " $icon $percentage $time $power "; + } + { + block = "net"; + format = " $icon $ssid $signal_strength $ip ↓$speed_down ↑$speed_up "; + interval = 2; + } + { + block = "time"; + interval = 1; + format = " $timestamp.datetime(f:'%F %T') "; + } + { + block = "sound"; + } + ]; + }; + }; + }; + + # use i3 as the window manager + xsession.windowManager.i3 = let + mod = "Mod4"; + in { + enable = true; + config = { + # status bar configuration + bars = [ + { + position = "bottom"; + statusCommand = "${pkgs.i3status-rust}/bin/i3status-rs ~/.config/i3status-rust/config-bottom.toml"; + } + ]; + + workspaceLayout = "tabbed"; + + gaps = let + gaps_inner = 5; + gaps_outer = 5; + gaps_top = 5; + gaps_bottom = 5; + in { + # Set inner/outer gaps + outer = gaps_outer; + inner = gaps_inner; + top = gaps_top; + bottom = gaps_bottom; + }; + + # keybindings + keybindings = lib.mkOptionDefault { + "${mod}+r" = "exec ${pkgs.dmenu}/bin/dmenu_run"; + "${mod}+Return" = "exec ${pkgs.kitty}/bin/kitty"; + "${mod}+p" = "exec sh -c '${pkgs.maim}/bin/maim -s | xclip -selection clipboard -t image/png'"; + "${mod}+Shift+x" = "exec sh -c '${pkgs.i3lock}/bin/i3lock -c 222222 & sleep 5 && xset dpms force of'"; + + "${mod}+v" = "floating toggle"; + "${mod}+g" = "sticky toggle"; + "${mod}+f" = "fullscreen"; + + # Focus + "${mod}+h" = "focus left"; + "${mod}+j" = "focus down"; + "${mod}+k" = "focus up"; + "${mod}+l" = "focus right"; + + # Move + "${mod}+Shift+h" = "move left"; + "${mod}+Shift+j" = "move down"; + "${mod}+Shift+k" = "move up"; + "${mod}+Shift+l" = "move right"; + + # workspace navigation + "${mod}+Shift+Right" = "workspace next"; + "${mod}+Shift+Left" = "workspace prev"; + + # workspace selection + "${mod}+1" = "workspace number 1"; + "${mod}+2" = "workspace number 2"; + "${mod}+3" = "workspace number 3"; + "${mod}+4" = "workspace number 4"; + "${mod}+5" = "workspace number 5"; + "${mod}+6" = "workspace number 6"; + "${mod}+7" = "workspace number 7"; + "${mod}+8" = "workspace number 8"; + "${mod}+9" = "workspace number 9"; + "${mod}+0" = "workspace number 0"; + + # keybindings for moving windows to different workspaces + "${mod}+Shift+1" = "move container to workspace number 1"; + "${mod}+Shift+2" = "move container to workspace number 2"; + "${mod}+Shift+3" = "move container to workspace number 3"; + "${mod}+Shift+4" = "move container to workspace number 4"; + "${mod}+Shift+5" = "move container to workspace number 5"; + "${mod}+Shift+6" = "move container to workspace number 6"; + "${mod}+Shift+7" = "move container to workspace number 7"; + "${mod}+Shift+8" = "move container to workspace number 8"; + "${mod}+Shift+9" = "move container to workspace number 9"; + + "${mod}+Shift+r" = ''restart; exec notify-send "i3 restarted"''; + "${mod}+Shif+q" = "kill"; + "${mod}+Shift+e" = "exit"; + + # Move the currently focused window to scratchpad + "${mod}+Shift+BackSpace" = "move scratchpad"; + + # Show the first scratchpad window + "${mod}+BackSpace" = "scratchpad show, move position center"; + }; + + startup = [ + /* + { + command = "${pkgs.feh}/bin/feh --bg-scale 'some path'"; + always = false; + notification = false; + } + */ + ]; + + assigns = let + w1 = "1:  TSK"; + w2 = "2:  MUS"; + w3 = "3:  CHAT"; + w4 = "4:  VIRT"; + w5 = "5:  TERM"; + w6 = "6:  GFX"; + w7 = "7:  WWW"; + w8 = "8:  TERM"; + w9 = "9:  DEV"; + w0 = "0:  TERM"; + in { + "${w2}" = [{class = "Spotify";}]; + "${w3}" = [{class = "Discord";}]; + "${w7}" = [{class = "Google-chrome";} {class = "firefox";}]; + "${w9}" = [{class = "VSCodium";}]; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/sway/config.nix b/nyx/homes/notashelf/programs/graphical/wms/sway/config.nix new file mode 100644 index 0000000..6f66953 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/sway/config.nix @@ -0,0 +1,78 @@ +{ + config, + lib, + defaults, + ... +}: let + terminal = + if (defaults.terminal == "foot") + then "footclient" + else "${defaults.terminal}"; +in { + config = { + wayland.windowManager.sway = { + config = { + assigns = { + "1: web" = [{class = "^Firefox$";}]; + "9: steam" = [{class = "^Steam$";}]; + }; + + workspaceAutoBackAndForth = true; + + modifier = "Mod4"; + keybindings = let + m = config.wayland.windowManager.sway.config.modifier; + in + lib.mkOptionDefault { + "${m}+Return" = "exec ${terminal}"; + "${m}+space" = "exec anyrun"; + + # utilities + "${m}+q" = "kill"; + "${m}+t" = "floating toggle"; + + # screenshots + "Print" = "grim -g \"$(slurp)\" - | wl-copy -t image/png"; + "${m}+Shift+r" = "grim -g \"$(slurp)\" - | wl-copy -t image/png"; + "Alt+Print" = "grim - | wl-copy -t image/png"; + "${m}+Alt+Shift+r" = "grim - | wl-copy -t image/png"; + }; + + keycodebindings = { + "--locked --no-repeat 121" = "exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; # mute + "--locked 122" = "exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 6%-"; # vol- + "--locked 123" = "exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 6%+"; # vol+ + "--locked 171" = "exec playerctl next"; # next song + "--locked --no-repeat 172" = "exec playerctl play-pause"; # play/pause + "--locked 173" = "exec playerctl previous"; # prev song + "--locked --no-repeat 198" = "exec wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; # mic mute + "--locked 232" = "exec light -U 5"; # brightness- + "--locked 233" = "exec light -A 5"; # brightness+ + }; + + menu = "anyrun"; + bars = []; + + gaps = { + smartBorders = "on"; + outer = 5; + inner = 5; + }; + + startup = [{command = "dbus-update-activation-environment --systemd WAYLAND_DISPLAY DISPLAY";}]; + + input = { + "type:pointer" = { + accel_profile = "flat"; + pointer_accel = "0"; + }; + "type:touchpad" = { + middle_emulation = "enabled"; + natural_scroll = "enabled"; + tap = "enabled"; + }; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/graphical/wms/sway/default.nix b/nyx/homes/notashelf/programs/graphical/wms/sway/default.nix new file mode 100644 index 0000000..d1f3430 --- /dev/null +++ b/nyx/homes/notashelf/programs/graphical/wms/sway/default.nix @@ -0,0 +1,18 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + env = osConfig.modules.usrEnv; +in { + imports = [./config.nix]; + config = mkIf env.desktops.sway.enable { + wayland.windowManager.sway = { + enable = true; + package = pkgs.swayfx; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/media/beets.nix b/nyx/homes/notashelf/programs/media/beets.nix new file mode 100644 index 0000000..7185394 --- /dev/null +++ b/nyx/homes/notashelf/programs/media/beets.nix @@ -0,0 +1,76 @@ +{ + osConfig, + config, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; +in { + programs.beets = mkIf prg.media.beets.enable { + enable = true; + + settings = { + ui.color = true; + directory = config.services.mpd.musicDirectory; + library = "${config.services.mpd.musicDirectory}/musiclibrary.db"; + + clutter = [ + "Thumbs.DB" + ".DS_Store" + ".directory" + ]; + + plugins = [ + # "acousticbrainz" # DEPRECATED + "mpdupdate" + "lyrics" + "thumbnails" + "fetchart" + "embedart" + "chroma" + "fromfilename" + "lastgenre" + "absubmit" + "duplicates" + "edit" + "mbcollection" + "mbsync" + "replaygain" + "scrub" + ]; + + import = { + move = true; + timid = true; + detail = true; + bell = true; + write = true; + }; + + mpd = { + host = "localhost"; + port = 6600; + }; + + lyrics = { + auto = true; + }; + + thumbnails.auto = true; + fetchart.auto = true; + + embedart = { + auto = true; + remove_art_file = true; + }; + + acousticbrainz.auto = true; + chroma.auto = true; + replaygain.backend = "gstreamer"; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/media/default.nix b/nyx/homes/notashelf/programs/media/default.nix new file mode 100644 index 0000000..c823330 --- /dev/null +++ b/nyx/homes/notashelf/programs/media/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./mpv + ./ncmpcpp + + ./beets.nix + ./packages.nix + ]; +} diff --git a/nyx/homes/notashelf/programs/media/mpv/default.nix b/nyx/homes/notashelf/programs/media/mpv/default.nix new file mode 100644 index 0000000..f5be68b --- /dev/null +++ b/nyx/homes/notashelf/programs/media/mpv/default.nix @@ -0,0 +1,78 @@ +{ + self', + osConfig, + lib, + ... +}: let + inherit (lib.modules) mkIf mkMerge; + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; + + inherit (self'.packages) anime4k; + low1k = import ./low1k.nix {inherit anime4k;}; +in { + config = mkIf prg.media.mpv.enable { + programs.mpv = { + enable = true; + + inherit (prg.media.mpv) scripts; + + config = { + ytdl-format = "bestvideo+bestaudio/best"; + audio-display = false; + force-window = true; + hidpi-window-scale = false; + hwdec = "auto"; + keep-open = true; + keep-open-pause = false; + osd-on-seek = false; + profile = "gpu-hq"; + script-opts = "osc-seekbarstyle=knob,osc-deadzonesize=1,osc-minmousemove=1"; + slang = "chi"; + sub-auto = "fuzzy"; + sub-codepage = "gbk"; + osc = "no"; + osd-bar = "no"; + border = "no"; + }; + + bindings = mkMerge [ + # mpv keybindings + { + "Y" = "add sub-scale +0.1"; # increase subtitle font size + "G" = "add sub-scale -0.1"; # decrease subtitle font size + "y" = "sub_step -1"; # immediately display next subtitle + "g" = "sub_step +1"; # previous + "R" = "cycle_values window-scale 2 0.5 1"; # switch between 2x, 1/2, unresized window size + + "l" = "seek 5"; + "h" = "seek -5"; + "j" = "seek -60"; + "k" = "seek 60"; + + "s" = "cycle sub"; + "a" = "cycle audio"; + + "Alt+h" = "add chapter -1"; + "Alt+l" = "add chapter 1"; + "Ctrl+SPACE" = "add chapter 1"; + + "Alt+j" = "add video-zoom -0.25"; + "Alt+k" = "add video-zoom 0.25"; + + "Alt+J" = "add sub-pos -1"; + "Alt+K" = "add sub-pos +1"; + + "Ctrl+h" = "multiply speed 1/1.1"; + "Ctrl+l" = "multiply speed 1.1"; + "Ctrl+H" = "set speed 1.0"; + } + + # merge low1k's keybindings into mpv bindings section + low1k + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/media/mpv/low1k.nix b/nyx/homes/notashelf/programs/media/mpv/low1k.nix new file mode 100644 index 0000000..3d1fdb3 --- /dev/null +++ b/nyx/homes/notashelf/programs/media/mpv/low1k.nix @@ -0,0 +1,10 @@ +{anime4k}: { + # curl -sL https://github.com/bloc97/Anime4K/raw/master/GLSL_Instructions.md | grep '^CTRL' | sed -r -e '/^$/d' -e 's|~~/shaders/|${anime4k}/|g' -e 's|;\$|:$|g' -e "s| |\" = ''|" -e 's|^| "|' -e "s|$|'';|" + "CTRL+1" = ''no-osd change-list glsl-shaders set "${anime4k}/Anime4K_Clamp_Highlights.glsl:${anime4k}/Anime4K_Restore_CNN_M.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_M.glsl:${anime4k}/Anime4K_AutoDownscalePre_x2.glsl:${anime4k}/Anime4K_AutoDownscalePre_x4.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode A (Fast)"''; + "CTRL+2" = ''no-osd change-list glsl-shaders set "${anime4k}/Anime4K_Clamp_Highlights.glsl:${anime4k}/Anime4K_Restore_CNN_Soft_M.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_M.glsl:${anime4k}/Anime4K_AutoDownscalePre_x2.glsl:${anime4k}/Anime4K_AutoDownscalePre_x4.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode B (Fast)"''; + "CTRL+3" = ''no-osd change-list glsl-shaders set "${anime4k}/Anime4K_Clamp_Highlights.glsl:${anime4k}/Anime4K_Upscale_Denoise_CNN_x2_M.glsl:${anime4k}/Anime4K_AutoDownscalePre_x2.glsl:${anime4k}/Anime4K_AutoDownscalePre_x4.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode C (Fast)"''; + "CTRL+4" = ''no-osd change-list glsl-shaders set "${anime4k}/Anime4K_Clamp_Highlights.glsl:${anime4k}/Anime4K_Restore_CNN_M.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_M.glsl:${anime4k}/Anime4K_Restore_CNN_S.glsl:${anime4k}/Anime4K_AutoDownscalePre_x2.glsl:${anime4k}/Anime4K_AutoDownscalePre_x4.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode A+A (Fast)"''; + "CTRL+5" = ''no-osd change-list glsl-shaders set "${anime4k}/Anime4K_Clamp_Highlights.glsl:${anime4k}/Anime4K_Restore_CNN_Soft_M.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_M.glsl:${anime4k}/Anime4K_AutoDownscalePre_x2.glsl:${anime4k}/Anime4K_AutoDownscalePre_x4.glsl:${anime4k}/Anime4K_Restore_CNN_Soft_S.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode B+B (Fast)"''; + "CTRL+6" = ''no-osd change-list glsl-shaders set "${anime4k}/Anime4K_Clamp_Highlights.glsl:${anime4k}/Anime4K_Upscale_Denoise_CNN_x2_M.glsl:${anime4k}/Anime4K_AutoDownscalePre_x2.glsl:${anime4k}/Anime4K_AutoDownscalePre_x4.glsl:${anime4k}/Anime4K_Restore_CNN_S.glsl:${anime4k}/Anime4K_Upscale_CNN_x2_S.glsl"; show-text "Anime4K: Mode C+A (Fast)"''; + "CTRL+0" = ''no-osd change-list glsl-shaders clr ""; show-text "GLSL shaders cleared"''; +} diff --git a/nyx/homes/notashelf/programs/media/ncmpcpp/binds.nix b/nyx/homes/notashelf/programs/media/ncmpcpp/binds.nix new file mode 100644 index 0000000..d888f6c --- /dev/null +++ b/nyx/homes/notashelf/programs/media/ncmpcpp/binds.nix @@ -0,0 +1,20 @@ +{ + programs.ncmpcpp.bindings = [ + { + key = "j"; + command = "scroll_down"; + } + { + key = "k"; + command = "scroll_up"; + } + { + key = "J"; + command = ["select_item" "scroll_down"]; + } + { + key = "K"; + command = ["select_item" "scroll_up"]; + } + ]; +} diff --git a/nyx/homes/notashelf/programs/media/ncmpcpp/default.nix b/nyx/homes/notashelf/programs/media/ncmpcpp/default.nix new file mode 100644 index 0000000..3a371be --- /dev/null +++ b/nyx/homes/notashelf/programs/media/ncmpcpp/default.nix @@ -0,0 +1,28 @@ +{ + osConfig, + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; +in { + imports = [./binds.nix ./settings.nix]; + + config.programs.ncmpcpp = mkIf prg.media.ncmpcpp.enable { + enable = true; + + # provide visualisier support for ncmpcpp + # it will optionally display a visualiser in the terminal + # if the mpd server is configured to write the visualiser + # mipe - e.g. /tmp/mpd.fifo + package = pkgs.ncmpcpp.override {visualizerSupport = true;}; + + # look for music tracks inside mpd's music directory + mpdMusicDir = config.services.mpd.musicDirectory; + }; +} diff --git a/nyx/homes/notashelf/programs/media/ncmpcpp/settings.nix b/nyx/homes/notashelf/programs/media/ncmpcpp/settings.nix new file mode 100644 index 0000000..935ed82 --- /dev/null +++ b/nyx/homes/notashelf/programs/media/ncmpcpp/settings.nix @@ -0,0 +1,61 @@ +{config, ...}: { + programs.ncmpcpp.settings = { + # Miscelaneous + ncmpcpp_directory = "${config.xdg.configHome}/ncmpcpp"; + ignore_leading_the = true; + external_editor = "nvim"; + message_delay_time = 1; + playlist_disable_highlight_delay = 2; + autocenter_mode = "yes"; + centered_cursor = "yes"; + allow_for_physical_item_deletion = "no"; + lines_scrolled = "0"; + follow_now_playing_lyrics = "yes"; + lyrics_fetchers = "musixmatch"; + + # visualizer + visualizer_data_source = "/tmp/mpd.fifo"; + visualizer_output_name = "mpd_visualizer"; + visualizer_type = "ellipse"; + visualizer_look = "●● "; + visualizer_color = "blue, green"; + + # appearance + colors_enabled = "yes"; + playlist_display_mode = "classic"; + user_interface = "classic"; + volume_color = "white"; + + # window + song_window_title_format = "Music"; + statusbar_visibility = "no"; + header_visibility = "no"; + titles_visibility = "no"; + # progress bar + progressbar_look = "‎‎‎"; + progressbar_color = "black"; + progressbar_elapsed_color = "blue"; + + # song list + song_status_format = "$7%t"; + song_list_format = "$(008)%t$R $(247)%a$R$5 %l$8"; + song_columns_list_format = "(53)[blue]{tr} (45)[blue]{a}"; + + current_item_prefix = "$b$2| "; + current_item_suffix = "$/b$5"; + + now_playing_prefix = "$b$5| "; + now_playing_suffix = "$/b$5"; + + song_library_format = "{{%a - %t} (%b)}|{%f}"; + + # colors + main_window_color = "blue"; + + current_item_inactive_column_prefix = "$b$5"; + current_item_inactive_column_suffix = "$/b$5"; + + color1 = "white"; + color2 = "blue"; + }; +} diff --git a/nyx/homes/notashelf/programs/media/packages.nix b/nyx/homes/notashelf/programs/media/packages.nix new file mode 100644 index 0000000..9c61d01 --- /dev/null +++ b/nyx/homes/notashelf/programs/media/packages.nix @@ -0,0 +1,39 @@ +{ + inputs', + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + inherit (osConfig) modules; + + env = modules.usrEnv; + prg = env.programs; + cfg = prg.media; +in { + config = mkIf cfg.addDefaultPackages { + home.packages = with pkgs; + [ + # tools that help with media operations/management + ffmpeg-full + yt-dlp + mpc_cli + playerctl + pavucontrol + pulsemixer + imv + cantata + easytag + kid3 + musikcube + + # get ani-cli and mov-cli from my own derivations + # I don't want to wait for nixpkgs + inputs'.nyxpkgs.packages.mov-cli + inputs'.nyxpkgs.packages.ani-cli + ] + ++ cfg.extraPackages; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/default.nix b/nyx/homes/notashelf/programs/terminal/default.nix new file mode 100644 index 0000000..320e342 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./editors + ./emulators + ./shell + ./tools + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/default.nix b/nyx/homes/notashelf/programs/terminal/editors/default.nix new file mode 100644 index 0000000..e17bc1b --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + #./helix # sucks + ./neovim # full-blown IDE + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/helix/default.nix b/nyx/homes/notashelf/programs/terminal/editors/helix/default.nix new file mode 100644 index 0000000..655641c --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/helix/default.nix @@ -0,0 +1,203 @@ +{ + lib, + pkgs, + osConfig, + inputs', + ... +}: let + inherit (lib) mkIf; + + dev = osConfig.modules.device; + acceptedTypes = ["desktop" "laptop" "hybrid" "server" "lite"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + programs.helix = { + enable = false; + package = inputs'.helix.packages.default.overrideAttrs (self: { + makeWrapperArgs = with pkgs; + self.makeWrapperArgs + or [] + ++ [ + "--suffix" + "PATH" + ":" + (lib.makeBinPath [ + clang-tools + marksman + nil + luajitPackages.lua-lsp + nodePackages.bash-language-server + nodePackages.vscode-css-languageserver-bin + nodePackages.vscode-langservers-extracted + nodePackages.prettier + rustfmt + rust-analyzer + black + alejandra + shellcheck + ]) + ]; + }); + settings = { + theme = "catppuccin_mocha_transparent"; + icons = "nerdfonts"; + keys.normal = { + "{" = "goto_prev_paragraph"; + "}" = "goto_next_paragraph"; + "X" = "extend_line_above"; + "esc" = ["collapse_selection" "keep_primary_selection"]; + "C-q" = ":xa"; + "C-w" = "file_picker"; + "space" = { + "space" = "file_picker"; + "w" = ":w"; + "q" = ":bc"; + "u" = { + "f" = ":format"; # format using LSP formatter + "w" = ":set whitespace.render all"; + "W" = ":set whitespace.render none"; + }; + }; + }; + keys.select = { + "%" = "match_brackets"; + }; + editor = { + color-modes = true; + cursorline = true; + mouse = true; + idle-timeout = 1; + line-number = "relative"; + scrolloff = 5; + rainbow-brackets = true; + completion-replace = true; + cursor-word = true; + bufferline = "always"; + true-color = true; + rulers = [80]; + soft-wrap.enable = true; + indent-guides = { + render = true; + }; + sticky-context = { + enable = true; + indicator = true; + }; + lsp = { + display-messages = true; + display-inlay-hints = true; + }; + gutters = ["diagnostics" "line-numbers" "spacer" "diff"]; + statusline = { + mode-separator = ""; + separator = ""; + left = ["mode" "selections" "spinner" "file-name" "total-line-numbers"]; + center = []; + right = ["diagnostics" "file-encoding" "file-line-ending" "file-type" "position-percentage" "position"]; + mode = { + normal = "NORMAL"; + insert = "INSERT"; + select = "SELECT"; + }; + }; + + whitespace.characters = { + space = "·"; + nbsp = "⍽"; + tab = "→"; + newline = "⤶"; + }; + + cursor-shape = { + insert = "bar"; + normal = "block"; + select = "block"; + }; + }; + }; + # override catppuccin theme and remove background to fix transparency + themes = { + catppuccin_mocha_transparent = { + "inherits" = "catppuccin_mocha"; + "ui.virtual.inlay-hint" = { + fg = "surface1"; + }; + "ui.background" = "{}"; + }; + }; + + languages = { + language = [ + { + name = "bash"; + auto-format = true; + formatter = { + command = "${pkgs.shfmt}/bin/shfmt"; + args = ["-i" "2" "-"]; + }; + } + { + name = "html"; + file-types = ["html" "tera"]; + } + { + name = "clojure"; + injection-regex = "(clojure|clj|edn|boot|yuck)"; + file-types = ["clj" "cljs" "cljc" "clje" "cljr" "cljx" "edn" "boot" "yuck"]; + } + ]; + + language-server = { + bash-language-server = { + command = "${pkgs.nodePackages.bash-language-server}/bin/bash-language-server"; + args = ["start"]; + }; + + clangd = { + command = "${pkgs.clang-tools}/bin/clangd"; + clangd.fallbackFlags = ["-std=c++2b"]; + }; + + nil = { + command = lib.getExe pkgs.nil; + config.nil.formatting.command = ["${lib.getExe pkgs.alejandra}" "-q"]; + }; + + vscode-css-language-server = { + command = "${pkgs.nodePackages.vscode-css-languageserver-bin}/bin/css-languageserver"; + args = ["--stdio"]; + }; + }; + }; + }; + + home.packages = with pkgs; [ + # some other lsp related packages / dev tools + lldb # debugging stuff + gopls # go + revive # go + rust-analyzer # rust + texlab # latex + zls # zig + #elixir_ls # broken + gcc # C/++ + uncrustify # source code beautifier + black # python + alejandra # nix formatting + shellcheck # bash + gawk + haskellPackages.haskell-language-server + nodePackages.typescript-language-server + java-language-server + kotlin-language-server + nodePackages.vls + nodePackages.yaml-language-server + nodePackages.jsonlint + nodePackages.yarn + nodePackages.pnpm + sumneko-lua-language-server + nodePackages.vscode-langservers-extracted + cargo + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/default.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/default.nix new file mode 100644 index 0000000..17e3c3b --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/default.nix @@ -0,0 +1,31 @@ +{ + inputs, + lib, + ... +}: let + inherit (builtins) filter map toString elem; + inherit (lib.filesystem) listFilesRecursive; + inherit (lib.strings) hasSuffix; + inherit (lib.lists) concatLists; + + mkNeovimModule = { + path, + ignoredPaths ? [./plugins/sources/default.nix], + }: + filter (hasSuffix ".nix") ( + map toString ( + filter (path: path != ./default.nix && !elem path ignoredPaths) (listFilesRecursive path) + ) + ); + + nvf = inputs.neovim-flake; +in { + imports = concatLists [ + # neovim-flake home-manager module + [nvf.homeManagerModules.default] + + # construct this entire directory as a module + # which means all default.nix files will be imported automatically + (mkNeovimModule {path = ./.;}) + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/autocmds.lua b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/autocmds.lua new file mode 100644 index 0000000..f3fa77b --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/autocmds.lua @@ -0,0 +1,60 @@ +-- alias for vim.api.nvim_create_autocmd +local create_autocmd = vim.api.nvim_create_autocmd + +-- taken from https://github.com/sitiom/nvim-numbertoggle +-- I would much rather avoid fetching yet another plugin for something +-- that should be done locally - and not as a plugin +local augroup = vim.api.nvim_create_augroup("numbertoggle", {}) + +create_autocmd({ "BufEnter", "FocusGained", "InsertLeave", "CmdlineLeave", "WinEnter" }, { + pattern = "*", + group = augroup, + callback = function() + if vim.o.nu and vim.api.nvim_get_mode().mode ~= "i" then + vim.opt.relativenumber = true + end + end, +}) + +create_autocmd({ "BufLeave", "FocusLost", "InsertEnter", "CmdlineEnter", "WinLeave" }, { + pattern = "*", + group = augroup, + callback = function() + if vim.o.nu then + vim.opt.relativenumber = false + vim.cmd "redraw" + end + end, +}) + + +-- enable spell checking & line wrapping +-- for git commit messages +create_autocmd({ "FileType" }, { + pattern = { "gitcommit" }, + callback = function() + vim.opt_local.wrap = true + vim.opt_local.spell = true + end, +}) + +-- Highlight yank after yanking +create_autocmd({ "TextYankPost" }, { + callback = function() + vim.highlight.on_yank({ higroup = "Visual", timeout = 200 }) + end, +}) + + +-- Close terminal window if process exists with code 0 +create_autocmd("TermClose", { + callback = function() + if not vim.b.no_auto_quit then + vim.defer_fn(function() + if vim.api.nvim_get_current_line() == "[Process exited 0]" then + vim.api.nvim_buf_delete(0, { force = true }) + end + end, 50) + end + end, +}) diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/core.lua b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/core.lua new file mode 100644 index 0000000..bb848f9 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/core.lua @@ -0,0 +1,25 @@ +local options = { + -- disable the -- STATUS -- line + showmode = false, + + -- spellchecking + spell = true, + + -- spell langs + spelllang = { "en" }, +} + + +-- iterate over the options table and set the options +-- for each key = value pair +for key, value in pairs(options) do + vim.opt[key] = value +end + +vim.api.nvim_create_autocmd({ "FileType" }, { + pattern = { "toggleterm" }, + callback = function() + vim.opt_local.wrap = false + vim.opt_local.spell = false + end, +}) diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/handlers.lua b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/handlers.lua new file mode 100644 index 0000000..9751fc8 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/handlers.lua @@ -0,0 +1,37 @@ +local float_options = { + border = 'single', + max_width = math.ceil(vim.api.nvim_win_get_width(0) * 0.6), + max_height = math.ceil(vim.api.nvim_win_get_height(0) * 0.8), +} + +vim.lsp.handlers['textDocument/publishDiagnostics'] = + vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + virtual_text = true, + signs = false, + underline = true, + update_in_insert = false, + severity_sort = true, + }) + +vim.lsp.handlers['textDocument/show_line_diagnostics'] = + vim.lsp.with(vim.lsp.handlers.hover, float_options) + +-- Prevent show notification +-- +vim.lsp.handlers['textDocument/hover'] = function(_, result, ctx, config) + config = config or float_options + config.focus_id = ctx.method + if not result then + return + end + local markdown_lines = + vim.lsp.util.convert_input_to_markdown_lines(result.contents) + markdown_lines = vim.lsp.util.trim_empty_lines(markdown_lines) + if vim.tbl_isempty(markdown_lines) then + return + end + return vim.lsp.util.open_floating_preview(markdown_lines, 'markdown', config) +end + +vim.lsp.handlers['textDocument/signatureHelp'] = + vim.lsp.with(vim.lsp.handlers.signature_help, float_options) diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/misc.lua b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/misc.lua new file mode 100644 index 0000000..142084f --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/misc.lua @@ -0,0 +1,4 @@ +-- disables "how to disable mouse" message +-- in right click popups +vim.cmd.aunmenu [[PopUp.How-to\ disable\ mouse]] +vim.cmd.aunmenu [[PopUp.-1-]] diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/neovide.lua b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/neovide.lua new file mode 100644 index 0000000..dd789a4 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/neovide.lua @@ -0,0 +1,5 @@ +if vim.g.neovide then + vim.o.guifont = "Iosevka Nerd Font:h14" -- text below applies for VimScript + vim.g.neovide_theme = 'auto' + vim.g.neovide_transparency = 0.95 +end diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/notify.lua b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/notify.lua new file mode 100644 index 0000000..9158cf1 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/lua/notify.lua @@ -0,0 +1,59 @@ +local noice = require("noice") +local no_top_text = { + opts = { + border = { + text = { top = "" }, + }, + }, +} + +noice.setup({ + cmdline = { + format = { + cmdline = no_top_text, + filter = no_top_text, + lua = no_top_text, + search_down = no_top_text, + search_up = no_top_text, + }, + }, + + lsp = { + override = { + ["cmp.entry.get_documentation"] = true, + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + }, + progress = { + enabled = false, + }, + }, + + popupmenu = { + backend = "cmp", + }, + + routes = { + { + filter = { + event = "msg_show", + kind = "search_count", + }, + opts = { skip = true }, + }, + }, + + views = { + cmdline_popup = { + border = { + style = "single", + }, + }, + confirm = { + border = { + style = "single", + text = { top = "" }, + }, + }, + }, +}) diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/insert.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/insert.nix new file mode 100644 index 0000000..b674dae --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/insert.nix @@ -0,0 +1,9 @@ +{ + programs.neovim-flake.settings.vim.maps = { + insert = { + # vsnip + #"".action = "(vsnip-jump-next)"; + #"".action = "(vsnip-jump-prev)"; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/normal.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/normal.nix new file mode 100644 index 0000000..bb78e93 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/normal.nix @@ -0,0 +1,59 @@ +{ + programs.neovim-flake.settings.vim.maps = { + normal = { + # General + "fd".action = ":lua vim.g.formatsave = not vim.g.formatsave"; + "zt".action = ":let g:default_terminal = v:count1"; + "e".action = ":NvimTreeToggle"; + "ld".action = ":lua vim.diagnostic.setqflist({open = true})"; + "lf".action = ":lua vim.lsp.buf.format()"; + "li".action = ":lua vim.lsp.buf.implementation()"; + + # Diffview + "gdq".action = ":DiffviewClose"; + "gdd".action = ":DiffviewOpen "; + "gdm".action = ":DiffviewOpen"; + "gdh".action = ":DiffviewFileHistory %"; + "gde".action = ":DiffviewToggleFiles"; + + # Git + "gu".action = "Gitsigns undo_stage_hunk"; + "g".action = "Gitsigns preview_hunk"; + "gp".action = "Gitsigns prev_hunk"; + "gn".action = "Gitsigns next_hunk"; + "gP".action = "Gitsigns preview_hunk_inline"; + "gR".action = "Gitsigns reset_buffer"; + "gb".action = "Gitsigns blame_line"; + "gD".action = "Gitsigns diffthis HEAD"; + "gw".action = "Gitsigns toggle_word_diff"; + + # Telescope + "".action = ":Telescope resume"; + "fq".action = ":Telescope quickfix"; + "f/".action = ":Telescope live_grep"; + + # Aerial + "".action = ":AerialToggle"; + + # vsnip + #"".action = "(vsnip-jump-next)"; + #"".action = "(vsnip-jump-prev)"; + }; + + normalVisualOp = { + "gs".action = ":Gitsigns stage_hunk"; + "gr".action = ":Gitsigns reset_hunk"; + "lr".action = "lua vim.lsp.buf.references()"; + + # ssr.nvim + "sr".action = ":lua require('ssr').open()"; + + # Toggleterm + "ct" = { + # action = ":ToggleTermSendVisualLines v:count"; + action = "':ToggleTermSendVisualLines ' . v:count == 0 ? g:default_terminal : v:count"; + expr = true; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/select.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/select.nix new file mode 100644 index 0000000..a8b4a2f --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/select.nix @@ -0,0 +1,9 @@ +{ + programs.neovim-flake.settings.vim.maps = { + select = { + # vsnip + #"".action = "(vsnip-jump-next)"; + #"".action = "(vsnip-jump-prev)"; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/terminal.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/terminal.nix new file mode 100644 index 0000000..ecf1799 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/mappings/terminal.nix @@ -0,0 +1,7 @@ +{ + programs.neovim-flake.settings.vim.maps = { + terminal = { + "".action = "q"; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/extra.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/extra.nix new file mode 100644 index 0000000..e19f353 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/extra.nix @@ -0,0 +1,141 @@ +{ + self, + pkgs, + ... +}: let + inherit (pkgs.vimPlugins) friendly-snippets aerial-nvim nvim-surround undotree mkdir-nvim ssr-nvim direnv-vim legendary-nvim; + pluginSources = import ./sources {inherit self pkgs;}; +in { + programs.neovim-flake.settings.vim.extraPlugins = { + # plugins that are pulled from nixpkgs + direnv = {package = direnv-vim;}; + friendly-snippets = {package = friendly-snippets;}; + mkdir-nvim = {package = mkdir-nvim;}; + aerial = { + package = aerial-nvim; + setup = "require('aerial').setup {}"; + }; + + nvim-surround = { + package = nvim-surround; + setup = "require('nvim-surround').setup {}"; + }; + + undotree = { + package = undotree; + setup = '' + vim.g.undotree_ShortIndicators = true + vim.g.undotree_TreeVertShape = '│' + ''; + }; + + ssr-nvim = { + package = ssr-nvim; + setup = "require('ssr').setup {}"; + }; + + legendary = { + package = legendary-nvim; + setup = '' + require('legendary').setup {}; + ''; + }; + + # plugins that are built from their sources + regexplainer = {package = pluginSources.regexplainer;}; + vim-nftables = {package = pluginSources.vim-nftables;}; + + data-view = { + package = pluginSources.data-viewer-nvim; + setup = '' + -- open data files in data-viewer.nvim + vim.api.nvim_exec([[ + autocmd BufReadPost,BufNewFile *.sqlite,*.csv,*.tsv DataViewer + ]], false) + + + -- keybinds + vim.api.nvim_set_keymap('n', 'dv', ':DataViewer', {noremap = true}) + vim.api.nvim_set_keymap('n', 'dvn', ':DataViewerNextTable', {noremap = true}) + vim.api.nvim_set_keymap('n', 'dvp', ':DataViewerPrevTable', {noremap = true}) + vim.api.nvim_set_keymap('n', 'dvc', ':DataViewerClose', {noremap = true}) + ''; + }; + + slides-nvim = { + package = pluginSources.slides-nvim; + setup = "require('slides').setup {}"; + }; + + hmts = { + package = pluginSources.hmts; + after = ["treesitter"]; + }; + + smart-splits = { + package = pluginSources.smart-splits; + setup = "require('smart-splits').setup {}"; + }; + + neotab-nvim = { + package = pluginSources.neotab-nvim; + setup = '' + require('neotab').setup { + tabkey = "", + act_as_tab = true, + behavior = "nested", ---@type ntab.behavior + pairs = { ---@type ntab.pair[] + { open = "(", close = ")" }, + { open = "[", close = "]" }, + { open = "{", close = "}" }, + { open = "'", close = "'" }, + { open = '"', close = '"' }, + { open = "`", close = "`" }, + { open = "<", close = ">" }, + }, + exclude = {}, + smart_punctuators = { + enabled = false, + semicolon = { + enabled = false, + ft = { "cs", "c", "cpp", "java" }, + }, + escape = { + enabled = false, + triggers = {}, ---@type table + }, + }, + } + ''; + }; + + specs-nvim = { + package = pluginSources.specs-nvim; + setup = '' + require('specs').setup { + show_jumps = true, + popup = { + delay_ms = 0, + inc_ms = 15, + blend = 15, + width = 10, + winhl = "PMenu", + fader = require('specs').linear_fader, + resizer = require('specs').shrink_resizer + }, + + ignore_filetypes = {'NvimTree', 'undotree'}, + + ignore_buftypes = {nofile = true}, + } + + -- toggle specs using the keybind + vim.api.nvim_set_keymap('n', '', ':lua require("specs").show_specs()', { noremap = true, silent = true }) + + -- bind specs to navigation keys + vim.api.nvim_set_keymap('n', 'n', 'n:lua require("specs").show_specs()', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'N', 'N:lua require("specs").show_specs()', { noremap = true, silent = true }) + ''; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/assistant.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/assistant.nix new file mode 100644 index 0000000..f1267f8 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/assistant.nix @@ -0,0 +1,8 @@ +{ + programs.neovim-flake.settings.vim = { + assistant.copilot = { + enable = true; + cmp.enable = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/autocomplete.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/autocomplete.nix new file mode 100644 index 0000000..61bbd28 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/autocomplete.nix @@ -0,0 +1,16 @@ +{ + programs.neovim-flake.settings.vim = { + autocomplete = { + enable = true; + type = "nvim-cmp"; + mappings = { + # close = ""; + confirm = ""; + next = ""; + previous = ""; + scrollDocsDown = ""; + scrollDocsUp = ""; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/autopairs.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/autopairs.nix new file mode 100644 index 0000000..11286de --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/autopairs.nix @@ -0,0 +1,5 @@ +{ + programs.neovim-flake.settings.vim = { + autopairs.enable = true; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/binds.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/binds.nix new file mode 100644 index 0000000..d626547 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/binds.nix @@ -0,0 +1,8 @@ +{ + programs.neovim-flake.settings.vim = { + binds = { + whichKey.enable = true; + cheatsheet.enable = false; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/comments.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/comments.nix new file mode 100644 index 0000000..4f0a7a7 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/comments.nix @@ -0,0 +1,5 @@ +{ + programs.neovim-flake.settings.vim = { + comments.comment-nvim.enable = true; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/dashboard.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/dashboard.nix new file mode 100644 index 0000000..81e8542 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/dashboard.nix @@ -0,0 +1,7 @@ +{ + programs.neovim-flake.settings.vim = { + dashboard = { + alpha.enable = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/debugger.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/debugger.nix new file mode 100644 index 0000000..a40e92d --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/debugger.nix @@ -0,0 +1,8 @@ +{ + programs.neovim-flake.settings.vim = { + debugger.nvim-dap = { + enable = true; + ui.enable = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/filetree.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/filetree.nix new file mode 100644 index 0000000..da13802 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/filetree.nix @@ -0,0 +1,63 @@ +{ + programs.neovim-flake.settings.vim = { + filetree = { + nvimTree = { + enable = true; + openOnSetup = true; + disableNetrw = true; + + mappings = { + toggle = ""; + }; + + setupOpts = { + update_focused_file.enable = true; + + hijack_unnamed_buffer_when_opening = true; + hijack_cursor = true; + hijack_directories = { + enable = true; + auto_open = true; + }; + + git = { + enable = true; + show_on_dirs = false; + timeout = 500; + }; + + view = { + cursorline = false; + width = 35; + }; + + renderer = { + indent_markers.enable = true; + root_folder_label = false; # inconsistent + + icons = { + modified_placement = "after"; + git_placement = "after"; + show.git = true; + show.modified = true; + }; + }; + + diagnostics.enable = true; + + modified = { + enable = true; + show_on_dirs = false; + show_on_open_dirs = true; + }; + + actions = { + change_dir.enable = false; + change_dir.global = false; + open_file.window_picker.enable = true; + }; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/gestures.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/gestures.nix new file mode 100644 index 0000000..d9e24e8 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/gestures.nix @@ -0,0 +1,5 @@ +{ + programs.neovim-flake.settings.vim = { + gestures.gesture-nvim.enable = false; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/git.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/git.nix new file mode 100644 index 0000000..8f46373 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/git.nix @@ -0,0 +1,11 @@ +{ + programs.neovim-flake.settings.vim = { + git = { + enable = true; + gitsigns = { + enable = true; + codeActions = false; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/languages.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/languages.nix new file mode 100644 index 0000000..219729e --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/languages.nix @@ -0,0 +1,58 @@ +{ + config, + pkgs, + lib, + ... +}: { + programs.neovim-flake.settings.vim = { + languages = { + enableLSP = true; + enableFormat = true; + enableTreesitter = true; + enableExtraDiagnostics = true; + + markdown.enable = true; + nix.enable = true; + html.enable = true; + css.enable = true; + tailwind.enable = true; + ts.enable = true; + go.enable = true; + python.enable = true; + bash.enable = true; + zig.enable = false; + dart.enable = false; + elixir.enable = false; + svelte.enable = false; + sql.enable = false; + java = let + jdtlsCache = "${config.xdg.cacheHome}/jdtls"; + in { + enable = true; + lsp.package = [ + "${lib.getExe pkgs.jdt-language-server}" + "-configuration ${jdtlsCache}/config" + "-data ${jdtlsCache}/workspace" + ]; + }; + + lua = { + enable = true; + lsp.neodev.enable = true; + }; + + rust = { + enable = true; + crates.enable = true; + }; + + clang = { + enable = true; + lsp = { + enable = true; + server = "clangd"; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/lsp.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/lsp.nix new file mode 100644 index 0000000..ae8c807 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/lsp.nix @@ -0,0 +1,15 @@ +{ + programs.neovim-flake.settings.vim = { + lsp = { + formatOnSave = true; + lspkind.enable = true; + lsplines.enable = true; + lightbulb.enable = true; + lspsaga.enable = false; + lspSignature.enable = true; + nvimCodeActionMenu.enable = true; + trouble.enable = false; + nvim-docs-view.enable = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/minimap.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/minimap.nix new file mode 100644 index 0000000..42bd866 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/minimap.nix @@ -0,0 +1,9 @@ +{ + programs.neovim-flake.settings.vim = { + minimap = { + # cool for vanity but practically useless on small screens + minimap-vim.enable = false; + codewindow.enable = false; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/notes.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/notes.nix new file mode 100644 index 0000000..2a02e37 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/notes.nix @@ -0,0 +1,9 @@ +{ + programs.neovim-flake.settings.vim = { + notes = { + todo-comments.enable = true; + mind-nvim.enable = false; + obsidian.enable = false; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/notify.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/notify.nix new file mode 100644 index 0000000..040aa7f --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/notify.nix @@ -0,0 +1,7 @@ +{ + programs.neovim-flake.settings.vim = { + notify = { + nvim-notify.enable = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/presence.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/presence.nix new file mode 100644 index 0000000..83e4dd8 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/presence.nix @@ -0,0 +1,5 @@ +{ + programs.neovim-flake.settings.vim = { + presence.neocord.enable = false; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/projects.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/projects.nix new file mode 100644 index 0000000..9d200d8 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/projects.nix @@ -0,0 +1,22 @@ +{ + programs.neovim-flake.settings.vim = { + projects = { + project-nvim = { + enable = true; + setupOpts = { + manualMode = false; + detectionMethods = ["lsp" "pattern"]; + patterns = [ + ".git" + ".hg" + "Makefile" + "package.json" + "index.*" + ".anchor" + "flake.nix" + ]; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/session.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/session.nix new file mode 100644 index 0000000..a76394d --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/session.nix @@ -0,0 +1,8 @@ +{ + programs.neovim-flake.settings.vim = { + session.nvim-session-manager = { + enable = false; + setupOpts.autoload_mode = "Disabled"; # misbehaves with dashboard + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/statusline.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/statusline.nix new file mode 100644 index 0000000..1190f35 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/statusline.nix @@ -0,0 +1,10 @@ +{ + programs.neovim-flake.settings.vim = { + statusline = { + lualine = { + enable = true; + theme = "catppuccin"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/tabline.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/tabline.nix new file mode 100644 index 0000000..5771d16 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/tabline.nix @@ -0,0 +1,7 @@ +{ + programs.neovim-flake.settings.vim = { + tabline = { + nvimBufferline.enable = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/telescope.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/telescope.nix new file mode 100644 index 0000000..f96b419 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/telescope.nix @@ -0,0 +1,5 @@ +{ + programs.neovim-flake.settings.vim = { + telescope.enable = true; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/template.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/template.nix new file mode 100644 index 0000000..ecf1b40 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/template.nix @@ -0,0 +1,4 @@ +{ + programs.neovim-flake.settings.vim = { + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/terminal.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/terminal.nix new file mode 100644 index 0000000..b53f695 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/terminal.nix @@ -0,0 +1,18 @@ +{ + programs.neovim-flake.settings.vim = { + terminal = { + toggleterm = { + enable = true; + mappings.open = ""; + + setupOpts = { + direction = "tab"; + lazygit = { + enable = true; + direction = "tab"; + }; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/theme.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/theme.nix new file mode 100644 index 0000000..93824f3 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/theme.nix @@ -0,0 +1,10 @@ +{ + programs.neovim-flake.settings.vim = { + theme = { + enable = true; + name = "catppuccin"; + style = "mocha"; + transparent = true; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/treesitter.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/treesitter.nix new file mode 100644 index 0000000..56afcbb --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/treesitter.nix @@ -0,0 +1,14 @@ +{pkgs, ...}: { + programs.neovim-flake.settings.vim = { + treesitter = { + fold = true; + context.enable = true; + + # extra grammars that will be installed by Nix + grammars = with pkgs.vimPlugins.nvim-treesitter.builtGrammars; [ + regex # for regexplainer + kdl # zellij configurations are in KDL, I want syntax highlighting + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/ui.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/ui.nix new file mode 100644 index 0000000..8edab0c --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/ui.nix @@ -0,0 +1,34 @@ +{ + programs.neovim-flake.settings.vim = { + ui = { + noice.enable = true; + colorizer.enable = true; + modes-nvim.enable = false; + illuminate.enable = true; + + breadcrumbs = { + enable = true; + source = "nvim-navic"; + navbuddy.enable = false; + }; + + smartcolumn = { + enable = true; + setupOpts = { + columnAt.languages = { + markdown = [80]; + nix = [150]; + ruby = 110; + java = 120; + go = [130]; + }; + }; + }; + + borders = { + enable = true; + globalStyle = "rounded"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/utility.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/utility.nix new file mode 100644 index 0000000..a929e4c --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/utility.nix @@ -0,0 +1,24 @@ +{pkgs, ...}: { + programs.neovim-flake.settings.vim = { + utility = { + ccc.enable = true; + icon-picker.enable = true; + diffview-nvim.enable = true; + + vim-wakatime = { + enable = true; + cli-package = pkgs.wakatime; + }; + + motion = { + hop.enable = true; + leap.enable = false; + }; + + preview = { + glow.enable = true; + markdownPreview.enable = true; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/visuals.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/visuals.nix new file mode 100644 index 0000000..9edf972 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/settings/visuals.nix @@ -0,0 +1,34 @@ +{ + programs.neovim-flake.settings.vim = { + visuals = { + enable = true; + nvimWebDevicons.enable = true; + scrollBar.enable = true; + smoothScroll.enable = false; + cellularAutomaton.enable = false; + highlight-undo.enable = true; + + indentBlankline = { + enable = true; + fillChar = null; + eolChar = null; + scope.enabled = true; + }; + + cursorline = { + enable = true; + lineTimeout = 0; + }; + + fidget-nvim = { + enable = true; + setupOpts = { + notification.window = { + winblend = 0; + border = "none"; + }; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/sources/default.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/sources/default.nix new file mode 100644 index 0000000..0268711 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/plugins/sources/default.nix @@ -0,0 +1,87 @@ +{ + self, + pkgs, + ... +}: let + inherit (self) pins; + inherit (pkgs) fetchFromGitHub; + inherit (pkgs.vimUtils) buildVimPlugin; + + sources = { + hmts = buildVimPlugin { + name = "hmts.nvim"; + src = pins."hmts.nvim"; + }; + + smart-splits = buildVimPlugin { + name = "smart-splits"; + src = pins."smart-splits.nvim"; + }; + + slides-nvim = buildVimPlugin { + name = "slides.nvim"; + src = pins."slides.nvim"; + }; + + regexplainer = buildVimPlugin { + name = "nvim-regexplainer"; + src = fetchFromGitHub { + owner = "bennypowers"; + repo = "nvim-regexplainer"; + rev = "4250c8f3c1307876384e70eeedde5149249e154f"; + hash = "sha256-15DLbKtOgUPq4DcF71jFYu31faDn52k3P1x47GL3+b0="; + }; + }; + + specs-nvim = buildVimPlugin { + name = "specs.nvim"; + src = fetchFromGitHub { + owner = "edluffy"; + repo = "specs.nvim"; + rev = "2743e412bbe21c9d73954c403d01e8de7377890d"; + hash = "sha256-mYTzltCEKO8C7BJ3WrB/iFa1Qq1rgJlcjW6NYHPfmPk="; + }; + }; + + deferred-clipboard = buildVimPlugin { + name = "deferred-clipboard"; + src = fetchFromGitHub { + owner = "EtiamNullam"; + repo = "deferred-clipboard.nvim"; + rev = "810a29d166eaa41afc220cc7cd85eeaa3c43b37f"; + hash = "sha256-nanNQEtpjv0YKEkkrPmq/5FPxq+Yj/19cs0Gf7YgKjU="; + }; + }; + + data-viewer-nvim = buildVimPlugin { + name = "data-viewer.nvim"; + src = fetchFromGitHub { + owner = "VidocqH"; + repo = "data-viewer.nvim"; + rev = "40ddf37bb7ab6c04ff9e820812d1539afe691668"; + hash = "sha256-D5hvLhsYski11H9qiDDL2zlZMtYmbpHgpewiWR6C7rE="; + }; + }; + + vim-nftables = buildVimPlugin { + name = "vim-nftables"; + src = fetchFromGitHub { + owner = "awisse"; + repo = "vim-nftables"; + rev = "bc29309080b4c7e1888ffb1a830846be16e5b8e7"; + hash = "sha256-L1x3Hv95t/DBBrLtPBKrqaTbIPor/NhVuEHVIYo/OaA="; + }; + }; + + neotab-nvim = buildVimPlugin { + name = "neotab.nvim"; + src = fetchFromGitHub { + owner = "kawre"; + repo = "neotab.nvim"; + rev = "6c6107dddaa051504e433608f59eca606138269b"; + hash = "sha256-bSFKbjj8fJHdfBzYoQ9l3NU0GAYfdfCbESKbwdbLNSw="; + }; + }; + }; +in + sources diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/settings.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/settings.nix new file mode 100644 index 0000000..71322a9 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/settings.nix @@ -0,0 +1,57 @@ +{ + inputs, + pkgs, + lib, + ... +}: let + inherit (builtins) filter map toString; + inherit (lib.filesystem) listFilesRecursive; + inherit (lib.strings) hasSuffix fileContents removeSuffix; + inherit (lib.attrsets) genAttrs; + + nvf = inputs.neovim-flake; +in { + config = { + programs.neovim-flake = { + enable = true; + settings = { + vim = { + package = pkgs.neovim-unwrapped; + + viAlias = true; + vimAlias = true; + + enableEditorconfig = true; + preventJunkFiles = true; + enableLuaLoader = true; + useSystemClipboard = true; + spellChecking.enable = false; + + debugMode = { + enable = false; + logFile = "/tmp/nvim.log"; + }; + + luaConfigRC = let + inherit (nvf.lib.nvim.dag) entryAnywhere; + + # get the name of each lua file in the lua directory, where setting files reside + configPaths = map (f: removeSuffix ".lua" f) (filter (hasSuffix ".lua") (map toString (listFilesRecursive ./lua))); + + # get the path of each file by removing the ./. prefix from each element in the list + configNames = map (p: removeSuffix "./" p) configPaths; + + # generates a key-value pair that looks roughly as follows: + # "fileName" = entryAnywhere "" + # which is expected by neovim-flake's modified DAG library + luaConfig = genAttrs configNames (name: + entryAnywhere '' + ${fileContents "${name}.lua"} + ''); + in + luaConfig; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/editors/neovim/wrapper.nix b/nyx/homes/notashelf/programs/terminal/editors/neovim/wrapper.nix new file mode 100644 index 0000000..3964c96 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/editors/neovim/wrapper.nix @@ -0,0 +1,31 @@ +{ + config, + pkgs, + lib, + ... +}: { + xdg.desktopEntries."Neovim" = lib.mkForce { + name = "Neovim"; + type = "Application"; + mimeType = ["text/plain"]; + + icon = builtins.fetchurl { + url = "https://raw.githubusercontent.com/NotAShelf/neovim-flake/main/assets/neovim-flake-logo-work.svg"; + sha256 = "19n7n9xafyak35pkn4cww0s5db2cr97yz78w5ppbcp9jvxw6yyz3"; + }; + + exec = let + wezterm = lib.getExe config.programs.wezterm.package; + direnv = lib.getExe pkgs.direnv; + in "${pkgs.writeShellScript "wezterm-neovim" '' + # define target filename + filename="$(readlink -f "$1")" + + # get the directory target file is in + dirname="$(dirname "$filename")" + + # launch a wezterm instance with direnv and nvim + ${wezterm} -e --cwd "$dirname" -- ${lib.getExe pkgs.zsh} -c "${direnv} exec . nvim '$filename'" + ''} %f"; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/default.nix b/nyx/homes/notashelf/programs/terminal/emulators/default.nix new file mode 100644 index 0000000..1c6973c --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/default.nix @@ -0,0 +1,7 @@ +_: { + imports = [ + ./foot + ./kitty + ./wezterm + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/foot/default.nix b/nyx/homes/notashelf/programs/terminal/emulators/foot/default.nix new file mode 100644 index 0000000..c3e22a5 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/foot/default.nix @@ -0,0 +1,75 @@ +{ + osConfig, + lib, + config, + pkgs, + inputs', + ... +}: let + inherit (osConfig.modules.style.colorScheme) slug colors; + inherit (lib) mkIf; + + dev = osConfig.modules.device; + acceptedTypes = ["laptop" "desktop" "hybrid" "lite"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + home.packages = with pkgs; [ + libsixel # for displaying images + ]; + programs.foot = { + enable = true; + package = inputs'.nyxpkgs.packages.foot-transparent; + server.enable = true; + settings = { + main = { + # window settings + app-id = "foot"; + title = "foot"; + locked-title = "no"; + term = "xterm-256color"; + pad = "16x16 center"; + shell = "zsh"; + + # notifications + notify = "notify-send -a \${app-id} -i \${app-id} \${title} \${body}"; + selection-target = "clipboard"; + + # font and font rendering + dpi-aware = false; # this looks more readable on a laptop, but it's unreasonably large + font = "Iosevka Nerd Font:size=14"; + font-bold = "Iosevka Nerd Font:size=14"; + vertical-letter-offset = "-0.90"; + }; + + scrollback = { + lines = 10000; + multiplier = 3; + }; + + tweak = { + font-monospace-warn = "no"; # reduces startup time + sixel = "yes"; + }; + + cursor = { + style = "beam"; + beam-thickness = 2; + }; + + mouse = { + hide-when-typing = "yes"; + }; + + url = { + launch = "xdg-open \${url}"; + label-letters = "sadfjklewcmpgh"; + osc8-underline = "url-mode"; + protocols = "http, https, ftp, ftps, file"; + uri-characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,~:;/?#@!$&%*+=\"'()[]"; + }; + + colors = import ./presets/${slug}/colors.nix {inherit colors;} // {alpha = "0.85";}; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/foot/presets/catppuccin-mocha/colors.nix b/nyx/homes/notashelf/programs/terminal/emulators/foot/presets/catppuccin-mocha/colors.nix new file mode 100644 index 0000000..0aefb9a --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/foot/presets/catppuccin-mocha/colors.nix @@ -0,0 +1,22 @@ +{colors}: { + foreground = "${colors.base05}"; # Text + background = "${colors.base00}"; # Base + + regular0 = "${colors.base03}"; # Surface 1 + regular1 = "${colors.base08}"; # red + regular2 = "${colors.base0B}"; # green + regular3 = "${colors.base0A}"; # yellow + regular4 = "${colors.base0D}"; # blue + regular5 = "${colors.base0F}"; # pink + regular6 = "${colors.base0C}"; # teal + regular7 = "${colors.base06}"; # Subtext 0 + # Subtext 1 ??? + bright0 = "${colors.base04}"; # Surface 2 + bright1 = "${colors.base08}"; # red + bright2 = "${colors.base0B}"; # green + bright3 = "${colors.base0A}"; # yellow + bright4 = "${colors.base0D}"; # blue + bright5 = "${colors.base0F}"; # pink + bright6 = "${colors.base0C}"; # teal + bright7 = "${colors.base07}"; # Subtext 0 +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/foot/presets/oxocarbon-dark/colors.nix b/nyx/homes/notashelf/programs/terminal/emulators/foot/presets/oxocarbon-dark/colors.nix new file mode 100644 index 0000000..32daffa --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/foot/presets/oxocarbon-dark/colors.nix @@ -0,0 +1,21 @@ +{colors}: { + background = "${colors.base00}"; + foreground = "${colors.base06}"; + + regular0 = "${colors.base01}"; + regular1 = "${colors.base0C}"; + regular2 = "${colors.base0D}"; + regular3 = "${colors.base05}"; + regular4 = "${colors.base0B}"; + regular5 = "${colors.base0A}"; + regular6 = "${colors.base08}"; + regular7 = "${colors.base04}"; + bright0 = "${colors.base02}"; + bright1 = "${colors.base0C}"; + bright2 = "${colors.base0D}"; + bright3 = "${colors.base05}"; + bright4 = "${colors.base0B}"; + bright5 = "${colors.base0A}"; + bright6 = "${colors.base08}"; + bright7 = "${colors.base06}"; +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/kitty/default.nix b/nyx/homes/notashelf/programs/terminal/emulators/kitty/default.nix new file mode 100644 index 0000000..966668f --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/kitty/default.nix @@ -0,0 +1,57 @@ +{ + osConfig, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + inherit (modules.style.colorScheme) colors; + + dev = modules.device; + acceptedTypes = ["laptop" "desktop" "hybrid"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + programs.kitty = { + enable = true; + settings = import ./settings.nix {inherit colors;}; + keybindings = { + "ctrl+c" = "copy_or_interrupt"; + "ctrl+alt+c" = "copy_to_clipboard"; + "ctrl+alt+v" = "paste_from_clipboard"; + "ctrl+shift+v" = "paste_from_clipboard"; + + "ctrl+shift+up" = "increase_font_size"; + "ctrl+shift+down" = "decrease_font_size"; + "ctrl+shift+backspace" = "restore_font_size"; + + "ctrl+shift+enter" = "new_window"; + "ctrl+shift+n" = "new_os_window"; + "ctrl+shift+w" = "close_window"; + "ctrl+shift+]" = "next_window"; + "ctrl+shift+[" = "previous_window"; + "ctrl+shift+f" = "move_window_forward"; + "ctrl+shift+b" = "move_window_backward"; + "ctrl+shift+`" = "move_window_to_top"; + "ctrl+shift+1" = "first_window"; + "ctrl+shift+2" = "second_window"; + "ctrl+shift+3" = "third_window"; + "ctrl+shift+4" = "fourth_window"; + "ctrl+shift+5" = "fifth_window"; + "ctrl+shift+6" = "sixth_window"; + "ctrl+shift+7" = "seventh_window"; + "ctrl+shift+8" = "eighth_window"; + "ctrl+shift+9" = "ninth_window"; + "ctrl+shift+0" = "tenth_window"; + + "ctrl+shift+right" = "next_tab"; + "ctrl+shift+left" = "previous_tab"; + "ctrl+shift+t" = "new_tab"; + "ctrl+shift+q" = "close_tab"; + "ctrl+shift+l" = "next_layout"; + "ctrl+shift+." = "move_tab_forward"; + "ctrl+shift+," = "move_tab_backward"; + "ctrl+shift+alt+t" = "set_tab_title"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/kitty/settings.nix b/nyx/homes/notashelf/programs/terminal/emulators/kitty/settings.nix new file mode 100644 index 0000000..a9b869e --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/kitty/settings.nix @@ -0,0 +1,63 @@ +{colors, ...}: { + # General + background_opacity = "0.85"; + font_family = "monospace"; + font_size = 14; + disable_ligatures = "never"; + cursor_shape = "underline"; + cursor_blink_interval = "0.5"; + cursor_stop_blinking_after = "15.0"; + scrollback_lines = 10000; + click_interval = "0.5"; + select_by_word_characters = ":@-./_~?&=%+#"; + remember_window_size = false; + allow_remote_control = true; + initial_window_width = 640; + initial_window_height = 400; + repaint_delay = 15; + input_delay = 3; + visual_bell_duration = "0.0"; + url_style = "double"; + open_url_with = "default"; + confirm_os_window_close = 0; + enable_audio_bell = false; + window_padding_width = 15; + window_margin_width = 10; + + # Colorscheme + foreground = "#${colors.base05}"; + background = "#${colors.base00}"; + selection_background = "#${colors.base05}"; + selection_foreground = "#${colors.base00}"; + url_color = "#${colors.base04}"; + cursor = "#${colors.base05}"; + active_border_color = "#${colors.base03}"; + inactive_border_color = "#${colors.base01}"; + active_tab_background = "#${colors.base00}"; + active_tab_foreground = "#${colors.base05}"; + inactive_tab_background = "#${colors.base01}"; + inactive_tab_foreground = "#${colors.base04}"; + tab_bar_background = "#${colors.base01}"; + color0 = "#${colors.base00}"; + color1 = "#${colors.base08}"; + color2 = "#${colors.base0B}"; + color3 = "#${colors.base0A}"; + color4 = "#${colors.base0D}"; + color5 = "#${colors.base0E}"; + color6 = "#${colors.base0C}"; + color7 = "#${colors.base05}"; + color8 = "#${colors.base03}"; + color9 = "#${colors.base08}"; + color10 = "#${colors.base0B}"; + color11 = "#${colors.base0A}"; + color12 = "#${colors.base0D}"; + color13 = "#${colors.base0E}"; + color14 = "#${colors.base0C}"; + color15 = "#${colors.base07}"; + color16 = "#${colors.base09}"; + color17 = "#${colors.base0F}"; + color18 = "#${colors.base01}"; + color19 = "#${colors.base02}"; + color20 = "#${colors.base04}"; + color21 = "#${colors.base06}"; +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/wezterm/colorSchemes.nix b/nyx/homes/notashelf/programs/terminal/emulators/wezterm/colorSchemes.nix new file mode 100644 index 0000000..ff812d7 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/wezterm/colorSchemes.nix @@ -0,0 +1,71 @@ +{colors}: +with colors; { + followSystem = { + # basic colors + background = "#${base00}"; + foreground = "#${base05}"; + + cursor_border = "#${base05}"; + cursor_bg = "#${base05}"; + cursor_fg = "#${base08}"; + + selection_bg = "#${base0E}"; + selection_fg = "#${base00}"; + + split = "#${base01}"; + + # base16 + ansi = [ + "#${base03}" + "#${base08}" + "#${base0B}" + "#${base0A}" + "#${base0D}" + "#${base0F}" + "#${base0C}" + "#${base06}" + ]; + + brights = [ + "#${base04}" + "#${base08}" + "#${base0B}" + "#${base0A}" + "#${base0D}" + "#${base0F}" + "#${base0C}" + "#${base07}" + ]; + + # tabbar + tab_bar = { + background = "#${base08}"; + active_tab = { + bg_color = "#${base00}"; + fg_color = "#${base05}"; + }; + + inactive_tab = { + bg_color = "#${base08}"; + fg_color = "#${base05}"; + }; + + inactive_tab_hover = { + bg_color = "#${base00}"; + fg_color = "#${base05}"; + }; + + inactive_tab_edge = "#${base00}"; + + new_tab = { + bg_color = "#${base08}"; + fg_color = "#${base07}"; + }; + + new_tab_hover = { + bg_color = "#${base00}"; + fg_color = "#${base05}"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/emulators/wezterm/default.nix b/nyx/homes/notashelf/programs/terminal/emulators/wezterm/default.nix new file mode 100644 index 0000000..6db375b --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/emulators/wezterm/default.nix @@ -0,0 +1,77 @@ +{ + osConfig, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + inherit (modules.style.colorScheme) colors; + + dev = modules.device; + acceptedTypes = ["laptop" "desktop" "hybrid"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + programs.wezterm = { + enable = true; + package = pkgs.wezterm; + colorSchemes = import ./colorSchemes.nix {inherit colors;}; + extraConfig = '' + local wez = require("wezterm") + local act = wezterm.action + local baseConfig = { + -- general + check_for_updates = false, -- nix has updates covered, I don't care about updates + exit_behavior = "CloseOnCleanExit", + enable_scroll_bar = false, + audible_bell = "Disabled", -- annoying + warn_about_missing_glyphs = false, + + -- anims + animation_fps = 1, + + -- term window settings + adjust_window_size_when_changing_font_size = false, + window_background_opacity = 0.85, + window_padding = { left = 12, right = 12, top = 12, bottom = 12, }, + window_close_confirmation = "NeverPrompt", + inactive_pane_hsb = { + saturation = 1.0, + brightness = 0.8 + }, + + -- cursor + default_cursor_style = "SteadyBar", + cursor_blink_rate = 700, + cursor_blink_ease_in = 'Constant', + cursor_blink_ease_out = 'Constant', + + -- tab bar + enable_tab_bar = true, -- no observable performance impact + use_fancy_tab_bar = false, + hide_tab_bar_if_only_one_tab = true, + show_tab_index_in_tab_bar = false, + + -- font config + font_size = 14.0, + font = wezterm.font_with_fallback { + { family = "Iosevka Nerd Font", weight = "Regular" }, + { family = "Symbols Nerd Font", weight = "Regular" } + }, + + -- perf + front_end = "WebGpu", + enable_wayland = true, + scrollback_lines = 10000, + + -- colors + -- the followSystem theme is defined in colorSchemes.nix + -- as per my base16 theming options + color_scheme = "followSystem", + } + + return baseConfig + ''; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/bash.nix b/nyx/homes/notashelf/programs/terminal/shell/bash.nix new file mode 100644 index 0000000..77fa5f3 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bash.nix @@ -0,0 +1,22 @@ +{ + programs.bash = { + enable = false; + enableCompletion = true; + bashrcExtra = '' + set -o vi + bind -m vi-command 'Control-l: clear-screen' + bind -m vi-insert 'Control-l: clear-screen' + + bind 'set show-mode-in-prompt on' + bind 'set vi-cmd-mode-string "n "' + bind 'set vi-ins-mode-string "i "' + + # use ctrl-z to toggle in and out of bg + if [[ $- == *i* ]]; then + stty susp undef + bind -m vi-command 'Control-z: fg\015' + bind -m vi-insert 'Control-z: fg\015' + fi + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/compilec/compilec.sh b/nyx/homes/notashelf/programs/terminal/shell/bin/compilec/compilec.sh new file mode 100644 index 0000000..3ff4b66 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/compilec/compilec.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash + +# Function to compile and run a single .cpp file +function compile_and_run_file() { + filename="$1" + basename="''${filename%.*}" + + echo "Compiling $filename..." + + if g++ -o "$basename" "$filename"; then + echo "Running $basename..." + "./$basename" + else + echo "Compilation failed." + fi +} + +# Function to prompt user to choose a .cpp file using skim or fzf +function choose_cpp_file() { + directory="$1" + + if command -v skim >/dev/null 2>&1; then + file=$(find "$directory" -maxdepth 1 -type f -name "*.cpp" | skim --ansi --query "") + elif command -v fzf >/dev/null 2>&1; then + file=$(find "$directory" -maxdepth 1 -type f -name "*.cpp" | fzf) + else + echo "Error: skim or fzf is required for file selection." + exit 1 + fi + + if [ -n "$file" ]; then + compile_and_run_file "$file" + else + echo "No .cpp file selected." + fi +} + +# Function to prompt user to choose a .cpp file recursively using skim or fzf +function choose_cpp_file_recursive() { + directory="$1" + + if command -v skim >/dev/null 2>&1; then + file=$(find "$directory" -type f -name "*.cpp" | sk --ansi --query "") + elif command -v fzf >/dev/null 2>&1; then + file=$(find "$directory" -type f -name "*.cpp" | fzf) + else + echo "Error: skim or fzf is required for file selection." + exit 1 + fi + + if [ -n "$file" ]; then + compile_and_run_file "$file" + else + echo "No .cpp file selected." + fi +} + +# Help menu +function display_help() { + echo "Usage: $0 [options] " + echo "Options:" + echo " --recursive Look for .cpp files recursively" + echo " --help Display this help menu" + echo + echo "Examples:" + echo " $0 ~/Dev/test.cpp" + echo " $0 ~/Dev" + echo " $0 ~/Dev --recursive" +} + +# Parse command line arguments +recursive=false +directory="" + +# Check if --help is passed +if [[ $1 == "--help" ]]; then + display_help + exit 0 +fi + +while [[ $# -gt 0 ]]; do + case "$1" in + --recursive) + recursive=true + shift + ;; + *) + directory="$1" + shift + ;; + esac +done + +# Check if directory is provided +if [ -z "$directory" ]; then + echo "Error: No directory specified." + display_help + exit 1 +fi + +# Check if directory exists +if [ ! -d "$directory" ]; then + echo "Error: Directory does not exist." + display_help + exit 1 +fi + +# Compile and run or display help menu +if [ -f "$directory" ]; then + compile_and_run_file "$directory" +elif [ "$recursive" = true ]; then + choose_cpp_file_recursive "$directory" +else + choose_cpp_file "$directory" +fi diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/default.nix b/nyx/homes/notashelf/programs/terminal/shell/bin/default.nix new file mode 100644 index 0000000..902e728 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/default.nix @@ -0,0 +1,94 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) getExe; + inherit (builtins) readFile; +in { + home = { + # make sure the scripts linked below in the session PATH + # so that they can be referred to by name + sessionPath = ["${config.home.homeDirectory}/.local/bin"]; + + # link scripts to the local PATH + file = { + ".local/bin/preview" = { + # Preview script for fzf tab + source = getExe (pkgs.writeShellApplication { + name = "preview"; + runtimeInputs = with pkgs; [fzf eza catimg]; + text = readFile ./preview/preview.sh; + }); + }; + + ".local/bin/show-zombie-parents" = { + # Show zombie processes and their parents + source = getExe (pkgs.writeShellApplication { + name = "show-zombie-parents"; + runtimeInputs = with pkgs; [fzf eza catimg]; + text = readFile ./show-zombie-parents/show-zombie-parents.sh; + }); + }; + + ".local/bin/tzip" = { + # Find all latest .tmod files recursively in current directory and zip them + # for tmodloader mods downloaded via steam workshop + source = getExe (pkgs.writeShellApplication { + name = "tzip"; + runtimeInputs = with pkgs; [zip]; + text = readFile ./tzip/tzip.sh; + }); + }; + + ".local/bin/extract" = { + # Extract the compressed file with the correct tool based on the extension + source = getExe (pkgs.writeShellApplication { + name = "extract"; + runtimeInputs = with pkgs; [zip unzip gnutar p7zip]; + text = readFile ./extract/extract.sh; + }); + }; + + ".local/bin/compilec" = { + # Interactively find and compile C++ programs + source = getExe (pkgs.writeShellApplication { + name = "compilec"; + runtimeInputs = with pkgs; [skim coreutils gcc]; + text = readFile ./compilec/compilec.sh; + }); + }; + + ".local/bin/fs-diff" = { + # Show diff of two directories + source = getExe (pkgs.writeShellApplication { + name = "fs-diff"; + runtimeInputs = with pkgs; [coreutils gnused btrfs-progs]; + text = readFile ./fs-diff/fs-diff.sh; + }); + }; + + ".local/bin/purge-direnv" = { + # Purge all direnv links + source = getExe (pkgs.writeShellApplication { + name = "purge-direnv"; + runtimeInputs = with pkgs; [direnv]; + text = readFile ./purge-direnv/purge-direnv.sh; + }); + }; + + ".local/bin/addr" = { + # Get external IP address + source = getExe (pkgs.writeShellApplication { + name = "addr"; + runtimeInputs = with pkgs; [curl]; + text = '' + #!${pkgs.stdenv.shell} + exec curl "$@" icanhazip.com + ''; + }); + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/extract/extract.sh b/nyx/homes/notashelf/programs/terminal/shell/bin/extract/extract.sh new file mode 100644 index 0000000..e54e0de --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/extract/extract.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +SAVEIFS=$IFS +IFS="$(printf '\n\t')" + +function extract { + if [ $# -eq 0 ]; then + # display usage if no parameters given + echo "Usage: extract ." + echo " extract [path/file_name_2.ext] [path/file_name_3.ext]" + fi + for n in "$@"; do + if [ ! -f "$n" ]; then + echo "'$n' - file doesn't exist" + return 1 + fi + + case "''${n%,}" in + *.cbt | *.tar.bz2 | *.tar.gz | *.tar.xz | *.tbz2 | *.tgz | *.txz | *.tar) + tar zxvf "$n" + ;; + *.lzma) unlzma ./"$n" ;; + *.bz2) bunzip2 ./"$n" ;; + *.cbr | *.rar) unrar x -ad ./"$n" ;; + *.gz) gunzip ./"$n" ;; + *.cbz | *.epub | *.zip) unzip ./"$n" ;; + *.z) uncompress ./"$n" ;; + *.7z | *.apk | *.arj | *.cab | *.cb7 | *.chm | *.deb | *.iso | *.lzh | *.msi | *.pkg | *.rpm | *.udf | *.wim | *.xar | *.vhd) + 7z x ./"$n" + ;; + *.xz) unxz ./"$n" ;; + *.exe) cabextract ./"$n" ;; + *.cpio) cpio -id <./"$n" ;; + *.cba | *.ace) unace x ./"$n" ;; + *.zpaq) zpaq x ./"$n" ;; + *.arc) arc e ./"$n" ;; + *.cso) ciso 0 ./"$n" ./"$n.iso" && + extract "$n.iso" && \rm -f "$n" ;; + *.zlib) zlib-flate -uncompress <./"$n" >./"$n.tmp" && + mv ./"$n.tmp" ./"''${n%.*zlib}" && rm -f "$n" ;; + *.dmg) + hdiutil mount ./"$n" -mountpoint "./$n.mounted" + ;; + *) + echo "extract: '$n' - unknown archive method" + return 1 + ;; + esac + done +} + +IFS=$SAVEIFS diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/fs-diff/fs-diff.sh b/nyx/homes/notashelf/programs/terminal/shell/bin/fs-diff/fs-diff.sh new file mode 100644 index 0000000..67e5460 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/fs-diff/fs-diff.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) +OLD_TRANSID=${OLD_TRANSID#transid marker was } + +sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" | + sed '$d' | + cut -f17- -d' ' | + sort | + uniq | + while read -r path; do + path="/$path" + if [ -L "$path" ]; then + : # The path is a symbolic link, so is probably handled by NixOS already + elif [ -d "$path" ]; then + : # The path is a directory, ignore + else + echo "$path" + fi + done diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/preview/preview.sh b/nyx/homes/notashelf/programs/terminal/shell/bin/preview/preview.sh new file mode 100644 index 0000000..61a906b --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/preview/preview.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +case "$1" in +-*) exit 0 ;; +esac + +case "$(file --mime-type "$1")" in +*text*) + bat --color always --plain "$1" + ;; +*image* | *pdf) + catimg -w 100 -r 2 "$1" + ;; +*directory*) + eza --icons -1 --color=always "$1" + ;; +*) + echo "unknown file format" + ;; +esac diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/purge-direnv/purge-direnv.sh b/nyx/homes/notashelf/programs/terminal/shell/bin/purge-direnv/purge-direnv.sh new file mode 100644 index 0000000..e5fc482 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/purge-direnv/purge-direnv.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# find all .direnv directories +direnv_dirs=$(fd -I -a --hidden --type directory --glob '.direnv') + +# check if any directories were found +if [ -z "$direnv_dirs" ]; then + echo "No .direnv directories found." + exit 0 +fi + +# print report +echo "The following .direnv directories will be deleted:" +echo "$direnv_dirs" + +# confirm deletion +read -p "Are you sure you want to delete these directories? (y/n) " -n 1 -r + +# move to a new line +echo -en "\n" + +if [[ $REPLY =~ ^[Yy]$ ]]; then + # Delete directories + echo "Deleting directories..." + for dir in $direnv_dirs; do + rm -rf "$dir" + done + echo "Directories deleted." +else + echo "Operation cancelled." +fi diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/show-zombie-parents/show-zombie-parents.sh b/nyx/homes/notashelf/programs/terminal/shell/bin/show-zombie-parents/show-zombie-parents.sh new file mode 100644 index 0000000..0bf02a5 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/show-zombie-parents/show-zombie-parents.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +# https://www.linkedin.com/pulse/how-identify-kill-zombiedefunct-processes-linux-without-george-gabra/ +ps -A -ostat,ppid | grep -e '[zZ]' | awk '{ print $2 }' | uniq | xargs ps -p diff --git a/nyx/homes/notashelf/programs/terminal/shell/bin/tzip/tzip.sh b/nyx/homes/notashelf/programs/terminal/shell/bin/tzip/tzip.sh new file mode 100644 index 0000000..39e9861 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/bin/tzip/tzip.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +mkdir -p mods/ + +# Loop through each subdirectory in the current directory +for subdir in */; do + # Find the most recently accessed file with a .tmod extension in the subdirectory + latest_file=$(find "$subdir" -name "*.tmod" -type f -printf "%T@ %p\n" | sort -n | tail -1 | awk '{print $2}') + # Copy the latest file found (if any) to the mods/ directory + if [[ -n $latest_file ]]; then + cp "$latest_file" "mods/" + echo "Copied $latest_file to mods/" + else + echo "No .tmod files found in $subdir" + fi +done + +# Zip up the mods/ directory +zip -r mods.zip mods/ +echo -en "Zipped up mods/ directory to mods.zip" diff --git a/nyx/homes/notashelf/programs/terminal/shell/default.nix b/nyx/homes/notashelf/programs/terminal/shell/default.nix new file mode 100644 index 0000000..ea53ed6 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./bin + ./zsh + + ./starship.nix + ./bash.nix + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/starship.nix b/nyx/homes/notashelf/programs/terminal/shell/starship.nix new file mode 100644 index 0000000..8b00731 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/starship.nix @@ -0,0 +1,103 @@ +{ + config, + lib, + ... +}: let + inherit (builtins) map; + inherit (lib.strings) concatStrings; +in { + home = { + sessionVariables = { + STARSHIP_CACHE = "${config.xdg.cacheHome}/starship"; + }; + }; + + programs.starship = let + elemsConcatted = concatStrings ( + map (s: "\$${s}") [ + "hostname" + "username" + "directory" + "shell" + "nix_shell" + "git_branch" + "git_commit" + "git_state" + "git_status" + "jobs" + "cmd_duration" + ] + ); + in { + enable = true; + + settings = { + scan_timeout = 2; + command_timeout = 2000; # nixpkgs makes starship implode with lower values + add_newline = false; + line_break.disabled = false; + + format = "${elemsConcatted}\n$character"; + + hostname = { + ssh_only = true; + disabled = false; + format = "@[$hostname](bold blue) "; # the whitespace at the end is actually important + }; + + # configure specific elements + character = { + error_symbol = "[](bold red)"; + success_symbol = "[](bold green)"; + vicmd_symbol = "[](bold yellow)"; + format = "$symbol [|](bold bright-black) "; + }; + + username = { + format = "[$user]($style) in "; + }; + + directory = { + truncation_length = 2; + + # removes the read_only symbol from the format, it doesn't play nicely with my folder icon + format = "[ ](bold green) [$path]($style) "; + + # the following removes tildes from the path, and substitutes some folders with shorter names + substitutions = { + "~/Dev" = "Dev"; + "~/Documents" = "Docs"; + }; + }; + + # git + git_commit.commit_hash_length = 7; + git_branch.style = "bold purple"; + git_status = { + style = "red"; + ahead = "⇡ "; + behind = "⇣ "; + conflicted = " "; + renamed = "»"; + deleted = "✘ "; + diverged = "⇆ "; + modified = "!"; + stashed = "≡"; + staged = "+"; + untracked = "?"; + }; + + # language configurations + # the whitespaces at the end *are* necessary for proper formatting + lua.symbol = "[ ](blue) "; + python.symbol = "[ ](blue) "; + rust.symbol = "[ ](red) "; + nix_shell.symbol = "[󱄅 ](blue) "; + golang.symbol = "[󰟓 ](blue)"; + c.symbol = "[ ](black)"; + nodejs.symbol = "[󰎙 ](yellow)"; + + package.symbol = "📦 "; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/aliases.nix b/nyx/homes/notashelf/programs/terminal/shell/zsh/aliases.nix new file mode 100644 index 0000000..be518b8 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/aliases.nix @@ -0,0 +1,70 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib.meta) getExe getExe'; + inherit (pkgs) eza bat ripgrep du-dust procs yt-dlp python3 netcat-gnu; + + dig = getExe' pkgs.dnsutils "dig"; +in { + programs.zsh.shellAliases = { + # make sudo use aliases + sudo = "sudo "; + + # easy netcat alias for my fiche host + # https://github.com/solusipse/fiche + fbin = "${getExe netcat-gnu} p.frzn.dev 9999"; + + # nix specific aliases + cleanup = "sudo nix-collect-garbage --delete-older-than 3d && nix-collect-garbage -d"; + bloat = "nix path-info -Sh /run/current-system"; + curgen = "sudo nix-env --list-generations --profile /nix/var/nix/profiles/system"; + gc-check = "nix-store --gc --print-roots | egrep -v \"^(/nix/var|/run/\w+-system|\{memory|/proc)\""; + repair = "nix-store --verify --check-contents --repair"; + run = "nix run"; + search = "nix search"; + shell = "nix shell"; + build = "nix build $@ --builders \"\""; + + # quality of life aliases + cat = "${getExe bat} --style=plain"; + grep = "${getExe ripgrep}"; + du = "${getExe du-dust}"; + ps = "${getExe procs}"; + mp = "mkdir -p"; + fcd = "cd $(find -type d | fzf)"; + ls = "${getExe eza} -h --git --icons --color=auto --group-directories-first -s extension"; + l = "ls -lF --time-style=long-iso --icons"; + ytmp3 = '' + ${getExe yt-dlp} -x --continue --add-metadata --embed-thumbnail --audio-format mp3 --audio-quality 0 --metadata-from-title="%(artist)s - %(title)s" --prefer-ffmpeg -o "%(title)s.%(ext)s" + ''; + + # system aliases + sc = "sudo systemctl"; + jc = "sudo journalctl"; + scu = "systemctl --user "; + jcu = "journalctl --user"; + la = "${getExe eza} -lah --tree"; + tree = "${getExe eza} --tree --icons=always"; + http = "${getExe python3} -m http.server"; + burn = "pkill -9"; + diff = "diff --color=auto"; + killall = "pkill"; + switch-yubikey = "gpg-connect-agent \"scd serialno\" \"learn --force\" /bye"; + + # insteaed of querying some weird and random"what is my ip" service + # we get our public ip by querying opendns directly. + # + canihazip = "${dig} @resolver4.opendns.com myip.opendns.com +short"; + canihazip4 = "${dig} @resolver4.opendns.com myip.opendns.com +short -4"; + canihazip6 = "${dig} @resolver1.ipv6-sandbox.opendns.com AAAA myip.opendns.com +short -6"; + + # faster navigation + ".." = "cd .."; + "..." = "cd ../../"; + "...." = "cd ../../../"; + "....." = "cd ../../../../"; + "......" = "cd ../../../../../"; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/default.nix b/nyx/homes/notashelf/programs/terminal/shell/zsh/default.nix new file mode 100644 index 0000000..1898624 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/default.nix @@ -0,0 +1,53 @@ +{config, ...}: { + imports = [ + ./aliases.nix + ./init.nix + ./plugins.nix + ]; + + config = { + programs.zsh = { + enable = true; + dotDir = ".config/zsh"; + enableCompletion = true; + autosuggestion.enable = true; + syntaxHighlighting.enable = true; + sessionVariables = {LC_ALL = "en_US.UTF-8";}; + + history = { + # share history between different zsh sessions + share = true; + + # avoid cluttering $HOME with the histfile + path = "${config.xdg.dataHome}/zsh/zsh_history"; + + # saves timestamps to the histfile + extended = true; + + # optimize size of the histfile by avoiding duplicates + # or commands we don't need remembered + save = 100000; + size = 100000; + expireDuplicatesFirst = true; + ignoreDups = true; + ignoreSpace = true; + ignorePatterns = ["rm *" "pkill *" "kill *" "killall *"]; + }; + + # dirhashes are easy aliases to commonly used directoryies + # e.g. `cd ~dl` would take you to $HOME/Downloads + dirHashes = { + docs = "$HOME/Documents"; + dl = "$HOME/Downloads"; + media = "$HOME/Media"; + vids = "$HOME/Media/Videos"; + music = "$HOME/Media/Music"; + pics = "$HOME/Media/Pictures"; + screenshots = "$HOME/Media/Pictures/Screenshots"; + notes = "$HOME/Cloud/Notes"; + dev = "$HOME/Dev"; + dots = "$HOME/.config/nyx"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/init.nix b/nyx/homes/notashelf/programs/terminal/shell/zsh/init.nix new file mode 100644 index 0000000..ae054f7 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/init.nix @@ -0,0 +1,71 @@ +{ + osConfig, + lib, + ... +}: let + inherit (builtins) readFile; + inherit (lib.strings) fileContents; + inherit (osConfig.modules.style.colorScheme) colors; +in { + programs.zsh = { + completionInit = '' + ${readFile ./rc/comp.zsh} + ${readFile ./rc/fzf.zsh} + + # configure fzf tab options + export FZF_DEFAULT_OPTS=" + --color gutter:-1 + --color bg:-1 + --color bg+:-1 + --color fg:#${colors.base04} + --color fg+:#${colors.base06} + --color hl:#${colors.base0D} + --color hl+:#${colors.base0D} + --color header:#${colors.base0D} + --color info:#${colors.base0A} + --color marker:#${colors.base0C} + --color pointer:#${colors.base0C} + --color prompt:#${colors.base0A} + --color spinner:#${colors.base0C} + --color preview-bg:#${colors.base01} + --color preview-fg:#${colors.base0D} + --prompt ' ' + --pointer '' + --layout=reverse + -m --bind ctrl-space:toggle,pgup:preview-up,pgdn:preview-down + " + ''; + + initExtra = '' + # avoid duplicated entries in PATH + typeset -U PATH + + # try to correct the spelling of commands + setopt correct + # disable C-S/C-Q + setopt noflowcontrol + # disable "no matches found" check + unsetopt nomatch + + # my helper functions for setting zsh options that I normally use on my shell + # a description of each option can be found in the Zsh manual + # + # NOTE: this slows down shell startup time considerably + ${fileContents ./rc/unset.zsh} + ${fileContents ./rc/set.zsh} + + # binds, zsh modules and everything else + ${fileContents ./rc/binds.zsh} + ${fileContents ./rc/modules.zsh} + ${fileContents ./rc/misc.zsh} + ''; + + initExtraFirst = '' + # Do this early so fast-syntax-highlighting can wrap and override this + if autoload history-search-end; then + zle -N history-beginning-search-backward-end history-search-end + zle -N history-beginning-search-forward-end history-search-end + fi + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/plugins.nix b/nyx/homes/notashelf/programs/terminal/shell/zsh/plugins.nix new file mode 100644 index 0000000..fd08bf0 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/plugins.nix @@ -0,0 +1,35 @@ +{pkgs, ...}: let + inherit (pkgs) fetchFromGitHub; +in { + programs.zsh.plugins = [ + { + # Must be before plugins that wrap widgets, such as zsh-autosuggestions or fast-syntax-highlighting + name = "fzf-tab"; + src = "${pkgs.zsh-fzf-tab}/share/fzf-tab"; + } + { + name = "zsh-nix-shell"; + src = pkgs.zsh-nix-shell; + file = "share/zsh-nix-shell/nix-shell.plugin.zsh"; + } + { + name = "zsh-vi-mode"; + src = pkgs.zsh-vi-mode; + file = "share/zsh-vi-mode/zsh-vi-mode.plugin.zsh"; + } + { + name = "fast-syntax-highlighting"; + src = "${pkgs.zsh-fast-syntax-highlighting}/share/zsh/site-functions"; + } + { + name = "zsh-autopair"; + file = "zsh-autopair.plugin.zsh"; + src = fetchFromGitHub { + owner = "hlissner"; + repo = "zsh-autopair"; + rev = "2ec3fd3c9b950c01dbffbb2a4d191e1d34b8c58a"; + hash = "sha256-Y7fkpvCOC/lC2CHYui+6vOdNO8dNHGrVYTGGNf9qgdg="; + }; + } + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/binds.zsh b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/binds.zsh new file mode 100644 index 0000000..848c26d --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/binds.zsh @@ -0,0 +1,11 @@ +# Enable Vi mode +bindkey -v + +# Use vim keys in the tab complete menu +bindkey -M menuselect 'h' vi-backward-char +bindkey -M menuselect 'k' vi-up-line-or-history +bindkey -M menuselect 'l' vi-forward-char +bindkey -M menuselect 'j' vi-down-line-or-history + +bindkey "^A" vi-beginning-of-line +bindkey "^E" vi-end-of-line diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/comp.zsh b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/comp.zsh new file mode 100644 index 0000000..2b7d961 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/comp.zsh @@ -0,0 +1,95 @@ +# Completion +# autoload -U compinit +zstyle ':completion:*' menu select +zmodload zsh/complist +compinit -d "$XDG_CACHE_HOME"/zsh/zcompdump-"$ZSH_VERSION" +_comp_options+=(globdots) + +# Group matches and describe. +zstyle ':completion:*' sort false +zstyle ':completion:complete:*:options' sort false +zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*' +zstyle ':completion:*' special-dirs true +zstyle ':completion:*' rehash true + +# Sort completions +# disable sort when completing `git checkout` +zstyle ':completion:*:git-checkout:*' sort false +# set descriptions format to enable group support +zstyle ':completion:*:descriptions' format '[%d]' +# set list-colors to enable filename colorizing +zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS} +# preview directory's content when completing cd +zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls -lAhF --group-directories-first --show-control-chars --quoting-style=escape --color=always $realpath' +zstyle ':fzf-tab:complete:cd:*' popup-pad 20 0 +zstyle ':completion:*' file-sort modification +zstyle ':completion:*:eza' sort false +zstyle ':completion:files' sort false + +# Job IDs +zstyle ':completion:*:jobs' numbers true +zstyle ':completion:*:jobs' verbose true + +# Array completion element sorting. +zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters + +# Don't complete unavailable commands. +zstyle ':completion:*:functions' ignored-patterns '(_*|pre(cmd|exec))' + +# No correction +zstyle ':completion:*' completer _oldlist _expand _complete _files _ignored + +# Don't insert tabs when there is no completion (e.g. beginning of line) +zstyle ':completion:*' insert-tab false + +# allow one error for every three characters typed in approximate completer +zstyle ':completion:*:approximate:' max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )' + +# start menu completion only if it could find no unambiguous initial string +zstyle ':completion:*:correct:*' insert-unambiguous true +zstyle ':completion:*:corrections' format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}' +zstyle ':completion:*:correct:*' original true + +# List directory completions first +zstyle ':completion:*' list-dirs-first true +# Offer the original completion when using expanding / approximate completions +zstyle ':completion:*' original true +# Treat multiple slashes as a single / like UNIX does (instead of as /*/) +zstyle ':completion:*' squeeze-slashes true + +# insert all expansions for expand completer +# # ???????????????ßß +zstyle ':completion:*:expand:*' tag-order all-expansions + +# match uppercase from lowercase +zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' + +# separate matches into groups +zstyle ':completion:*:matches' group 'yes' +zstyle ':completion:*' group-name '' + +zstyle ':completion:*:messages' format '%d' +zstyle ':completion:*:options' auto-description '%d' + +# describe options in full +zstyle ':completion:*:options' description 'yes' + +# on processes completion complete all user processes +zstyle ':completion:*:processes' command 'ps -au$USER' + +# provide verbose completion information +zstyle ':completion:*' verbose true + +# Ignore completion functions for commands you don't have: +zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*' + +# Provide more processes in completion of programs like killall: +zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq' + +# complete manual by their section +zstyle ':completion:*:manuals' separate-sections true +zstyle ':completion:*:manuals.*' insert-sections true +zstyle ':completion:*:man:*' menu yes select + +# provide .. as a completion +zstyle ':completion:*' special-dirs .. diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/fzf.zsh b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/fzf.zsh new file mode 100644 index 0000000..e053581 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/fzf.zsh @@ -0,0 +1,73 @@ +autoload -U add-zle-hook-widget + +# autosuggests otherwise breaks these widgets. +# +ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(history-beginning-search-backward-end history-beginning-search-forward-end) + +# FZF widgets +function __fzf() { + if [[ -n "$TMUX_PANE" && ( "${FZF_TMUX:-0}" != 0 || -n "$FZF_TMUX_OPTS" ) ]]; then + fzf-tmux -d"${FZF_TMUX_HEIGHT:-40%}" -- "$@" + else + fzf "$@" + fi +} + +function __fzf_select() { + setopt localoptions pipefail no_aliases 2>/dev/null + local item + FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore,tab:down,btab:up,change:top,ctrl-space:toggle $FZF_DEFAULT_OPTS" __fzf "$@" | while read item; do + echo -n "${(q)item} " + done + local ret=$? + echo + return $ret +} + +function __fzf_find_files() { + local include_hidden=${1:-0} + local types=${2:-fdl} + shift 2 + local type_selectors=() + local i + for (( i=0; i<${#types}; i++ )); do + [[ "$i" -gt 0 ]] && type_selectors+=('-o') + type_selectors+=('-type' "${types:$i:1}") + done + local hide_hidden_files=() + if [[ $include_hidden == "0" ]]; then + hide_hidden_files=('-path' '*/\.*' '-o') + fi + setopt localoptions pipefail no_aliases 2>/dev/null + command find -L . -mindepth 1 \ + \( "${hide_hidden_files[@]}" -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \) -prune \ + -o \( "${type_selectors[@]}" \) -print \ + | __fzf_select "$@" +} + +function __fzf_find_files_widget_helper() { + LBUFFER="${LBUFFER}$(__fzf_find_files "$@")" + local ret=$? + zle reset-prompt + return $ret +} + +function fzf-select-file-or-dir() { __fzf_find_files_widget_helper 0 fdl -m; }; zle -N fzf-select-file-or-dir +function fzf-select-file-or-dir-hidden() { __fzf_find_files_widget_helper 1 fdl -m; }; zle -N fzf-select-file-or-dir-hidden +function fzf-select-dir() { __fzf_find_files_widget_helper 0 d -m; }; zle -N fzf-select-dir +function fzf-select-dir-hidden() { __fzf_find_files_widget_helper 1 d -m; }; zle -N fzf-select-dir-hidden +function fzf-cd() { + local dir="$(__fzf_find_files 0 d +m)" + if [[ -z "$dir" ]]; then + zle redisplay + return 0 + fi + zle push-line # Clear buffer. Auto-restored on next prompt. + BUFFER="cd -- $dir" + zle accept-line + local ret=$? + unset dir # ensure this doesn't end up appearing in prompt expansion + zle reset-prompt + return $ret +} +zle -N fzf-cd diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/misc.zsh b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/misc.zsh new file mode 100644 index 0000000..789184a --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/misc.zsh @@ -0,0 +1,22 @@ +# If this is an xterm set the title to user@host:dir +case "$TERM" in + xterm*|rxvt*|Eterm|aterm|kterm|gnome*|alacritty|kitty*) + TERM_TITLE=$'\e]0;%n@%m: %1~\a' + ;; + *) + ;; +esac + +# enable keyword-style arguments in shell functions +set -k + +# Colors +autoload -Uz colors && colors + +# Autosuggest +ZSH_AUTOSUGGEST_USE_ASYNC="true" + +# open commands in $EDITOR +autoload -z edit-command-line +zle -N edit-command-line +bindkey "^e" edit-command-line diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/modules.zsh b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/modules.zsh new file mode 100644 index 0000000..4dc8e8c --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/modules.zsh @@ -0,0 +1,8 @@ +# zsh Line Editor (ZLE) module +zmodload zsh/zle + +# zsh pseudo-terminal (PTY) module +zmodload zsh/zpty + +# zsh completion list (complist) module +zmodload zsh/complist diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/set.zsh b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/set.zsh new file mode 100644 index 0000000..c301ae0 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/set.zsh @@ -0,0 +1,31 @@ +# Define a function to set Zsh options +function set_zsh_options() { + local options=( + "AUTO_CD" # if not command, then directory + "AUTO_LIST" # list choices on ambiguous completion + "AUTO_MENU" # use menu completion after the second consecutive request for completion + "AUTO_PARAM_SLASH" # if parameter is completed whose content is the name of a directory, then add trailing slash instead of space + "AUTO_PUSHD" # make cd push the old directory onto the directory stack + "APPEND_HISTORY" # append history list to the history file, rather than replace it + "ALWAYS_TO_END" # cursor is moved to the end of the word after completion + "CORRECT" # try to correct the spelling of commands + "EXTENDED_HISTORY" # save each command’s beginning timestamp and the duration to the history file + "HIST_FCNTL_LOCK" # use system’s fcntl call to lock the history file + "HIST_REDUCE_BLANKS" # remove superfluous blanks + "HIST_SAVE_NO_DUPS" # older commands that duplicate newer ones are omitted + "HIST_VERIFY" # don’t execute the line directly; instead perform history expansion and reload the line into the editing buffer + "INC_APPEND_HISTORY" # new history lines are added to the $HISTFILE incrementally (as soon as they are entered) + "INTERACTIVE_COMMENTS" # allow comments even in interactive shells + "MENU_COMPLETE" # insert the first match immediately on ambiguous completion + "NO_NOMATCH" # not explained, probably disables NOMATCH lmao + "PUSHD_IGNORE_DUPS" # don’t push multiple copies of the same directory + "PUSHD_TO_HOME" # have pushd with no arguments act like `pushd $HOME` + "PUSHD_SILENT" # do not print the directory stack + ) + + for option in "${options[@]}"; do + setopt $option + done +} + +set_zsh_options diff --git a/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/unset.zsh b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/unset.zsh new file mode 100644 index 0000000..b718ad7 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/shell/zsh/rc/unset.zsh @@ -0,0 +1,14 @@ +# Define a function to unset Zsh options +function unset_zsh_options() { + local options=( + "CORRECT_ALL" # try to correct the spelling of all arguments in a line. + "HIST_BEEP" # beep in ZLE when a widget attempts to access a history entry which isn’t there + "SHARE_HISTORY" # read the documentation for more details + ) + + for option in "${options[@]}"; do + unsetopt $option + done +} + +unset_zsh_options diff --git a/nyx/homes/notashelf/programs/terminal/tools/bat.nix b/nyx/homes/notashelf/programs/terminal/tools/bat.nix new file mode 100644 index 0000000..e69672a --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/bat.nix @@ -0,0 +1,25 @@ +{pkgs, ...}: let + catppuccin = builtins.readFile (pkgs.fetchurl { + url = "https://raw.githubusercontent.com/catppuccin/bat/main/Catppuccin-mocha.tmTheme"; + hash = "sha256-qMQNJGZImmjrqzy7IiEkY5IhvPAMZpq0W6skLLsng/w="; + }); +in { + programs.bat = { + enable = true; + themes = { + Catppuccin-mocha = { + src = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "bat"; + rev = "ba4d16880d63e656acced2b7d4e034e4a93f74b1"; + sha256 = "sha256-6WVKQErGdaqb++oaXnY3i6/GuH2FhTgK0v4TN4Y0Wbw="; + }; + file = "Catppuccin-mocha.tmTheme"; + }; + }; + config = { + theme = "Catppuccin-mocha"; + pager = "less -FR"; # frfr + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/bottom.nix b/nyx/homes/notashelf/programs/terminal/tools/bottom.nix new file mode 100644 index 0000000..60b6bdc --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/bottom.nix @@ -0,0 +1,33 @@ +{pkgs, ...}: { + home.packages = with pkgs; [ + # replace top and htop with bottom + # if breaks shit? cope. + (writeScriptBin "htop" ''exec btm'') + (writeScriptBin "top" ''exec btm'') + ]; + programs.bottom = { + enable = true; + settings = { + flags.group_processes = true; + row = [ + { + ratio = 2; + child = [ + {type = "cpu";} + {type = "mem";} + ]; + } + { + ratio = 3; + child = [ + { + type = "proc"; + ratio = 1; + default = true; + } + ]; + } + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/default.nix b/nyx/homes/notashelf/programs/terminal/tools/default.nix new file mode 100644 index 0000000..473a9db --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/default.nix @@ -0,0 +1,29 @@ +{ + imports = [ + ./fastfetch + ./git + ./neomutt + ./newsboat + ./vifm + ./xplr + ./yazi + ./zellij + + ./bat.nix + ./bottom.nix + ./dircolors.nix + ./eza.nix + ./gh.nix + ./gpg.nix + ./man.nix + ./nix-index.nix + ./nix-init.nix + ./nix-shell.nix + ./ranger.nix + ./ssh.nix + ./tealdeer.nix + ./transient-services.nix + ./xdg.nix + ./zoxide.nix + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/dircolors.nix b/nyx/homes/notashelf/programs/terminal/tools/dircolors.nix new file mode 100644 index 0000000..ad790f9 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/dircolors.nix @@ -0,0 +1,10 @@ +{ + programs.dircolors = { + enable = true; + settings = { + OTHER_WRITABLE = "30;46"; + ".sh" = "01;32"; + ".csh" = "01;32"; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/eza.nix b/nyx/homes/notashelf/programs/terminal/tools/eza.nix new file mode 100644 index 0000000..2266f2d --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/eza.nix @@ -0,0 +1,12 @@ +{ + programs.eza = { + enable = true; + icons = true; + git = true; + enableZshIntegration = false; + extraOptions = [ + "--group-directories-first" + "--header" + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/fastfetch/default.nix b/nyx/homes/notashelf/programs/terminal/tools/fastfetch/default.nix new file mode 100644 index 0000000..f97700b --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/fastfetch/default.nix @@ -0,0 +1,61 @@ +{ + pkgs, + lib, + ... +}: { + config = { + home = { + packages = [pkgs.fastfetch]; + }; + + xdg.configFile."fastfetch/config.jsonc".text = builtins.toJSON { + "$schema" = "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json"; + logo = { + source = "nixos_small"; + padding = { + left = 1; + right = 3; + }; + }; + display = { + separator = " "; + keyWidth = 14; + }; + modules = [ + { + type = "os"; + key = " system "; + format = "{3}"; + } + { + type = "kernel"; + key = " kernel "; + format = "{1} {2} ({4})"; + } + { + type = "uptime"; + key = " uptime "; + } + { + type = "wm"; + key = " wm "; + } + { + type = "command"; + key = "󰆧 packages"; + text = "(${lib.getExe' pkgs.nix "nix-store"} --query --requisites /run/current-system | wc -l | tr -d '\n') && echo ' (nix; /run/current-system)'"; + } + { + type = "memory"; + key = "󰍛 memory "; + } + { + type = "disk"; + key = "󱥎 storage "; + format = "{1} / {2} ({3})"; + folders = "/"; + } + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/gh.nix b/nyx/homes/notashelf/programs/terminal/tools/gh.nix new file mode 100644 index 0000000..4d375cd --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/gh.nix @@ -0,0 +1,16 @@ +{pkgs, ...}: { + programs.gh = { + enable = true; + gitCredentialHelper.enable = false; + extensions = with pkgs; [ + gh-dash # dashboard with pull requests and issues + gh-eco # explore the ecosystem + gh-cal # contributions calender terminal viewer + gh-poi # clean up local branches safely + ]; + settings = { + git_protocol = "ssh"; + prompt = "enabled"; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/git/aliases.nix b/nyx/homes/notashelf/programs/terminal/tools/git/aliases.nix new file mode 100644 index 0000000..3708c0f --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/git/aliases.nix @@ -0,0 +1,23 @@ +{ + programs.git.aliases = { + br = "branch"; + c = "commit -m"; + ca = "commit -am"; + co = "checkout"; + d = "diff"; + df = "!git hist | peco | awk '{print $2}' | xargs -I {} git diff {}^ {}"; + edit-unmerged = "!f() { git ls-files --unmerged | cut -f2 | sort -u ; }; vim `f`"; + fuck = "commit --amend -m"; + graph = "log --all --decorate --graph"; + ps = "!git push origin $(git rev-parse --abbrev-ref HEAD)"; + pl = "!git pull origin $(git rev-parse --abbrev-ref HEAD)"; + af = "!git add $(git ls-files -m -o --exclude-standard | fzf -m)"; + st = "status"; + hist = '' + log --pretty=format:"%Cgreen%h %Creset%cd %Cblue[%cn] %Creset%s%C(yellow)%d%C(reset)" --graph --date=relative --decorate --all + ''; + llog = '' + log --graph --name-status --pretty=format:"%C(red)%h %C(reset)(%cd) %C(green)%an %Creset%s %C(yellow)%d%Creset" --date=relative + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/git/default.nix b/nyx/homes/notashelf/programs/terminal/tools/git/default.nix new file mode 100644 index 0000000..677a375 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/git/default.nix @@ -0,0 +1,111 @@ +{ + osConfig, + pkgs, + ... +}: let + inherit (osConfig) modules; + cfg = modules.system.programs.git; +in { + imports = [ + ./aliases.nix + ./ignore.nix + ]; + + config = { + home.packages = with pkgs; [ + gist # manage github gists + act # local github actions + zsh-forgit # zsh plugin to load forgit via `git forgit` + gitflow + ]; + + programs.git = { + enable = true; + package = pkgs.gitAndTools.gitFull; + + # my credientals + userName = "NotAShelf"; + userEmail = "raf@notashelf.dev"; + + # lets sign using our own key + # this must be provided by the host + signing = { + key = cfg.signingKey; + signByDefault = true; + }; + + lfs = { + enable = true; + skipSmudge = true; + }; + + extraConfig = { + # I don't care about the usage of the term "master" + # but main is easier to type, so that's that + init.defaultBranch = "main"; + + # disable the horrendous GUI password prompt for Git when auth fails + core.askPass = ""; + + # prefer using libsecret for storing and retrieving credientals + credential.helper = "${pkgs.gitAndTools.gitFull}/bin/git-credential-libsecret"; + + # delta is some kind of a syntax highlighting pager for git + # it looks nice but I'd like to consider difftastic at some point + delta = { + enable = true; + line-numbers = true; + features = "decorations side-by-side navigate"; + options = { + navigate = true; + line-numbers = true; + side-by-side = true; + dark = true; + }; + }; + + branch.autosetupmerge = "true"; + pull.ff = "only"; + + push = { + default = "current"; + followTags = true; + autoSetupRemote = true; + }; + + merge = { + stat = "true"; + conflictstyle = "diff3"; + }; + + core.whitespace = "fix,-indent-with-non-tab,trailing-space,cr-at-eol"; + color.ui = "auto"; + + repack.usedeltabaseoffset = "true"; + + rebase = { + autoSquash = true; + autoStash = true; + }; + + rerere = { + autoupdate = true; + enabled = true; + }; + + url = { + "https://github.com/".insteadOf = "github:"; + "ssh://git@github.com/".pushInsteadOf = "github:"; + "https://gitlab.com/".insteadOf = "gitlab:"; + "ssh://git@gitlab.com/".pushInsteadOf = "gitlab:"; + "https://aur.archlinux.org/".insteadOf = "aur:"; + "ssh://aur@aur.archlinux.org/".pushInsteadOf = "aur:"; + "https://git.sr.ht/".insteadOf = "srht:"; + "ssh://git@git.sr.ht/".pushInsteadOf = "srht:"; + "https://codeberg.org/".insteadOf = "codeberg:"; + "ssh://git@codeberg.org/".pushInsteadOf = "codeberg:"; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/git/ignore.nix b/nyx/homes/notashelf/programs/terminal/tools/git/ignore.nix new file mode 100644 index 0000000..bcf8785 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/git/ignore.nix @@ -0,0 +1,53 @@ +{lib, ...}: let + general = '' + .cache/ + tmp/ + *.tmp + log/ + ''; + + ide = '' + *.swp + .idea/ + .~lock* + ''; + + c = '' + .tags + tags + *~ + *.o + *.so + *.cmake + CMakeCache.txt + CMakeFiles/ + cmake-build-debug/ + compile_commands.json + .ccls* + ''; + + nix = '' + result + result-* + .direnv/ + ''; + + node = '' + node_modules/ + ''; + + python = '' + venv + .venv + *pyc + *.egg-info/ + __pycached__/ + .mypy_cache + ''; + + ignore = lib.concatStringsSep "\n" [general c nix node ide python]; +in { + # construct the list of ignored files from a very large string containing + # the list of ignored files, but in a plaintext format for my own convenience + programs.git.ignores = map (v: "${toString v}") (builtins.split "\n" ignore); +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/gpg.nix b/nyx/homes/notashelf/programs/terminal/tools/gpg.nix new file mode 100644 index 0000000..3135f97 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/gpg.nix @@ -0,0 +1,81 @@ +{ + osConfig, + config, + pkgs, + lib, + ... +}: let + sys = osConfig.modules.system; + + pinentryPkg = + if sys.video.enable + then pkgs.pinentry-gnome3 # requires services.dbus.packages = [ pkgs.gcr ] + else pkgs.pinentry-curses; +in { + services = { + gpg-agent = { + enable = true; + pinentryPackage = pinentryPkg; + enableSshSupport = true; + defaultCacheTtl = 1209600; + defaultCacheTtlSsh = 1209600; + maxCacheTtl = 1209600; + maxCacheTtlSsh = 1209600; + extraConfig = "allow-preset-passphrase"; + enableZshIntegration = true; + }; + }; + + # Allow manually restarting gpg-agent in case of failure + systemd.user.services.gpg-agent.Unit.RefuseManualStart = lib.mkForce false; + + programs = { + gpg = { + enable = true; + homedir = "${config.xdg.dataHome}/gnupg"; + settings = { + keyserver = "keys.openpgp.org"; + # https://github.com/drduh/config/blob/master/gpg.conf + # https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html + # https://www.gnupg.org/documentation/manuals/gnupg/GPG-Esoteric-Options.html + # Use AES256, 192, or 128 as cipher + personal-cipher-preferences = "AES256 AES192 AES"; + # Use SHA512, 384, or 256 as digest + personal-digest-preferences = "SHA512 SHA384 SHA256"; + # Use ZLIB, BZIP2, ZIP, or no compression + personal-compress-preferences = "ZLIB BZIP2 ZIP Uncompressed"; + # Default preferences for new keys + default-preference-list = "SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed"; + # SHA512 as digest to sign keys + cert-digest-algo = "SHA512"; + # SHA512 as digest for symmetric ops + s2k-digest-algo = "SHA512"; + # AES256 as cipher for symmetric ops + s2k-cipher-algo = "AES256"; + # UTF-8 support for compatibility + charset = "utf-8"; + # Show Unix timestamps + fixed-list-mode = ""; + # No comments in signature + no-comments = ""; + # No version in signature + no-emit-version = ""; + # Disable banner + no-greeting = ""; + # Long hexidecimal key format + keyid-format = "0xlong"; + # Display UID validity + list-options = "show-uid-validity"; + verify-options = "show-uid-validity"; + # Display all keys and their fingerprints + with-fingerprint = ""; + # Cross-certify subkeys are present and valid + require-cross-certification = ""; + # Disable caching of passphrase for symmetrical ops + no-symkey-cache = ""; + # Enable smartcard + use-agent = ""; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/man.nix b/nyx/homes/notashelf/programs/terminal/tools/man.nix new file mode 100644 index 0000000..d95251d --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/man.nix @@ -0,0 +1,6 @@ +{ + programs.man = { + enable = true; + generateCaches = true; # slows down rebuilds + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/neomutt/binds.nix b/nyx/homes/notashelf/programs/terminal/tools/neomutt/binds.nix new file mode 100644 index 0000000..4ea29a8 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/neomutt/binds.nix @@ -0,0 +1,53 @@ +{ + binds = [ + { + # Reply to a group or mailing list. + action = "group-reply"; + key = "R"; + map = [ + "index" + "pager" + ]; + } + + { + # Move to the previous box in the sidebar. + action = "sidebar-prev"; + key = "\\cK"; + map = [ + "index" + "pager" + ]; + } + + { + # Move to the next box in the sidebar. + action = "sidebar-next"; + key = "\\cJ"; + map = [ + "index" + "pager" + ]; + } + + { + # Open the current box highlighted in the sidebar. + action = "sidebar-open"; + key = "\\cO"; + map = [ + "index" + "pager" + ]; + } + + { + # View the raw contents of a message. + action = "view-raw-message"; + key = "Z"; + map = [ + "index" + "pager" + ]; + } + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/neomutt/colors.nix b/nyx/homes/notashelf/programs/terminal/tools/neomutt/colors.nix new file mode 100644 index 0000000..17ead14 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/neomutt/colors.nix @@ -0,0 +1,77 @@ +# vim: filetype=nix +{pkgs, ...}: { + muttColors = pkgs.writeTextFile { + name = "muttColors"; + text = '' + # vim: filetype=muttrc + # Header colors: + color header blue default ".*" + color header brightmagenta default "^(From)" + color header brightcyan default "^(Subject)" + color header brightwhite default "^(CC|BCC)" + + mono bold bold + mono underline underline + mono indicator reverse + mono error bold + color normal default default + color indicator brightyellow default # currently selected message. default makes bar clear, disabled arrow to save space. + color sidebar_highlight red default + color sidebar_divider brightblack black + color sidebar_flagged red black + color sidebar_new green black + color normal brightyellow default + color error red default + color tilde black default + color message cyan default + color markers red white + color attachment white default + color search brightmagenta default + color status brightyellow black + color hdrdefault brightgreen default + color quoted green default + color quoted1 blue default + color quoted2 cyan default + color quoted3 yellow default + color quoted4 red default + color quoted5 brightred default + color signature brightgreen default + color bold black default + color underline black default + color normal default default + + color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses + color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL + color body green default "\`[^\`]*\`" # Green text between ` and ` + color body brightblue default "^# \.*" # Headings as bold blue + color body brightcyan default "^## \.*" # Subheadings as bold cyan + color body brightgreen default "^### \.*" # Subsubheadings as bold green + color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow + color body brightcyan default "[;:][-o][)/(|]" # emoticons + color body brightcyan default "[;:][)(|]" # emoticons + color body brightcyan default "[ ][*][^*]*[*][ ]?" # more emoticon? + color body brightcyan default "[ ]?[*][^*]*[*][ ]" # more emoticon? + color body red default "(BAD signature)" + color body cyan default "(Good signature)" + color body brightblack default "^gpg: Good signature .*" + color body brightyellow default "^gpg: " + color body brightyellow red "^gpg: BAD signature from.*" + mono body bold "^gpg: Good signature" + mohttps://neomutt.org/code/config_vars.htmlno body bold "^gpg: BAD signature from.*" + color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]" + + # Default index colors: + color index yellow default '.*' + color index_author red default '.*' + color index_number blue default + color index_subject cyan default '.*' + + # For new mail: + color index brightyellow black "~N" + color index_author brightred black "~N" + color index_subject brightcyan black "~N" + + color progress black cyan + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/neomutt/default.nix b/nyx/homes/notashelf/programs/terminal/tools/neomutt/default.nix new file mode 100644 index 0000000..3330c01 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/neomutt/default.nix @@ -0,0 +1,74 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mapAttrsToList flatten concatStringsSep; +in { + config = { + programs.neomutt = { + enable = true; + vimKeys = true; + checkStatsInterval = 60; + + # sidebar + sidebar = { + enable = true; + width = 30; + format = "%D%?F? [%F]?%* %?N?%N/?%S"; + }; + + # sort default view by threads + sort = "threads"; + + # get keybinds from their respective file + inherit (import ./binds.nix) binds; + + # get settings from their respective file + inherit (import ./settings.nix {inherit config;}) settings; + + # get macros from their respective file + inherit (import ./macros.nix) macros; + + extraConfig = let + # collect all addresses and aliases from accounts.email.accounts attribute of home-manager + accounts = mapAttrsToList (_: value: [value.address] ++ value.aliases) config.accounts.email.accounts; + addresses = flatten accounts; + in '' + # add collected accounts to neomutt config + alternates "${concatStringsSep "|" addresses}" + + # mark anything marked by SpamAssassin as probably spam + spam "X-Spam-Score: ([0-9\\.]+).*" "SA: %1" + + # only show the basic mail headers + ignore * + unignore From To Cc Bcc Date Subject + + # show headers in the following order + unhdr_order * + hdr_order From: To: Cc: Bcc: Date: Subject: + + ''; + }; + + xdg = { + desktopEntries = { + neomutt = { + name = "Neomutt"; + genericName = "Email Client"; + comment = "Read and send emails"; + exec = "neomutt %U"; + icon = "neomutt"; + terminal = true; + categories = ["Network" "Email" "ConsoleOnly"]; + type = "Application"; + mimeType = ["x-scheme-handler/mailto"]; + }; + }; + mimeApps.defaultApplications = { + "x-scheme-handler/mailto" = "neomutt.desktop"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/neomutt/macros.nix b/nyx/homes/notashelf/programs/terminal/tools/neomutt/macros.nix new file mode 100644 index 0000000..1606f28 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/neomutt/macros.nix @@ -0,0 +1,15 @@ +{ + macros = [ + { + # toggle the sidebar's visibility and refresh/redraw the screen + action = "toggle sidebar_visible"; + key = "B"; + map = ["index"]; + } + { + action = "toggle sidebar_visible"; + key = "B"; + map = ["pager"]; + } + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/neomutt/settings.nix b/nyx/homes/notashelf/programs/terminal/tools/neomutt/settings.nix new file mode 100644 index 0000000..41c2241 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/neomutt/settings.nix @@ -0,0 +1,92 @@ +{config}: { + settings = { + # if the given mail doesn't have an explicit charset, assume an old + # and Windows-y compatible charset as fallback + assumed_charset = "iso-8859-1"; + + # use gpgme for cryptography + crypt_use_gpgme = "yes"; + + # use PKA to find keys via DNS records and possibly check whether an email + # address is controlled by who it says it is + crypt_use_pka = "yes"; + + # always try to verify signatures + crypt_verify_sig = "yes"; + + # ask to purge messages marked for delete when closing/syncing a box, with + # the default to do so + delete = "ask-yes"; + + # when editing outgoing mail, allow editing the headers too + edit_headers = "yes"; + + # the format to use for subjects when forwarding messages + forward_format = "\"Fwd: %s\""; + + # save 10_000 lines of string buffer history per category + history = "10000"; + + # save history to a file in neomutt's directory + history_file = "${config.xdg.configHome}/neomutt/history"; + + # when connecting via IMAP, add all subscribed folders from the server + imap_check_subscribed = "yes"; + + # keep IMAP connections alive with a keepalive every 5 minutes + imap_keepalive = "300"; + + # use a smaller IMAP pipeline to play nice with servers like GMail + imap_pipeline_depth = "5"; + + # check for new mail every minute + mail_check = "60"; + + # the path to the mailcap file + mailcap_path = "${config.home.homeDirectory}/.mailcap"; + + # use Maildir-style mailboxes + mbox_type = "Maildir"; + + # scroll menus and such by a single line, rather than a whole page + menu_scroll = "yes"; + + # show five lines of context when moving between pages in the pager + pager_context = "5"; + + # the format for the pager status line. + pager_format = "\" %C - %[%H:%M] %.20v, %s%* %?H? [%H] ?\""; + + # when in the mail pager, show 10 lines of the index above the current + # message + pager_index_lines = "10"; + + # don't move to the next message when reaching the bottom of a message + pager_stop = "yes"; + + # reply to mail using the same address the original was sent to + reverse_name = "yes"; + + # send all mail as UTF-8 + send_charset = "utf-8"; + + # sort the mailboxes in the sidebar by mailbox path + sidebar_sort_method = "path"; + + # sort by last message date if messages are in the same thread + sort_aux = "last-date-received"; + + # separate matching spam headers with this separator + spam_separator = ", "; + + # only group messages as a thread by the In-Reply-To or References headers + # rather than matching subject names + strict_threads = "yes"; + + # search messages against their decoded contents + thorough_search = "yes"; + + # pad blank lines at the bottom of the screen with tildes + tilde = "yes"; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/newsboat/default.nix b/nyx/homes/notashelf/programs/terminal/tools/newsboat/default.nix new file mode 100644 index 0000000..c6df610 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/newsboat/default.nix @@ -0,0 +1,83 @@ +{ + config, + pkgs, + lib, + osConfig, + ... +}: let + inherit (lib) mkIf getExe; + + mpv = "${getExe pkgs.mpv}"; + glow = "${getExe pkgs.glow}"; + pandoc = "${getExe pkgs.pandoc}"; + + dev = osConfig.modules.device; + acceptedTypes = ["laptop" "desktop" "hybrid" "lite"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + programs.newsboat = { + enable = true; + autoReload = true; + + inherit ((import ./urls.nix)) urls; + + extraConfig = '' + error-log /dev/null + + download-full-page yes + download-retries 3 + cookie-cache ~/.cache/newsboat/cookies.txt + + auto-reload yes + max-items 0 + scrolloff 999 + reload-threads 100 + + bind-key j down + bind-key k up + bind-key j next articlelist + bind-key k prev articlelist + bind-key J next-feed articlelist + bind-key K prev-feed articlelist + bind-key G end + bind-key g home + bind-key d pagedown + bind-key u pageup + bind-key l open + bind-key h quit + bind-key a toggle-article-read + bind-key n next-unread + bind-key N prev-unread + bind-key D pb-download + bind-key U show-urls + bind-key x pb-delete + + color listnormal color15 default + color listnormal_unread color2 default + color listfocus_unread color2 color0 + color listfocus default color0 + color background default default + color article default default + color end-of-text-marker color8 default + color info color4 color8 + color hint-separator default color8 + color hint-description default color8 + color title color14 color8 + + highlight article "^(Feed|Title|Author|Link|Date): .+" color4 default bold + highlight article "^(Feed|Title|Author|Link|Date):" color14 default bold + highlight article "\\((link|image|video)\\)" color8 default + highlight article "https?://[^ ]+" color4 default + highlight article "\[[0-9]+\]" color6 default bold + user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" + + html-renderer "${pandoc} --from=html -t markdown_github-raw_html" + pager "${glow} --pager --width 72" + + # macros + macro v set browser "${mpv} %u" ; open-in-browser ; set browser "firefox %u" -- "Open video on mpv" + macro , open-in-browser + ''; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/newsboat/urls.nix b/nyx/homes/notashelf/programs/terminal/tools/newsboat/urls.nix new file mode 100644 index 0000000..0b93e3c --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/newsboat/urls.nix @@ -0,0 +1,59 @@ +{ + urls = [ + # Weekly NixOS news and some other stuff + { + title = "NixOS Weekly"; + tags = ["news" "twitter"]; + url = "https://weekly.nixos.org/feeds/all.rss.xml"; + } + # https://hackaday.com/blog/feed/ + { + title = "Hacker News"; + url = "https://hnrss.org/newest"; + tags = ["tech"]; + } + { + title = "Hacker News Daily"; + url = "https://www.daemonology.net/hn-daily/index.rss"; + tags = ["tech"]; + } + # Reddit + { + title = "/r/neovim"; + url = "https://www.reddit.com/r/neovim/.rss"; + tags = ["neovim" "reddit"]; + } + { + title = "/r/unixporn"; + url = "https://www.reddit.com/r/unixporn/.rss"; + tags = ["unix" "ricing" "style"]; + } + # Computerphile + { + title = "Computerphile"; + url = "https://www.youtube.com/feeds/videos.xml?channel_id=UC9-y-6csu5WGm29I7JiwpnA"; + tags = ["tech" "youtube"]; + } + # Security news + { + title = "Krebson Security"; + url = "https://krebsonsecurity.com/feed/"; + tags = ["tech" "security"]; + } + + # Unsorted + {url = "https://nitter.net/GergelyOrosz/rss";} + {url = "https://feeds.feedburner.com/ThePragmaticEngineer";} + {url = "https://www.reddit.com/r/ExperiencedDevs/.rss";} + {url = "https://news.ycombinator.com/rss";} + {url = "https://programming.dev/feeds/local.xml?sort=Active";} + {url = "https://programming.dev/feeds/c/functional_programming.xml?sort=Active";} + {url = "https://programming.dev/feeds/c/linux.xml?sort=Active";} + {url = "https://programming.dev/feeds/c/experienced_devs.xml?sort=Active";} + {url = "https://programming.dev/feeds/c/nix.xml?sort=Active";} + {url = "https://programming.dev/feeds/c/commandline.xml?sort=Active";} + {url = "https://beehaw.org/feeds/c/technology.xml?sort=Active";} + {url = "https://lobste.rs/rss";} + {url = "https://kiszamolo.hu/feed";} + ]; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/nix-index.nix b/nyx/homes/notashelf/programs/terminal/tools/nix-index.nix new file mode 100644 index 0000000..b7b7545 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/nix-index.nix @@ -0,0 +1,21 @@ +{inputs, ...}: { + imports = [inputs.nix-index-db.hmModules.nix-index]; + + config = { + home.sessionVariables = { + # auto-run programs using nix-index-database + NIX_AUTO_RUN = "1"; + }; + + programs = { + nix-index-database.comma.enable = true; + + nix-index = { + enable = true; + + # link nix-inde database to ~/.cache/nix-index + symlinkToCacheHome = true; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/nix-init.nix b/nyx/homes/notashelf/programs/terminal/tools/nix-init.nix new file mode 100644 index 0000000..e315eeb --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/nix-init.nix @@ -0,0 +1,12 @@ +{pkgs, ...}: let + toTOML = name: (pkgs.formats.toml {}).generate "${name}"; +in { + config = { + home.packages = [pkgs.nix-init]; + + xdg.configFile."nix-init/config.toml".source = toTOML "config.toml" { + commit = true; + maintainers = ["NotAShelf"]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/nix-shell.nix b/nyx/homes/notashelf/programs/terminal/tools/nix-shell.nix new file mode 100644 index 0000000..8e47ebd --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/nix-shell.nix @@ -0,0 +1,8 @@ +{pkgs, ...}: { + home = { + packages = with pkgs; [ + alejandra + nix-tree + ]; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/ranger.nix b/nyx/homes/notashelf/programs/terminal/tools/ranger.nix new file mode 100644 index 0000000..3c729b9 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/ranger.nix @@ -0,0 +1,24 @@ +{ + pkgs, + lib, + osConfig, + config, + ... +}: let + device = osConfig.modules.device; + # TODO: maybe not have a TUI file manager on desktops, when GUI does it better + acceptedTypes = ["laptop" "desktop" "hybrid" "server" "lite"]; + inherit (lib.strings) optionalString; +in { + config = lib.mkIf (builtins.elem device.type acceptedTypes) { + home.packages = with pkgs; [ + ranger + ]; + + # TODO: more file preview methods + xdg.configFile."ranger/rc.conf".text = '' + set preview_images true + ${(optionalString config.programs.kitty.enable "set preview_images_method kitty")} + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/ssh.nix b/nyx/homes/notashelf/programs/terminal/tools/ssh.nix new file mode 100644 index 0000000..e52be5d --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/ssh.nix @@ -0,0 +1,68 @@ +{ + programs = { + ssh = { + enable = true; + hashKnownHosts = true; + compression = true; + matchBlocks = let + commonIdFile = "~/.ssh/id_ed25519"; + in { + "aur" = { + hostname = "aur.archlinux.org"; + identityFile = "~/.ssh/aur"; + }; + + "builder" = { + hostname = "build.neushore.dev"; + user = "builder"; + identityFile = "~/.ssh/builder"; + port = 30; + }; + + "helios" = { + port = 30; + }; + + "enyo" = { + port = 30; + }; + + "hermes" = { + port = 30; + }; + + "epimetheus" = { + port = 30; + }; + + "icarus" = { + port = 30; + }; + + "nix-builder" = { + hostname = "helios"; + user = "nix-builder"; + identityFile = "~/.ssh/builder"; + }; + + "frozendev" = { + hostname = "frzn.dev"; + user = "raf"; + identityFile = "~/.ssh/id_rsa"; + }; + + "github" = { + hostname = "github.com"; + identityFile = "~/.ssh/github_rsa"; + }; + + "neushore" = { + hostname = "ssh.neushore.dev"; + user = "raf"; + identityFile = "~/.ssh/neushore"; + port = 30; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/tealdeer.nix b/nyx/homes/notashelf/programs/terminal/tools/tealdeer.nix new file mode 100644 index 0000000..d610a02 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/tealdeer.nix @@ -0,0 +1,17 @@ +{ + programs = { + tealdeer = { + enable = false; + settings = { + display = { + compact = false; + use_pager = true; + }; + + updates = { + auto_update = false; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/transient-services.nix b/nyx/homes/notashelf/programs/terminal/tools/transient-services.nix new file mode 100644 index 0000000..2fe1b97 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/transient-services.nix @@ -0,0 +1,37 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.strings) optionalString concatStringsSep; + inherit (lib.attrsets) mapAttrsToList; + + sessionPath = optionalString (config.home.sessionPath != []) '' + export PATH=${concatStringsSep ":" config.home.sessionPath}:$PATH + ''; + + sessionVariables = concatStringsSep "\n" (mapAttrsToList (key: value: '' + export ${key}="${toString value}" + '') + config.home.sessionVariables); + + apply-hm-env = pkgs.writeShellScript "apply-hm-env" '' + ${sessionPath} + ${sessionVariables} + ${config.home.sessionVariablesExtra} + exec "$@" + ''; + + # runs processes as systemd transient services + run-as-service = pkgs.writeShellScriptBin "run-as-service" '' + exec ${pkgs.systemd}/bin/systemd-run \ + --slice=app-manual.slice \ + --property=ExitType=cgroup \ + --user \ + --wait \ + bash -lc "exec ${apply-hm-env} $@" + ''; +in { + home.packages = [run-as-service]; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/colors/.gitkeep b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/colors/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/colors/.gitkeep @@ -0,0 +1 @@ + diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/abbr.vifm b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/abbr.vifm new file mode 100644 index 0000000..3949c55 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/abbr.vifm @@ -0,0 +1,4 @@ +" vim:ft=vim +cabbrev t touch +cabbrev mk mkdir + diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/commands.vifm b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/commands.vifm new file mode 100644 index 0000000..1704428 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/commands.vifm @@ -0,0 +1,26 @@ +" vim:ft=vim +" :com[mand][!] command_name action +" The following macros can be used in a command +" %a is replaced with the user arguments. +" %c the current file under the cursor. +" %C the current file under the cursor in the other directory. +" %f the current selected file, or files. +" %F the current selected file, or files in the other directory. +" %b same as %f %F. +" %d the current directory name. +" %D the other window directory name. +" %m run the command in a menu window +" more information: https://vifm.info/vimdoc.shtml#vifm-macros + +command! df df -h %m 2> /dev/null +command! diff nvim -d %f %F +command! run !! ./%f +command! make !!make %a +command! mkcd :mkdir %a | cd %a +command! vgrep vim "+grep %a" +command! reload :write | restart +command! dragon dragon-drop -a -x %f +command! clear vifmimg clear +command! print lp -n 1 -o sides=two-sided-long-edge %f +command! sudoedit sudoedit %c + diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/favicons.vifm b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/favicons.vifm new file mode 100644 index 0000000..76b4d3b --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/favicons.vifm @@ -0,0 +1,70 @@ +" vim:ft=vim + +" Filetypes/directories +set classify=' :dir:/, :exe:, :reg:, :link:,? :?:, ::../::' + +" Specific files +set classify+=' ::.Xdefaults,,.Xresources,,.bashprofile,,.bash_profile,,.bashrc,,.dmrc,,.d_store,,.fasd,,.gitconfig,,.gitignore,,.jack-settings,,.mime.types,,.nvidia-settings-rc,,.pam_environment,,.profile,,.recently-used,,.selected_editor,,.xinitpurc,,.zprofile,,.yarnc,,.snclirc,,.tmux.conf,,.urlview,,.config,,.ini,,.user-dirs.dirs,,.mimeapps.list,,.offlineimaprc,,.msmtprc,,.Xauthority,,config::' +set classify+=' ::dropbox::' +set classify+=' ::favicon.*,,README,,readme::' +set classify+=' ::.vim,,.vimrc,,.gvimrc,,.vifm::' +set classify+=' ::gruntfile.coffee,,gruntfile.js,,gruntfile.ls::' +set classify+=' ::gulpfile.coffee,,gulpfile.js,,gulpfile.ls::' +set classify+=' ::ledger::' +set classify+=' ::license,,copyright,,copying,,LICENSE,,COPYRIGHT,,COPYING::' +set classify+=' ::node_modules::' +set classify+=' ::react.jsx::' + +" File extensions +set classify+='λ ::*.ml,,*.mli::' +set classify+=' ::*.styl::' +set classify+=' ::*.scss::' +set classify+=' ::*.py,,*.pyc,,*.pyd,,*.pyo::' +set classify+=' ::*.php::' +set classify+=' ::*.markdown,,*.md::' +set classify+=' ::*.json::' +set classify+=' ::*.js::' +set classify+=' ::*.bmp,,*.gif,,*.ico,,*.jpeg,,*.jpg,,*.png,,*.svg,,*.svgz,,*.tga,,*.tiff,,*.xmb,,*.xcf,,*.xpm,,*.xspf,,*.xwd,,*.cr2,,*.dng,,*.3fr,,*.ari,,*.arw,,*.bay,,*.crw,,*.cr3,,*.cap,,*.data,,*.dcs,,*.dcr,,*drf,,*.eip,,*.erf,,*.fff,,*.gpr,,*.iiq,,*.k25,,*.kdc,,*.mdc,,.*mef,,*.mos,,.*.mrw,,.*.obm,,*.orf,,*.pef,,*.ptx,,*.pxn,,*.r3d,,*.raf,,*.raw,,*.rwl,,*.rw2,,*.rwz,,*.sr2,,*.srf,,*.srf,,*.srw,,*.tif,,*.x3f::' +set classify+=' ::*.ejs,,*.htm,,*.html,,*.slim,,*.xml::' +set classify+=' ::*.mustasche::' +set classify+=' ::*.css,,*.less,,*.bat,,*.conf,,*.ini,,*.rc,,*.yml,,*.cfg,,*.rc::' +set classify+=' ::*.rss::' +set classify+=' ::*.coffee::' +set classify+=' ::*.twig::' +set classify+=' ::*.c++,,*.cc,,*.cpp,,*.cxx,,*.h::' +set classify+=' ::*.c::' +set classify+=' ::*.hs,,*.lhs::' +set classify+=' ::*.lua::' +set classify+=' ::*.jl::' +set classify+=' ::*.go::' +set classify+=' ::*.ts::' +set classify+=' ::*.db,,*.dump,,*.sql::' +set classify+=' ::*.sln,,*.suo::' +set classify+=' ::*.exe::' +set classify+=' ::*.diff,,*.sum,,*.md5,,*.sha512::' +set classify+=' ::*.scala::' +set classify+=' ::*.java,,*.jar::' +set classify+=' ::*.xul::' +set classify+=' ::*.clj,,*.cljc::' +set classify+=' ::*.pl,,*.pm,,*.t::' +set classify+=' ::*.cljs,,*.edn::' +set classify+=' ::*.rb::' +set classify+=' ::*.fish,,*.sh,,*.bash::' +set classify+=' ::*.dart::' +set classify+=' ::*.f#,,*.fs,,*.fsi,,*.fsscript,,*.fsx::' +set classify+=' ::*.rlib,,*.rs::' +set classify+=' ::*.d::' +set classify+=' ::*.erl,,*.hrl::' +set classify+=' ::*.ai::' +set classify+=' ::*.psb,,*.psd::' +set classify+=' ::*.jsx::' +set classify+=' ::*.aac,,*.anx,,*.asf,,*.au,,*.axa,,*.flac,,*.m2a,,*.m4a,,*.mid,,*.midi,,*.mp3,,*.mpc,,*.oga,,*.ogg,,*.ogx,,*.ra,,*.ram,,*.rm,,*.spx,,*.wav,,*.wma,,*.ac3::' +set classify+=' ::*.avi,,*.flv,,*.mkv,,*.mov,,*.mov,,*.mp4,,*.mpeg,,*.mpg,,*.webm::' +set classify+=' ::*.epub,,*.pdf,,*.fb2,,*.djvu::' +set classify+=' ::*.7z,,*.apk,,*.bz2,,*.cab,,*.cpio,,*.deb,,*.gem,,*.gz,,*.gzip,,*.lh,,*.lzh,,*.lzma,,*.rar,,*.rpm,,*.tar,,*.tgz,,*.xz,,*.zip::' +set classify+=' ::*.cbr,,*.cbz::' +set classify+=' ::*.log::' +set classify+=' ::*.doc,,*.docx,,*.adoc::' +set classify+=' ::*.xls,,*.xls,,*.xlsmx::' +set classify+=' ::*.pptx,,*.ppt::' + diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/ft.vifm b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/ft.vifm new file mode 100644 index 0000000..3d2a2d1 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/ft.vifm @@ -0,0 +1,136 @@ +" vim:ft=vim +" filextype: What should it do (which program should it use), when you want to open it +" fileviewer: What should it do for the prievew? + +filextype *.pdf zathura %c & + +filextype *.ps,*.eps,*.ps.gz + \ {View in sioyek} + \ sioyek %f & + +filextype *.xml,*.ipe ipe %c & + +filextype *.djvu + \ {View in sioyek} + \ sioyek %f & , + \ {View in apvlv} + \ apvlv %f, + +filetype *.wav,*.mp3,*.flac,*.m4a,*.wma,*.ape,*.ac3,*.og[agx],*.spx,*.opus,*.MOD + \ {Play using ffplay} + \ ffplay -nodisp -autoexit %c &, + \ {Play using MPlayer} + \ mplayer %f &, +fileviewer *.mp3 mp3info +fileviewer *.flac soxi + +filextype *.avi,*.mp4,*.wmv,*.3gp,*.ogv,*.mkv,*.mpg,*.mpeg,*.vob, + \*.fl[icv],*.m2v,*.mov,*.webm,*.mts,*.m4v,*.r[am],*.qt,*.divx, + \*.as[fx] + \ {View using ffplay} + \ ffplay -fs -autoexit -volume 100 %f &, + +filextype *.html,*.htm + \ firefox %f &, +filetype *.html,*.htm links, lynx +fileviewer *.html + \ w3m %c + +filetype *.o,*.out objdump -d %f | less +fileviewer *.o,*.out objdump -d %f + +filetype *.[1-8] man ./%c +fileviewer *.[1-8] man ./%c | col -b + +filextype *.bmp,*.jpg,*.jpeg,*.png,*.xpm,*.svg,*.ico,*.gif + "\ viewnior %c & + " \ vimiv --log-level info --debug vimico %c & + \ vimiv %c & + +filextype *.ora + \ {Edit in MyPaint} + \ mypaint %f, + +filextype *.vym + \ {Open with VYM} + \ vym %f &, + +filetype *.md5 + \ {Check MD5 hash sum} + \ md5sum -c %f %S, + +filetype *.sha1 + \ {Check SHA1 hash sum} + \ sha1sum -c %f %S, + +filetype *.sha256 + \ {Check SHA256 hash sum} + \ sha256sum -c %f %S, + +filetype *.sha512 + \ {Check SHA512 hash sum} + \ sha512sum -c %f %S, + +filetype *.asc + \ {Check signature} + \ !!gpg --verify %c, + +filetype *.torrent ktorrent %f & +fileviewer *.torrent dumptorrent -v %c + +filetype *.zip,*.jar,*.war,*.ear,*.oxt,*.apkg + \ {Mount with fuse-zip} + \ FUSE_MOUNT|fuse-zip %SOURCE_FILE %DESTINATION_DIR, + \ {View contents} + \ zip -sf %c | less, + \ {Extract here} + \ tar -xf %c +filetype *.zip unzip %f +filetype *.tar.gz tar -xvf %f +fileviewer *.zip,*.jar,*.war,*.ear,*.oxt zip -sf %c + +filetype *.tar,*.tar.bz2,*.tbz2,*.tgz,*.tar.gz,*.tar.xz,*.txz + \ {Mount with archivemount} + \ FUSE_MOUNT|archivemount %SOURCE_FILE %DESTINATION_DIR, +fileviewer *.tgz,*.tar.gz tar -tzf %c +fileviewer *.tar.bz2,*.tbz2 tar -tjf %c +fileviewer *.tar.txz,*.txz xz --list %c +fileviewer *.tar tar -tf %c + +filetype *.rar + \ {Mount with rar2fs} + \ FUSE_MOUNT|rar2fs %SOURCE_FILE %DESTINATION_DIR, +fileviewer *.rar unrar v %c + +filetype *.iso + \ {Mount with fuseiso} + \ FUSE_MOUNT|fuseiso %SOURCE_FILE %DESTINATION_DIR, + +filetype *.ssh + \ {Mount with sshfs} + \ FUSE_MOUNT2|sshfs %PARAM %DESTINATION_DIR %FOREGROUND, + +filetype *.ftp + \ {Mount with curlftpfs} + \ FUSE_MOUNT2|curlftpfs -o ftp_port=-,,disable_eprt %PARAM %DESTINATION_DIR %FOREGROUND, + +filetype *.7z + \ {Mount with fuse-7z} + \ FUSE_MOUNT|fuse-7z %SOURCE_FILE %DESTINATION_DIR, +fileviewer *.7z 7z l %c + +filextype *.odt,*.doc,*.docx,*.xls,*.xlsx,*.odp,*.pptx libreoffice %f & +fileviewer *.odt odt2txt %f +fileviewer *.docx docx2txt %f - + +filetype *.tudu tudu -f %c + +filextype *.pro qtcreator %f & + +filextype */ + \ pacmanfm %f &, + +fileviewer *.md glow %c + +filetype *.xopp xournalpp %f & + diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/fv.vifm b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/fv.vifm new file mode 100644 index 0000000..969a9ea --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/fv.vifm @@ -0,0 +1,3 @@ +" vim:ft=vim + +fileviewer *.* bat --color=always --decorations=never %c diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/mappings.vifm b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/mappings.vifm new file mode 100644 index 0000000..42c1ae9 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/settings/mappings.vifm @@ -0,0 +1,38 @@ +" vim:ft=vim + +" Editing / Do something with the files +nnoremap cd :cd +nnoremap cD :diff +vnoremap cD :diff + +" start shell +nmap S :shell + +" Display sorting dialog +nnoremap s :sort + +" preview window +" Toggle visibility of preview window +nnoremap w :view +vnoremap w :viewgv + +" panel resize +nnoremap < 5< +nnoremap > 5> + +" tabs +nnoremap :tabnew + +" drag and drop +nmap :dragon +vmap :dragon + +" Yank current directory path into the clipboard +nnoremap yd :!echo -n %d | wl-copy %i:echo expand('%"d') "is yanked to clipboard" +" Yank current file path into the clipboard +nnoremap yf :!echo -n %c:p | wl-copy %i:echo expand('%"c:p') "is yanked to clipboard" + +nnoremap q :q + +"nnoremap ö q + diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/config/vifmrc b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/vifmrc new file mode 100644 index 0000000..c190ae5 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/config/vifmrc @@ -0,0 +1,114 @@ +" vim:ft=vim + +" editor +set vicmd="nvim" + +" This makes vifm perform file operations on its own instead of relying on +" standard utilities like `cp`. While using `cp` and alike is a more universal +" solution, it's also much slower when processing large amounts of files and +" doesn't support progress measuring. +set syscalls + +" miller view +set millerview +set milleroptions="lsize:1,csize:2,rsize:0,rpreview:all" + +set sizefmt=units:si,precision:2,space + +" The display on the bottom left +set rulerformat="%2l/%2S %[MAX: %2L%]" + +set findprg="fd %A" +set grepprg="rg -n -H %i %a %s" + +" set fillchars=vborder:│ + +" execute files +set runexec + +set tuioptions="pu" + +" controls details of file operations +set iooptions=fastfilecloning + +" Trash Directory +" The default is to move files that are deleted with dd or :d to +" the trash directory. If you change this you will not be able to move +" files by deleting them and then using p to put the file in the new location. +" I recommend not changing this until you are familiar with vifm. +" This probably shouldn't be an option. +set trash +set trashdir="~/.local/share/Trash/files" + +" This is how many directories to store in the directory history. +set history=100 + +" number of spaces of a tab" +set tabstop=4 + +" With this option turned on you can run partially entered commands with +" unambiguous beginning using :! (e.g. :!Te instead of :!Terminal or :!Te). +set fastrun + +" Natural sort of (version) numbers within text. +set sortnumbers + +" Maximum number of changes that can be undone. +set undolevels=100 + +" If you installed the vim.txt help file set vimhelp. +" If would rather use a plain text help file set novimhelp. +set vimhelp + +" If you would like to run an executable file when you +" press return on the file name set this. +set norunexec + +set rnu +set dotdirs= + +" colorscheme custom + +" Format for displaying time in file list. For example: +" TIME_STAMP_FORMAT=%m/%d-%H:%M +" See man date or man strftime for details. +set timefmt=%d.%m.%Y\ \ %H:%M + +" Show list of matches on tab completion in command-line mode +set wildmenu +" Display completions in a form of popup with descriptions of the matches +set wildstyle=popup + +" Display suggestions in normal, visual and view modes for keys, marks and +" registers (at most 5 files). In other view, when available. +set suggestoptions=normal,visual,view,otherpane,keys,marks,registers,delay:0 + +" Ignore case in search patterns unless it contains at least one uppercase +" letter +set ignorecase +set smartcase + +" Don't highlight search results automatically +set nohlsearch + +" Use increment searching (search while typing) +set incsearch + +" Try to leave some space from cursor to upper/lower border in lists +set scrolloff=4 + +" Don't do too many requests to slow file systems +if !has('win') + set slowfs=curlftpfs +endif + +set statusline=" %A %10u:%-7g %20d Free Space: %a" + +set vifminfo=dhistory,chistory,state,tui,shistory, + \phistory,fhistory,dirstack,registers,bookmarks,bmarks + +" ------------ +" panels +" ------------ +set viewcolumns=-{name},{size} + diff --git a/nyx/homes/notashelf/programs/terminal/tools/vifm/default.nix b/nyx/homes/notashelf/programs/terminal/tools/vifm/default.nix new file mode 100644 index 0000000..054c260 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/vifm/default.nix @@ -0,0 +1,22 @@ +{ + self, + pkgs, + ... +}: { + imports = [self.homeManagerModules.vifm]; + config = { + programs.vifm = { + enable = true; + package = pkgs.vifm-full; + config = builtins.readFile "${./config/vifmrc}"; + extraConfigFiles = [ + "${./config/settings/abbr.vifm}" + "${./config/settings/commands.vifm}" + "${./config/settings/favicons.vifm}" + "${./config/settings/ft.vifm}" + "${./config/settings/fv.vifm}" + "${./config/settings/mappings.vifm}" + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/xdg.nix b/nyx/homes/notashelf/programs/terminal/tools/xdg.nix new file mode 100644 index 0000000..6c8119c --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/xdg.nix @@ -0,0 +1,82 @@ +{ + config, + pkgs, + lib, + ... +}: let + browser = ["Schizofox.desktop"]; + mailer = ["thunderbird.desktop"]; + zathura = ["org.pwmt.zathura.desktop.desktop"]; + fileManager = ["org.kde.dolphin.desktop"]; + + associations = { + "text/html" = browser; + "x-scheme-handler/http" = browser; + "x-scheme-handler/https" = browser; + "x-scheme-handler/ftp" = browser; + "x-scheme-handler/about" = browser; + "x-scheme-handler/unknown" = browser; + "application/x-extension-htm" = browser; + "application/x-extension-html" = browser; + "application/x-extension-shtml" = browser; + "application/xhtml+xml" = browser; + "application/x-extension-xhtml" = browser; + "application/x-extension-xht" = browser; + + "inode/directory" = fileManager; + "application/x-xz-compressed-tar" = ["org.kde.ark.desktop"]; + + "audio/*" = ["mpv.desktop"]; + "video/*" = ["mpv.dekstop"]; + "image/*" = ["imv.desktop"]; + "application/json" = browser; + "application/pdf" = zathura; + "x-scheme-handler/tg" = ["telegramdesktop.desktop"]; + "x-scheme-handler/spotify" = ["spotify.desktop"]; + "x-scheme-handler/discord" = ["WebCord.desktop"]; + "x-scheme-handler/mailto" = mailer; + }; + + template = import lib.xdgTemplate "home-manager"; +in { + #home.sessionVariables = template.sysEnv; + xdg = { + enable = true; + cacheHome = "${config.home.homeDirectory}/.cache"; + configHome = "${config.home.homeDirectory}/.config"; + dataHome = "${config.home.homeDirectory}/.local/share"; + stateHome = "${config.home.homeDirectory}/.local/state"; + + configFile = { + "npm/npmrc" = template.npmrc; + "python/pythonrc" = template.pythonrc; + }; + + userDirs = { + enable = pkgs.stdenv.isLinux; + createDirectories = true; + + download = "${config.home.homeDirectory}/Downloads"; + desktop = "${config.home.homeDirectory}/Desktop"; + documents = "${config.home.homeDirectory}/Documents"; + + publicShare = "${config.home.homeDirectory}/.local/share/public"; + templates = "${config.home.homeDirectory}/.local/share/templates"; + + music = "${config.home.homeDirectory}/Media/Music"; + pictures = "${config.home.homeDirectory}/Media/Pictures"; + videos = "${config.home.homeDirectory}/Media/Videos"; + + extraConfig = { + XDG_SCREENSHOTS_DIR = "${config.xdg.userDirs.pictures}/Screenshots"; + XDG_MAIL_DIR = "${config.home.homeDirectory}/Mail"; + }; + }; + + mimeApps = { + enable = true; + associations.added = associations; + defaultApplications = associations; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/xplr/default.nix b/nyx/homes/notashelf/programs/terminal/tools/xplr/default.nix new file mode 100644 index 0000000..c218127 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/xplr/default.nix @@ -0,0 +1,57 @@ +{ + pkgs, + lib, + osConfig, + ... +}: let + device = osConfig.modules.device; + acceptedTypes = ["laptop" "desktop" "hybrid" "server" "lite"]; +in { + config = lib.mkIf (builtins.elem device.type acceptedTypes) { + home.packages = with pkgs; [ + xplr + ]; + + xdg.configFile."xplr/init.lua".text = let + # get plugin derivations from plugins.nix so that this file remains clean + inherit (import ./plugins.nix pkgs) wl-clipboard-plugin nuke-plugin; + in '' + version = '${pkgs.xplr.version}' + + package.path = + "${wl-clipboard-plugin}/init.lua;" .. + "${nuke-plugin}/init.lua;" .. + package.path + + + require("wl-clipboard").setup{ + copy_command = "wl-copy -t text/uri-list", + paste_command = "wl-paste", + keep_selection = true, + } + + require("nuke").setup{ + pager = "less -R", + open = { + run_executables = true, -- default: false + custom = { + {extension = "jpg", command = "imv {}"}, + {extension = "pdf", command = "zathura {}"}, + {mime_regex = "^video/.*", command = "mpv {}"}, + {mime_regex = ".*", command = "xdg-open {}"} + } + }, + + view = { + show_line_numbers = true, -- default: false + }, + + smart_view = { + custom = { + {extension = "so", command = "ldd -r {} | less"}, + }, + } + } + ''; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/xplr/plugins.nix b/nyx/homes/notashelf/programs/terminal/tools/xplr/plugins.nix new file mode 100644 index 0000000..8a7687f --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/xplr/plugins.nix @@ -0,0 +1,14 @@ +pkgs: { + wl-clipboard-plugin = pkgs.fetchFromGitHub { + owner = "sayanarijit"; + repo = "wl-clipboard.xplr"; + rev = "a3ffc87460c5c7f560bffea689487ae14b36d9c3"; + hash = "sha256-I4rh5Zks9hiXozBiPDuRdHwW5I7ppzEpQNtirY0Lcks="; + }; + nuke-plugin = pkgs.fetchFromGitHub { + owner = "Junker"; + repo = "nuke.xplr"; + rev = "f83a7ed58a7212771b15fbf1fdfb0a07b23c81e9"; + hash = "sha256-k/yre9SYNPYBM2W1DPpL6Ypt3w3EMO9dznHwa+fw/n0="; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/yazi/default.nix b/nyx/homes/notashelf/programs/terminal/tools/yazi/default.nix new file mode 100644 index 0000000..d61ccb5 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/yazi/default.nix @@ -0,0 +1,40 @@ +{ + config, + pkgs, + ... +}: { + imports = [ + ./theme/icons.nix + ./theme/manager.nix + ./theme/status.nix + ]; + + home.packages = [pkgs.exiftool]; + + programs.yazi = { + enable = true; + + enableBashIntegration = config.programs.bash.enable; + enableZshIntegration = config.programs.zsh.enable; + + settings = { + manager = { + layout = [1 4 3]; + sort_by = "alphabetical"; + sort_sensitive = true; + sort_reverse = false; + sort_dir_first = true; + linemode = "none"; + show_hidden = false; + show_symlink = true; + }; + + preview = { + tab_size = 2; + max_width = 600; + max_height = 900; + cache_dir = "${config.xdg.cacheHome}/yazi"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/icons.nix b/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/icons.nix new file mode 100644 index 0000000..987527a --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/icons.nix @@ -0,0 +1,146 @@ +{ + programs.yazi.theme.icons = { + # Default + "*" = ""; + "*/" = "󰉋"; + + # Home + ".config/" = ""; + ".ssh/" = "󰢬"; + "Desktop/" = ""; + "Development/" = ""; + "Documents/" = ""; + "Downloads/" = "󰉍"; + "Library/" = ""; + "Movies/" = ""; + "Music/" = "󱍙"; + "Pictures/" = "󰉏"; + "Videos/" = ""; + "Public/" = ""; + + # Git + ".git/" = ""; + ".gitignore" = ""; + ".gitmodules" = ""; + ".gitattributes" = ""; + + # Dotfiles + ".DS_Store" = ""; + ".bashrc" = ""; + ".bashprofile" = ""; + ".zshrc" = ""; + ".zshenv" = ""; + ".zprofile" = ""; + ".vimrc" = ""; + + # Text + "*.txt" = ""; + "*.md" = ""; + "*.rst" = ""; + COPYING = "󰿃"; + LICENSE = "󰿃"; + + # Archives + "*.zip" = ""; + "*.tar" = ""; + "*.gz" = ""; + "*.7z" = ""; + "*.bz2" = ""; + "*.xz" = ""; + + # Documents + "*.csv" = ""; + "*.doc" = ""; + "*.doct" = ""; + "*.docx" = ""; + "*.dot" = ""; + "*.ods" = ""; + "*.ots" = ""; + "*.pdf" = ""; + "*.pom" = ""; + "*.pot" = ""; + "*.ppm" = ""; + "*.pps" = ""; + "*.ppt" = ""; + "*.potx" = ""; + "*.ppmx" = ""; + "*.ppsx" = ""; + "*.pptx" = ""; + "*.xlc" = ""; + "*.xlm" = ""; + "*.xls" = ""; + "*.xlt" = ""; + "*.xlsm" = ""; + "*.xlsx" = ""; + + # Audio + "*.mp3" = ""; + "*.flac" = ""; + "*.wav" = ""; + "*.aac" = ""; + "*.ogg" = ""; + "*.m4a" = ""; + "*.mp2" = ""; + + # Movies + "*.mp4" = ""; + "*.mkv" = ""; + "*.avi" = ""; + "*.mov" = ""; + "*.webm" = ""; + + # Images + "*.jpg" = ""; + "*.jpeg" = ""; + "*.png" = ""; + "*.gif" = ""; + "*.webp" = ""; + "*.avif" = ""; + "*.bmp" = ""; + "*.ico" = ""; + "*.svg" = ""; + "*.xcf" = ""; + "*.HEIC" = ""; + + # Programming + "*.c" = ""; + "*.cpp" = ""; + "*.h" = ""; + "*.hpp" = ""; + "*.rs" = ""; + "*.go" = ""; + "*.py" = ""; + "*.hs" = ""; + "*.js" = ""; + "*.ts" = ""; + "*.tsx" = ""; + "*.jsx" = ""; + "*.rb" = ""; + "*.php" = ""; + "*.java" = ""; + "*.sh" = ""; + "*.fish" = ""; + "*.swift" = ""; + "*.vim" = ""; + "*.lua" = ""; + "*.html" = ""; + "*.css" = ""; + "*.sass" = ""; + "*.scss" = ""; + "*.json" = ""; + "*.toml" = ""; + "*.yml" = ""; + "*.yaml" = ""; + "*.ini" = ""; + "*.conf" = ""; + "*.lock" = ""; + "*.nix" = ""; + Containerfile = "󰡨"; + Dockerfile = "󰡨"; + + # Misc + "*.bin" = ""; + "*.exe" = ""; + "*.pkg" = ""; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/manager.nix b/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/manager.nix new file mode 100644 index 0000000..53e67a7 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/manager.nix @@ -0,0 +1,63 @@ +{ + programs.yazi.theme.manager = { + cwd = {fg = "cyan";}; + + # Hovered + hovered = { + fg = "black"; + bg = "lightblue"; + }; + + preview_hovered = { + fg = "black"; + bg = "lightblue"; + }; + + # Find + find_keyword = { + fg = "yellow"; + italic = true; + }; + find_position = { + fg = "magenta"; + bg = "reset"; + italic = true; + }; + + # Marker + marker_selected = { + fg = "lightgreen"; + # bg = "lightgreen"; + }; + marker_copied = { + fg = "lightyellow"; + # bg = "lightyellow"; + }; + marker_cut = { + fg = "lightred"; + # bg = "lightred"; + }; + + # Tab + tab_active = { + fg = "black"; + bg = "lightblue"; + }; + tab_inactive = { + fg = "white"; + bg = "darkgray"; + }; + tab_width = 1; + + # Border; + border_symbol = "│"; + border_style = {fg = "gray";}; + + # Offset; + folder_offset = [1 0 1 0]; + preview_offset = [1 1 1 1]; + + # Highlighting; + syntect_theme = ""; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/status.nix b/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/status.nix new file mode 100644 index 0000000..878deb7 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/yazi/theme/status.nix @@ -0,0 +1,45 @@ +{ + programs.yazi.theme.status = { + separator_open = "█"; + separator_close = "█"; + separator_style = { + fg = "darkgray"; + bg = "darkgray"; + }; + + # Mode; + mode_normal = { + fg = "black"; + bg = "lightblue"; + bold = true; + }; + mode_select = { + fg = "black"; + bg = "lightgreen"; + bold = true; + }; + mode_unset = { + fg = "black"; + bg = "lightmagenta"; + bold = true; + }; + + # Progress; + progress_label = {bold = true;}; + progress_normal = { + fg = "blue"; + bg = "black"; + }; + progress_error = { + fg = "red"; + bg = "black"; + }; + + # Permissions; + permissions_t = {fg = "blue";}; + permissions_r = {fg = "lightyellow";}; + permissions_w = {fg = "lightred";}; + permissions_x = {fg = "lightgreen";}; + permissions_s = {fg = "darkgray";}; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/zellij/default.nix b/nyx/homes/notashelf/programs/terminal/tools/zellij/default.nix new file mode 100644 index 0000000..45a3284 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/zellij/default.nix @@ -0,0 +1,62 @@ +{osConfig, ...}: let + inherit (osConfig.modules.style.colorScheme) slug colors; +in { + config = { + programs.zellij = { + enable = true; + enableZshIntegration = false; # do NOT auto-start, thank you + settings = { + # custom defined layouts + layout_dir = "${./layouts}"; + + # clipboard provider + copy_command = "wl-copy"; + + auto_layouts = true; + + default_layout = "system"; # or compact + default_mode = "locked"; + + on_force_close = "quit"; + pane_frames = true; + session_serialization = false; + + ui.pane_frames = { + rounded_corners = true; + hide_session_name = true; + }; + + # load internal plugins from built-in paths + plugins = { + tab-bar.path = "tab-bar"; + status-bar.path = "status-bar"; + strider.path = "strider"; + compact-bar.path = "compact-bar"; + }; + + # generate a local colorscheme from the system theming module + # using the color palette and the slug provided by the module + # this will ensure consistency, generally, with differing + # colorschemes + themes = { + "${slug}" = with colors; { + bg = "#${base00}"; + fg = "#${base05}"; + red = "#${base08}"; + green = "#${base0A}"; + blue = "#${base0D}"; + yellow = "#${base06}"; + magenta = "#${base0E}"; + orange = "#${base09}"; + cyan = "#${base0C}"; + black = "#${base00}"; + white = "#${base05}"; + }; + }; + + # set theme to Catppuccin Mocha + theme = "${slug}"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/zellij/layouts/system.kdl b/nyx/homes/notashelf/programs/terminal/tools/zellij/layouts/system.kdl new file mode 100644 index 0000000..5061305 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/zellij/layouts/system.kdl @@ -0,0 +1,127 @@ +// this is my custom "system" layout, loosely based on the official +// zellij development layout - it's simplified for desktop use +// and allows me to remain in a single workspace even when I'm +// using a tiling window manager and am constrained to a single +// workspace. It provides default tabs for media, file browsing +// which should be everything that I need, but I may add more +// in the future + +layout { + // define default tab layout + default_tab_template { + // tab bar on the top + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + + // child tabs and panes + children + + // status bar on the bottom + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } + } + + // strider tab uses the strider plugin of zellij + // which is similar to neovim's nvimtree + // ...but slower and much less configurable + tab_template name="strider_tab" { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + + // use the strider plugin on the left side of the screen + // to achieve a nvim-tree like layout on the left 15% of + // the terminal window - looks cool but is not flexible + pane split_direction="Vertical" { + pane size="15%" name="Filetree" { + plugin location="zellij:strider" + } + children + } + + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } + } + + // define a template pane for the terminal + // this once again imitates the neovim layout + // by providing a terminal instance on the bottom + // 25% of the screen that enters the z shell when + // zellij starts - the exec duration for zsh matters + // here as it'll repeat for each "tab" that exists + pane_template name="term" { + // horizontal split to place the terminal + // on the bottom half of the screen like the + // toggleterm neovim plugin + pane split_direction="horizontal" { + children + pane command="zsh" size="25%" name="Shell" + } + } + + // create a "strider tab" for my system configuration + // which is a tab that utilizes the strider tab template + // that we have defined earlier, provides a file-tree + // view in my system config directory, and opens flake.nix + // with the $EDITOR variable - has focus, is the first tab + strider_tab name="Nyx" cwd="~dots" focus=true { + term split_direction="vertical" { + // FIXME: edit does not open the file from cwd + // instead opens a buffer named flake.nix in cwd + // which should be the original flake.nix + // but is not + pane edit="./flake.nix" name="Flake" + } + } + + // regular vertical tab that will open btop automatically for + // viewing active processes in a standalone tab + // more utilities can go here if seen necessary + tab name="Processes" split_direction="vertical" { + pane { + // open btop in the home directory + // doesn't really matter where you open it + cwd "$HOME" + command "btop" + } + } + + // the media tab opens musikcube, the TUI music player + // and pulsemixer for volume control across different + // audio devices - this is split horizontally so that + // the mixer covers less space on the screen, at the + // bottom 35% of the active tab + tab name="Media" split_direction="vertical" { + // run musikcube in the Music directory + // the CWD doesn't really matter as musikcube + // is capable of binding to mpd daemon but + // the music directory seemed suitable as + // the working directory for the player + pane split_direction="horizontal" name="Player" { + pane { + cwd "$HOME/Music" + command "musikcube" + } + } + + // standalone pane for pulsemixer + pane split_direction="horizontal" name="Mixer" { + pane size="35%" { + command "pulsemixer" + } + } + } + + // The last tab is a file browser that opens in the home directory + // so that I may freely browse my files and open them using the XDG + // specs when yazi can handle the file type. + tab name="Files" split_direction="horizontal" name="Files" { + pane { + cwd "$HOME" + command "yazi" + } + } +} diff --git a/nyx/homes/notashelf/programs/terminal/tools/zoxide.nix b/nyx/homes/notashelf/programs/terminal/tools/zoxide.nix new file mode 100644 index 0000000..5c9bbd9 --- /dev/null +++ b/nyx/homes/notashelf/programs/terminal/tools/zoxide.nix @@ -0,0 +1,6 @@ +{ + programs.zoxide = { + enable = true; + options = ["--cmd cd"]; + }; +} diff --git a/nyx/homes/notashelf/services/default.nix b/nyx/homes/notashelf/services/default.nix new file mode 100644 index 0000000..f738520 --- /dev/null +++ b/nyx/homes/notashelf/services/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./wayland # services that are wayland-only + ./x11 # services that are x11-only + ./shared # services that should be enabled regardless + ]; +} diff --git a/nyx/homes/notashelf/services/shared/default.nix b/nyx/homes/notashelf/services/shared/default.nix new file mode 100644 index 0000000..97bf826 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/default.nix @@ -0,0 +1,14 @@ +{ + imports = [ + ./dunst + ./media + + ./kdeconnect.nix + ./mail.nix + ./nextcloud.nix + ./polkit.nix + ./transience.nix + ./tray.nix + ./udiskie.nix + ]; +} diff --git a/nyx/homes/notashelf/services/shared/dunst/assets/brightness.svg b/nyx/homes/notashelf/services/shared/dunst/assets/brightness.svg new file mode 100644 index 0000000..c738f56 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/dunst/assets/brightness.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/nyx/homes/notashelf/services/shared/dunst/assets/mic-mute.svg b/nyx/homes/notashelf/services/shared/dunst/assets/mic-mute.svg new file mode 100644 index 0000000..65a3f22 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/dunst/assets/mic-mute.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nyx/homes/notashelf/services/shared/dunst/assets/mic.svg b/nyx/homes/notashelf/services/shared/dunst/assets/mic.svg new file mode 100644 index 0000000..9925f8b --- /dev/null +++ b/nyx/homes/notashelf/services/shared/dunst/assets/mic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nyx/homes/notashelf/services/shared/dunst/assets/notification.svg b/nyx/homes/notashelf/services/shared/dunst/assets/notification.svg new file mode 100644 index 0000000..2b02564 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/dunst/assets/notification.svg @@ -0,0 +1,57 @@ + + + + + + + + + diff --git a/nyx/homes/notashelf/services/shared/dunst/assets/volume-mute.svg b/nyx/homes/notashelf/services/shared/dunst/assets/volume-mute.svg new file mode 100644 index 0000000..2cb564a --- /dev/null +++ b/nyx/homes/notashelf/services/shared/dunst/assets/volume-mute.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nyx/homes/notashelf/services/shared/dunst/assets/volume.svg b/nyx/homes/notashelf/services/shared/dunst/assets/volume.svg new file mode 100644 index 0000000..c09ed6a --- /dev/null +++ b/nyx/homes/notashelf/services/shared/dunst/assets/volume.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nyx/homes/notashelf/services/shared/dunst/default.nix b/nyx/homes/notashelf/services/shared/dunst/default.nix new file mode 100644 index 0000000..3fcd97d --- /dev/null +++ b/nyx/homes/notashelf/services/shared/dunst/default.nix @@ -0,0 +1,100 @@ +{ + osConfig, + config, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + inherit (modules.style.colorScheme) colors; + + dev = modules.device; + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + services.dunst = { + enable = true; + iconTheme = { + package = config.gtk.iconTheme.package; + name = "Papirus-Dark"; + }; + + settings = { + global = { + follow = "mouse"; + width = 320; + height = 280; + origin = "top-center"; + alignment = "left"; + vertical_alignment = "center"; + ellipsize = "middle"; + offset = "17x17"; + padding = 15; + horizontal_padding = 15; + text_icon_padding = 15; + icon_position = "left"; + min_icon_size = 48; + max_icon_size = 64; + progress_bar = true; + progress_bar_height = 8; + progress_bar_frame_width = 1; + progress_bar_min_width = 150; + progress_bar_max_width = 300; + separator_height = 2; + frame_width = 2; + frame_color = "#${colors.base0E}"; + separator_color = "frame"; + corner_radius = 8; + transparency = 0; + gap_size = 8; + line_height = 0; + notification_limit = 3; + idle_threshold = 120; + history_length = 20; + show_age_threshold = 60; + markup = "full"; + font = "Iosevka 16"; + word_wrap = "yes"; + sort = "yes"; + shrink = "no"; + indicate_hidden = "yes"; + sticky_history = "yes"; + ignore_newline = "no"; + show_indicators = "no"; + stack_duplicates = true; + always_run_script = true; + hide_duplicate_count = false; + ignore_dbusclose = false; + force_xwayland = false; + force_xinerama = false; + mouse_left_click = "do_action"; + mouse_middle_click = "close_all"; + mouse_right_click = "close_current"; + }; + + fullscreen_delay_everything = {fullscreen = "delay";}; + + urgency_low = { + timeout = 3; + background = "#${colors.base02}"; + foreground = "#${colors.base05}"; + highlight = "#${colors.base0C}"; + }; + + urgency_normal = { + timeout = 7; + background = "#${colors.base02}"; + foreground = "#${colors.base05}"; + highlight = "#${colors.base0C}"; + }; + + urgency_critical = { + timeout = 0; + background = "#${colors.base02}"; + foreground = "#${colors.base05}"; + highlight = "#${colors.base08}"; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/kdeconnect.nix b/nyx/homes/notashelf/services/shared/kdeconnect.nix new file mode 100644 index 0000000..388d1a5 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/kdeconnect.nix @@ -0,0 +1,6 @@ +{ + services.kdeconnect = { + enable = false; + indicator = true; + }; +} diff --git a/nyx/homes/notashelf/services/shared/mail.nix b/nyx/homes/notashelf/services/shared/mail.nix new file mode 100644 index 0000000..15741cd --- /dev/null +++ b/nyx/homes/notashelf/services/shared/mail.nix @@ -0,0 +1,117 @@ +{ + osConfig, + config, + pkgs, + ... +}: { + config = let + extraMailboxes = ["Archive" "Drafts" "Junk" "Sent" "Trash"]; + in { + accounts.email = { + maildirBasePath = config.xdg.userDirs.extraConfig.XDG_MAIL_DIR; + accounts = { + notashelf = let + gpgKey = "0xBA46BCC36E912922"; + name = "NotAShelf"; + in { + primary = true; + address = "raf@notashelf.dev"; + aliases = ["me@notashelf.dev"]; + userName = "raf@notashelf.dev"; + realName = name; # very real, I know + passwordCommand = '' + # this is a really bad way of getting the password + # but home-manager does not provide a passwordFile option + tail ${osConfig.age.secrets.client-email.path} -n 1 + ''; + + signature = { + showSignature = "append"; + text = '' + -- + ${name} + + Want to use GPG encryption with me? Try my GPG key: + [${gpgKey}](https://github.com/notashelf.gpg) + ''; + }; + + folders = { + inbox = "Inbox"; + drafts = "Drafts"; + sent = "Sent"; + trash = "Trash"; + }; + + imap = { + host = "notashelf.dev"; + tls.enable = true; + }; + + smtp = { + host = "notashelf.dev"; + tls.enable = true; + }; + + gpg = { + key = gpgKey; + signByDefault = true; + }; + + msmtp.enable = true; + mbsync = { + enable = true; + create = "maildir"; # funny as it is, this is not a path - it's an instruction + expunge = "both"; + }; + + neomutt = { + enable = true; + inherit extraMailboxes; + }; + }; + }; + }; + + systemd.user = { + timers."mbsync" = { + Unit.Description = "Automatic mbsync synchronization"; + Timer = { + OnBootSec = "30"; + OnUnitActiveSec = "5m"; + }; + Install.WantedBy = ["timers.target"]; + }; + + services."genFolders" = { + Unit.Description = "Generate folders for email accounts"; + Install.WantedBy = ["multi-user.target"]; + Service = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = let + script = pkgs.writeShellApplication { + name = "genFolders"; + text = '' + # move to the current user's home directory + # FIXME: pretty sure this can also be set as the service's runtime dir + cd "${config.home.homeDirectory}/Mail" + + # iterate over dirs and create those that do not exist + for dir in ${toString extraMailboxes}; do + if [ ! -d "$dir" ]; then + echo -en "$dir does not exist, creating...\n"; + mkdir "$dir" + echo "Done creating $dir" + fi + done + ''; + }; + in "${script}/bin/genFolders"; + + # set runtime dir to the current user's home directory + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/media/default.nix b/nyx/homes/notashelf/services/shared/media/default.nix new file mode 100644 index 0000000..60b1d37 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/media/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./easyeffects + ./mpd + + ./noisetorch.nix + ./spotifyd.nix + ]; +} diff --git a/nyx/homes/notashelf/services/shared/media/easyeffects/default.nix b/nyx/homes/notashelf/services/shared/media/easyeffects/default.nix new file mode 100644 index 0000000..515245b --- /dev/null +++ b/nyx/homes/notashelf/services/shared/media/easyeffects/default.nix @@ -0,0 +1,19 @@ +{ + osConfig, + lib, + ... +}: let + inherit (lib.modules) mkIf; + + dev = osConfig.modules.device; + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + services.easyeffects = { + enable = true; + preset = "quiet"; + }; + + xdg.configFile."easyeffects/output/quiet.json".source = ./quiet.json; + }; +} diff --git a/nyx/homes/notashelf/services/shared/media/easyeffects/quiet.json b/nyx/homes/notashelf/services/shared/media/easyeffects/quiet.json new file mode 100644 index 0000000..11956b4 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/media/easyeffects/quiet.json @@ -0,0 +1,258 @@ +{ + "output": { + "blocklist": ["mpd", "mpd.pipewire"], + "compressor#0": { + "attack": 19.969999999999995, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "bypass": false, + "dry": -100.0, + "hpf-frequency": 10.0, + "hpf-mode": "off", + "input-gain": 14.9, + "knee": -6.499999999999998, + "lpf-frequency": 20000.0, + "lpf-mode": "off", + "makeup": 0.0, + "mode": "Upward", + "output-gain": -8.3, + "ratio": 3.9400000000000013, + "release": 100.0, + "release-threshold": -100.0, + "sidechain": { + "lookahead": 0.0, + "mode": "RMS", + "preamp": 0.0, + "reactivity": 10.0, + "source": "Middle", + "type": "Feed-forward" + }, + "threshold": -12.0, + "wet": 0.0 + }, + "multiband_compressor#0": { + "band0": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 500.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 10.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false + }, + "band1": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "enable-band": true, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 1000.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 500.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false, + "split-frequency": 500.0 + }, + "band2": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "enable-band": true, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 2000.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 1000.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false, + "split-frequency": 1000.0 + }, + "band3": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "enable-band": true, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 4000.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 2000.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false, + "split-frequency": 2000.0 + }, + "band4": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "enable-band": false, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 8000.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 4000.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false, + "split-frequency": 4000.0 + }, + "band5": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "enable-band": false, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 12000.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 8000.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false, + "split-frequency": 8000.0 + }, + "band6": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "enable-band": false, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 16000.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 12000.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false, + "split-frequency": 12000.0 + }, + "band7": { + "attack-threshold": -12.0, + "attack-time": 20.0, + "boost-amount": 6.0, + "boost-threshold": -72.0, + "compression-mode": "Downward", + "compressor-enable": true, + "enable-band": false, + "external-sidechain": false, + "knee": -6.0, + "makeup": 0.0, + "mute": false, + "ratio": 1.0, + "release-threshold": -100.0, + "release-time": 100.0, + "sidechain-custom-highcut-filter": false, + "sidechain-custom-lowcut-filter": false, + "sidechain-highcut-frequency": 20000.0, + "sidechain-lookahead": 0.0, + "sidechain-lowcut-frequency": 16000.0, + "sidechain-mode": "RMS", + "sidechain-preamp": 0.0, + "sidechain-reactivity": 10.0, + "sidechain-source": "Middle", + "solo": false, + "split-frequency": 16000.0 + }, + "bypass": true, + "compressor-mode": "Modern", + "dry": -100.0, + "envelope-boost": "None", + "input-gain": 19.2, + "output-gain": -0.8, + "wet": 0.0 + }, + "plugins_order": ["multiband_compressor#0", "compressor#0"] + } +} diff --git a/nyx/homes/notashelf/services/shared/media/mpd/default.nix b/nyx/homes/notashelf/services/shared/media/mpd/default.nix new file mode 100644 index 0000000..06a6cfa --- /dev/null +++ b/nyx/homes/notashelf/services/shared/media/mpd/default.nix @@ -0,0 +1,111 @@ +{ + osConfig, + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (osConfig) modules; + + env = modules.usrEnv; + srv = env.services; +in { + config = mkIf srv.media.mpd.enable { + home.packages = with pkgs; [ + playerctl # CLI interface for playerctld + mpc_cli # CLI interface for mpd + cava # CLI music visualizer (cavalier is a gui alternative) + ]; + + services = { + playerctld.enable = true; + mpris-proxy.enable = true; + mpd-mpris.enable = true; + + # music player daemon service + mpd = { + enable = true; + musicDirectory = "${config.home.homeDirectory}/Media/Music"; + network = { + startWhenNeeded = true; + listenAddress = "127.0.0.1"; + port = 6600; + }; + + extraConfig = '' + auto_update "yes" + volume_normalization "yes" + restore_paused "yes" + filesystem_charset "UTF-8" + + audio_output { + type "pipewire" + name "PipeWire" + } + + audio_output { + type "fifo" + name "Visualiser" + path "/tmp/mpd.fifo" + format "44100:16:2" + } + + audio_output { + type "httpd" + name "lossless" + encoder "flac" + port "8000" + max_clients "8" + mixer_type "software" + format "44100:16:2" + } + ''; + }; + + # MPRIS 2 support to mpd + mpdris2 = { + enable = true; + notifications = true; + multimediaKeys = true; + mpd = { + # for some reason config.xdg.userDirs.music is not a "path" - possibly because it has $HOME in its name? + inherit (config.services.mpd) musicDirectory; + }; + }; + + # discord rich presence for mpd + mpd-discord-rpc = { + enable = true; + settings = { + format = { + details = "$title"; + state = "On $album by $artist"; + large_text = "$album"; + small_image = ""; + }; + }; + }; + }; + + programs = { + /* + # yams service + # TODO: figure out a way to provide the lastfm authentication declaratively + + systemd.user.services.yams = { + Unit = { + Description = "Last.FM scrobbler for MPD"; + After = ["mpd.service"]; + }; + Service = { + ExecStart = "${pkgs.yams}/bin/yams -N"; + Environment = "NON_INTERACTIVE=1"; + Restart = "always"; + }; + Install.WantedBy = ["default.target"]; + }; + */ + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/media/noisetorch.nix b/nyx/homes/notashelf/services/shared/media/noisetorch.nix new file mode 100644 index 0000000..ea4056b --- /dev/null +++ b/nyx/homes/notashelf/services/shared/media/noisetorch.nix @@ -0,0 +1,64 @@ +{ + osConfig, + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf mkEnableOption mkOption literalExpression types; + + cfg = config.services.noisetorch; + + dev = osConfig.modules.device; + + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + options = { + services.noisetorch = { + enable = mkEnableOption "noisetorch service"; + package = mkOption { + type = types.package; + default = pkgs.noisetorch; + defaultText = literalExpression "pkgs.noisetorch"; + description = "Which package to use for noisetorch"; + }; + threshold = mkOption { + type = types.int; + default = -1; + description = "Voice activation threshold (default -1)"; + }; + device = mkOption { + type = types.str; + description = "Use the specified source/sink device ID"; + }; + deviceUnit = mkOption { + type = types.str; + description = "Systemd device unit which is providing the audio device"; + }; + }; + }; + + config = mkIf (cfg.enable && builtins.elem dev.type acceptedTypes) { + home.packages = [cfg.package]; + + systemd.user.services.noisetorch = { + Unit = { + Description = "Noisetorch Noise Cancelling"; + Requires = "${cfg.deviceUnit}"; + After = "${cfg.deviceUnit}"; + }; + Install = { + WantedBy = ["default.target"]; + }; + Service = { + Type = "simple"; + RemainAfterExit = "yes"; + ExecStart = "${cfg.package}/bin/noisetorch -i -s ${cfg.device} -t ${builtins.toString cfg.threshold}"; + ExecStop = "${cfg.package}/bin/noisetorch -u"; + Restart = "on-failure"; + RestartSec = 3; + Nice = -10; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/media/spotifyd.nix b/nyx/homes/notashelf/services/shared/media/spotifyd.nix new file mode 100644 index 0000000..140f89c --- /dev/null +++ b/nyx/homes/notashelf/services/shared/media/spotifyd.nix @@ -0,0 +1,38 @@ +{ + osConfig, + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + dev = osConfig.modules.device; + + credientals = { + password_cmd = "${pkgs.coreutils}/bin/tail -1 /run/agenix/spotify"; + username_cmd = "${pkgs.coreutils}/bin/head -1 /run/agenix/spotify"; + }; + + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes) { + services = { + spotifyd = { + enable = false; + package = pkgs.spotifyd.override {withMpris = true;}; + settings.global = { + inherit (credientals) password_cmd username_cmd; + cache_path = "${config.xdg.cacheHome}/spotifyd"; + device_type = "computer"; + use_mpris = true; + autoplay = true; + + # audio settings + volume_normalisation = true; + backend = "pulseaudio"; + bitrate = 320; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/nextcloud.nix b/nyx/homes/notashelf/services/shared/nextcloud.nix new file mode 100644 index 0000000..d7ed3cc --- /dev/null +++ b/nyx/homes/notashelf/services/shared/nextcloud.nix @@ -0,0 +1,33 @@ +{ + lib, + osConfig, + pkgs, + ... +}: let + inherit (lib) mkIf; + + dev = osConfig.modules.device; + vid = osConfig.modules.system.video; + env = osConfig.modules.usrEnv; + + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + config = mkIf ((builtins.elem dev.type acceptedTypes) && (vid.enable && env.isWayland)) { + /* + services = { + nextcloud-client.enable = true; + nextcloud-client.startInBackground = true; + }; + */ + + home.packages = [pkgs.nextcloud-client]; + systemd.user.services.nextcloud = lib.mkGraphicalService { + Unit.Description = "Nextcloud client service"; + Service = { + ExecStart = "${pkgs.nextcloud-client}/bin/nextcloud --background"; + Restart = "always"; + Slice = "background.slice"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/polkit.nix b/nyx/homes/notashelf/services/shared/polkit.nix new file mode 100644 index 0000000..3327dcb --- /dev/null +++ b/nyx/homes/notashelf/services/shared/polkit.nix @@ -0,0 +1,22 @@ +{ + lib, + osConfig, + pkgs, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) modules; + + dev = modules.device; + sys = modules.system; + + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + config = mkIf ((builtins.elem dev.type acceptedTypes) && sys.video.enable) { + # gnome polkit agent + systemd.user.services.polkit-pantheon-authentication-agent-1 = lib.mkGraphicalService { + #Service.ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"; + Service.ExecStart = "${pkgs.pantheon.pantheon-agent-polkit}/libexec/policykit-1-pantheon/io.elementary.desktop.agent-polkit"; + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/transience.nix b/nyx/homes/notashelf/services/shared/transience.nix new file mode 100644 index 0000000..bb51fe3 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/transience.nix @@ -0,0 +1,14 @@ +{ + osConfig, + self, + ... +}: let + sys = osConfig.modules.system; +in { + imports = [self.homeManagerModules.transience]; + services.transience = { + enable = false; + directories = []; + user = sys.mainUser; + }; +} diff --git a/nyx/homes/notashelf/services/shared/tray.nix b/nyx/homes/notashelf/services/shared/tray.nix new file mode 100644 index 0000000..8d2a337 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/tray.nix @@ -0,0 +1,19 @@ +{ + osConfig, + lib, + ... +}: let + env = osConfig.modules.usrEnv; +in { + # assume system is headless if desktop is not set + config = lib.mkIf (env.desktop != "") { + # fake a tray to let apps start + # https://github.com/nix-community/home-manager/issues/2064 + systemd.user.targets.tray = { + Unit = { + Description = "Home Manager System Tray"; + Requires = ["graphical-session-pre.target"]; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/shared/udiskie.nix b/nyx/homes/notashelf/services/shared/udiskie.nix new file mode 100644 index 0000000..f3ea3b8 --- /dev/null +++ b/nyx/homes/notashelf/services/shared/udiskie.nix @@ -0,0 +1,3 @@ +{ + services.udiskie.enable = true; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/.envrc b/nyx/homes/notashelf/services/wayland/ags/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/.envrc @@ -0,0 +1 @@ +use nix diff --git a/nyx/homes/notashelf/services/wayland/ags/.eslintrc.yml b/nyx/homes/notashelf/services/wayland/ags/.eslintrc.yml new file mode 100644 index 0000000..006b5de --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/.eslintrc.yml @@ -0,0 +1,108 @@ +root: true +env: + es2021: true +extends: + - "eslint:recommended" + - "plugin:@typescript-eslint/recommended" +parser: "@typescript-eslint/parser" +parserOptions: + ecmaVersion: 2022 + sourceType: "module" + project: "./tsconfig.json" + warnOnUnsupportedTypeScriptVersion: false +ignorePatterns: + - types/ + - node_modules/ + - bin/ + - result/ + - style/ +plugins: + - "@typescript-eslint" +rules: + "@typescript-eslint/ban-ts-comment": + - "off" + "@typescript-eslint/no-non-null-assertion": + - "off" + "@typescript-eslint/no-explicit-any": + - "off" + "@typescript-eslint/no-unused-vars": + - error + - varsIgnorePattern: (^unused|_$) + argsIgnorePattern: ^(unused|_) + "@typescript-eslint/no-empty-interface": + - "off" + + comma-dangle: + - error + - always-multiline + comma-spacing: + - error + - before: false + after: true + comma-style: + - error + - last + curly: + - error + - multi-or-nest + - consistent + dot-location: + - error + - property + eol-last: + - error + indent: + - error + - 4 + - SwitchCase: 1 + keyword-spacing: + - error + - before: true + lines-between-class-members: + - error + - always + - exceptAfterSingleLine: true + padded-blocks: + - error + - never + - allowSingleLineBlocks: false + prefer-const: + - error + quotes: + - error + - double + - avoidEscape: true + semi: + - error + - always + nonblock-statement-body-position: + - error + - below + no-trailing-spaces: + - error + no-useless-escape: + - off + max-len: + - error + - code: 100 + func-call-spacing: + - error + array-bracket-spacing: + - error + space-before-blocks: + - error + key-spacing: + - error + object-curly-spacing: + - error + - always + +globals: + globalThis: readonly + imports: readonly + Intl: readonly + log: readonly + logError: readonly + print: readonly + printerr: readonly + console: readonly diff --git a/nyx/homes/notashelf/services/wayland/ags/.gitignore b/nyx/homes/notashelf/services/wayland/ags/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/nyx/homes/notashelf/services/wayland/ags/.prettierrc b/nyx/homes/notashelf/services/wayland/ags/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/nyx/homes/notashelf/services/wayland/ags/.stylelintrc.yml b/nyx/homes/notashelf/services/wayland/ags/.stylelintrc.yml new file mode 100644 index 0000000..bf75e9a --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/.stylelintrc.yml @@ -0,0 +1,14 @@ +extends: stylelint-config-standard-scss +ignoreFiles: + - "**/*.js" + - "**/*.ts" +rules: + selector-type-no-unknown: null + declaration-empty-line-before: null + no-descending-specificity: null + selector-pseudo-class-no-unknown: null + color-function-notation: legacy + alpha-value-notation: number + scss/operator-no-unspaced: null + scss/no-global-function-names: null + scss/dollar-variable-empty-line-before: null diff --git a/nyx/homes/notashelf/services/wayland/ags/README.md b/nyx/homes/notashelf/services/wayland/ags/README.md new file mode 100644 index 0000000..6e1ad5e --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/README.md @@ -0,0 +1,29 @@ +# Ags Configuration + +A complete-ish shell replacement with a strong dependency on Hyprland. +Currently features a drop-in replacement for my old Waybar configuration +paired with a few other features that I found interesting, such as a program +launcher and desktop right click capture. + +## Developing Locally + +This configuration is primarily tied to a systemd user service - the +dependencies will be made available to ags inside a wrapper, so you do not +need to add anything to your `home.packages`. If developing locally, those +dependencies will need to be available inside your devshell. Take a look at the +`dependencies` list in `default.nix` and enter a shell with the required packages +to be able to run `ags -c ./config.js`. Currently `sassc` and `python3` are +necessary to be able to start the bar. If you skip this step, ags will not actually +display the bar. + +## Credits + +I have taken inspiration or/and code snippets from the cool people below. If you like +this configuration, consider giving them a star on their respective repositories. + +- [Exoess](https://github.com/exoess/.files) - initially based on their configuration +- [SoraTenshi](https://github.com/SoraTenshi/ags-env) - the connection widget and weather module inspiration +- [Fufexan](https://github.com/fufexan/dotfiles/tree/main/home/programs/ags) - cool dude overall, inspiration + for a few widgets and his willingness to help with my skill issues + +And of course [Aylur](https://github.com/Aylur) for his awesome work on AGS. diff --git a/nyx/homes/notashelf/services/wayland/ags/bin/hyprctl_swallow b/nyx/homes/notashelf/services/wayland/ags/bin/hyprctl_swallow new file mode 100755 index 0000000..750acc4 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/bin/hyprctl_swallow @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# vim: syntax=bash + +notifySend="notify-send" + +getSwallowStatus() { + output=$(hyprctl getoption misc:enable_swallow) + if [[ $output == *"int: 1"* ]]; then + status=false + else + status=true + fi + echo "{\"status\": $status}" +} + +switchSwallowStatus() { + enable=$1 + if [ "$enable" = true ]; then + statusMsg="Turned on swallowing" + keyword="true" + else + statusMsg="Turned off swallowing" + keyword="false" + fi + hyprctl keyword misc:enable_swallow $keyword + $notifySend "Hyprland" "$statusMsg" +} + +if [ $# -gt 0 ] && [ "${1}" = "query" ]; then + getSwallowStatus + exit 0 +fi + +output=$(hyprctl getoption misc:enable_swallow) + +if [[ $output == *"int: 1"* ]]; then + switchSwallowStatus false +else + switchSwallowStatus true +fi diff --git a/nyx/homes/notashelf/services/wayland/ags/bin/move_window b/nyx/homes/notashelf/services/wayland/ags/bin/move_window new file mode 100755 index 0000000..71e0e50 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/bin/move_window @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# vim: syntax=sh + +move_window() { + local position="$1" + local size="$2" + + if [[ -z "$position" || -z "$size" ]]; then + echo "Error: Both position and size are required." 1>&2 + exit 1 + fi + + hyprctl --batch "dispatch moveactive exact ${position//,/ }; dispatch resizeactive exact ${size//x/ }" +} + +if [[ $# -ne 2 ]]; then + echo "Usage: $0 " + exit 1 +fi + +move_window "$1" "$2" diff --git a/nyx/homes/notashelf/services/wayland/ags/bin/open_window b/nyx/homes/notashelf/services/wayland/ags/bin/open_window new file mode 100755 index 0000000..17bb5f7 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/bin/open_window @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# vim: syntax=bash + +open_window() { + local position="$1" + local size="$2" + local command="$3" + + # Validate input + if [[ -z "$position" || -z "$size" || -z "$command" ]]; then + echo "Error: Position, size, and command are required." 1>&2 + exit 1 + fi + + hyprctl dispatch exec "[float; move ${position//,/ }; size ${size//x/ }] $command" +} + +if [[ $# -ne 3 ]]; then + echo "Usage: $0 " + exit 1 +fi + +open_window "$1" "$2" "$3" diff --git a/nyx/homes/notashelf/services/wayland/ags/bin/weather b/nyx/homes/notashelf/services/wayland/ags/bin/weather new file mode 100755 index 0000000..36fc730 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/bin/weather @@ -0,0 +1,178 @@ +#!/usr/bin/env python +# vim: syntax=python + +import os +import json +import requests +import logging +from datetime import datetime, timedelta + +logging.basicConfig(level=logging.ERROR) +logger = logging.getLogger(__name__) + +CACHE_EXPIRATION = 60 +XDG_CACHE_HOME = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache")) +CACHE_DIR = os.path.join(XDG_CACHE_HOME, "zephyr") +FALLBACK_CACHE_DIR = "/tmp" +CACHE_FILE = os.path.join(CACHE_DIR, "zephyr_cache.json") + +SUNNY = "\udb81\udda8" +CLOUDY = "\ue312" +RAIN = "\ue318" +SNOW = "\ue31a" +THUNDERSTORM = "\ue31d" +PARTLY_CLOUDY = "\ue302" +CLEAR = "\ue30d" + +HOURS_AGO_THRESHOLD = 2 +TEMP_THRESHOLD_COLD = 10 +TEMP_THRESHOLD_HOT = 0 + + +def ensure_cache_directory(): + try: + if not os.path.exists(CACHE_DIR): + os.makedirs(CACHE_DIR, exist_ok=True) + except Exception as e: + logger.error(f"Error creating cache directory: {e}") + + +def get_weather_data(): + ensure_cache_directory() + try: + response = requests.get("https://wttr.in/?format=j1") + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + logger.error(f"Error fetching weather data: {e}") + return None + + +def get_cached_weather_data(): + try: + if os.path.exists(CACHE_FILE): + with open(CACHE_FILE, "r") as cache_file: + cached_data = json.load(cache_file) + cache_time = datetime.strptime( + cached_data["timestamp"], "%Y-%m-%d %H:%M:%S" + ) + if datetime.now() - cache_time < timedelta(minutes=CACHE_EXPIRATION): + return cached_data["data"] + except Exception as e: + logger.error(f"Error loading cached data: {e}") + return None + + +def cache_weather_data(data): + try: + with open(CACHE_FILE, "w") as cache_file: + cached_data = { + "data": data, + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + } + json.dump(cached_data, cache_file) + except Exception as e: + logger.error(f"Error caching data: {e}") + + +def format_time(time): + return time.replace("00", "").zfill(2) + + +def format_temp(temp): + return f" {temp}°".ljust(4) + + +def get_emoji_for_condition(condition): + emoji_map = { + "Sunny": SUNNY, + "Partly cloudy": PARTLY_CLOUDY, + "Overcast": CLOUDY, + "Patchy rain nearby": RAIN, + "Clear": CLEAR, + "Fog": "\ue313", + "Frost": "\udb83\udf29", + "Thunder": THUNDERSTORM, + "Snow": SNOW, + "Windy": "\u27A7", + "Mist": "\u2601", + "Drizzle": "\u2601", + "Heavy rain": "\u2614", + "Sleet": "\u2744", + "Wintry mix": "\u2744", + "Clear/Sunny": CLEAR, + "Clear/Mostly clear": CLEAR, + "Clear/Mostly clear (night)": CLEAR, + "Drizzle (night)": "\u2601", + } + return emoji_map.get(condition, "") + + +def format_conditions(hour): + condition_probabilities = { + "chanceoffog": "Fog", + "chanceoffrost": "Frost", + "chanceofovercast": "Overcast", + "chanceofrain": "Rain", + "chanceofsnow": "Snow", + "chanceofsunshine": "Sunshine", + "chanceofthunder": "Thunder", + "chanceofwindy": "Wind", + } + if "chanceofpartlycloudy" in hour: + condition_probabilities["chanceofpartlycloudy"] = "Partly Cloudy" + conditions = [] + for event, description in condition_probabilities.items(): + if event in hour: + probability = int(hour[event]) + if probability > 0: + emoji = get_emoji_for_condition(description) + conditions.append(f"{emoji} {description} {probability}%") + return ", ".join(conditions) + + +def format_weather_data(weather_data): + current_condition = weather_data["current_condition"][0] + temp = int(current_condition["FeelsLikeC"]) + temp_sign = "+" if TEMP_THRESHOLD_HOT > temp > TEMP_THRESHOLD_COLD else "" + formatted_data = { + "text": f" {SUNNY} \n {temp_sign}{temp}°", + "tooltip": f"{current_condition['weatherDesc'][0]['value']} {current_condition['temp_C']}°\n" + f"Feels like: {current_condition['FeelsLikeC']}°\n" + f"Wind: {current_condition['windspeedKmph']}Km/h\n" + f"Humidity: {current_condition['humidity']}%\n", + } + for i, day in enumerate(weather_data["weather"]): + formatted_data["tooltip"] += f"\n" + if i == 0: + formatted_data["tooltip"] += "Today, " + if i == 1: + formatted_data["tooltip"] += "Tomorrow, " + formatted_data["tooltip"] += f"{day['date']}\n" + formatted_data["tooltip"] += f"⬆️ {day['maxtempC']}° ⬇️ {day['mintempC']}° " + formatted_data[ + "tooltip" + ] += f"🌅 {day['astronomy'][0]['sunrise']} 🌇 {day['astronomy'][0]['sunset']}\n" + now = datetime.now() + for hour in day["hourly"]: + hour_time = format_time(hour["time"]) + if i == 0 and int(hour_time) < now.hour - HOURS_AGO_THRESHOLD: + continue + formatted_data[ + "tooltip" + ] += f"{hour_time} {get_emoji_for_condition(hour['weatherDesc'][0]['value'])} {format_temp(hour['FeelsLikeC'])} {hour['weatherDesc'][0]['value']}, {format_conditions(hour)}\n" + return formatted_data + + +def main(): + weather_data = get_weather_data() + if weather_data is None: + weather_data = get_cached_weather_data() + if weather_data: + formatted_data = format_weather_data(weather_data) + cache_weather_data(formatted_data) + print(json.dumps(formatted_data)) + + +if __name__ == "__main__": + main() diff --git a/nyx/homes/notashelf/services/wayland/ags/config.js b/nyx/homes/notashelf/services/wayland/ags/config.js new file mode 100644 index 0000000..31ac676 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/config.js @@ -0,0 +1,34 @@ +import { App, Notifications } from "./js/imports.js"; +const css = App.configDir + "/style.css"; + +// Windows +import { AppLauncher } from "./js/windows/launcher/index.js"; +import { Bar } from "./js/windows/bar/index.js"; +import { Desktop } from "./js/windows/desktop/index.js"; +import { Popups } from "./js/windows/popups/index.js"; +import { Notifs } from "./js/windows/notifications/index.js"; +import { Media } from "./js/windows/music/index.js"; + +App.connect("config-parsed", () => print("config parsed")); + +Notifications.popupTimeout = 5000; +Notifications.forceTimeout = false; +Notifications.cacheActions = true; + +// Main config +export default { + style: css, + closeWindowDelay: { + launcher: 300, + music: 300, + }, +}; + +/** + * @param {any[]} windows + */ +function addWindows(windows) { + windows.forEach((win) => App.addWindow(win)); +} + +addWindows([AppLauncher(), Bar(), Media(), Desktop(), Popups(), Notifs()]); diff --git a/nyx/homes/notashelf/services/wayland/ags/default.nix b/nyx/homes/notashelf/services/wayland/ags/default.nix new file mode 100644 index 0000000..723b2e0 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/default.nix @@ -0,0 +1,122 @@ +{ + inputs, + osConfig, + config, + pkgs, + lib, + ... +}: let + inherit (lib.fileset) fileFilter unions difference toSource; + inherit (lib.modules) mkIf; + inherit (osConfig.modules) device; + + # dependencies required for the ags runtime to function properly + # some of those dependencies are used internally for setting variables + # or basic functionality where built-in services do not suffice + coreDeps = with pkgs; [ + inputs.hyprpicker.packages.${pkgs.system}.default + inputs.hyprland.packages.${pkgs.system}.default + config.programs.foot.package + + # basic functionality + inotify-tools + gtk3 + + # script and service helpers + bash + brightnessctl + coreutils + gawk + gvfs + imagemagick + libnotify + procps + ripgrep + slurp + sysstat + + # for weather widget + (python3.withPackages (ps: [ps.requests])) + ]; + + # applications that are not necessarily required to compile ags + # but are used by the widgets to launch certain applications + widgetDeps = with pkgs; [ + pavucontrol + networkmanagerapplet + blueman + ]; + + dependencies = coreDeps ++ widgetDeps; + filterNixFiles = fileFilter (file: lib.hasSuffix ".nix" file.name) ./.; + + baseSrc = unions [ + # runtime executables + ./bin + + # ags widgets and utilities + ./js + ./config.js + + # compiled stylesheet + # should be generated using the below command + # `sassc -t compressed style/main.scss style.css` + ./style.css + ]; + + filter = difference baseSrc filterNixFiles; + + cfg = config.programs.ags; + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + imports = [inputs.ags.homeManagerModules.default]; + config = mkIf (builtins.elem device.type acceptedTypes) { + programs.ags = { + enable = true; + configDir = toSource { + root = ./.; + fileset = filter; + }; + }; + + systemd.user.services.ags = { + Install.WantedBy = ["graphical-session.target"]; + + Unit = { + Description = "Aylur's Gtk Shell (Ags)"; + After = ["graphical-session-pre.target"]; + PartOf = [ + "tray.target" + "graphical-session.target" + ]; + }; + + Service = { + Type = "simple"; + + Environment = "PATH=/run/wrappers/bin:${lib.makeBinPath dependencies}"; + ExecStart = "${cfg.package}/bin/ags"; + ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR2 $MAINPID"; # hot-reloading + + # runtime + RuntimeDirectory = "ags"; + ProtectSystem = "strict"; + ProtectHome = "read-only"; + CacheDirectory = ["ags"]; + ReadWritePaths = [ + # socket access + "%t" # /run/user/1000 for the socket + "/tmp/hypr" # hyprland socket + + # for thumbnail caching + "~/notashelf/.local/share/firefox-mpris/" + "~/.cache/ags/media" + ]; + + # restart on failure + Restart = "on-failure"; + KillMode = "mixed"; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/js/icons.js b/nyx/homes/notashelf/services/wayland/ags/js/icons.js new file mode 100644 index 0000000..0cf24f4 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/icons.js @@ -0,0 +1,119 @@ +export const Icon = { + settings: "org.gnome.Settings-symbolic", + tick: "object-select-symbolic", + audio: { + mic: { + muted: "microphone-disabled-symbolic", + unmuted: "microphone-sensitivity-high-symbolic", + }, + volume: { + muted: "audio-volume-muted-symbolic", + low: "audio-volume-low-symbolic", + medium: "audio-volume-medium-symbolic", + high: "audio-volume-high-symbolic", + overamplified: "audio-volume-overamplified-symbolic", + }, + type: { + headset: "audio-headphones-symbolic", + speaker: "audio-speakers-symbolic", + card: "audio-card-symbolic", + }, + mixer: "tool-symbolic", + }, + apps: { + apps: "view-app-grid-symbolic", + search: "folder-saved-search-symbolic", + }, + bluetooth: { + enabled: "bluetooth-active-symbolic", + disabled: "bluetooth-disabled-symbolic", + }, + brightness: { + indicator: "display-brightness-symbolic", + keyboard: "keyboard-brightness-symbolic", + screen: ["󰛩", "󱩎", "󱩏", "󱩐", "󱩑", "󱩒", "󱩓", "󱩔", "󱩕", "󱩖", "󰛨"], + }, + powermenu: { + sleep: "weather-clear-night-symbolic", + reboot: "system-reboot-symbolic", + logout: "system-log-out-symbolic", + shutdown: "system-shutdown-symbolic", + lock: "system-lock-screen-symbolic", + close: "window-close-symbolic", + }, + recorder: { + recording: "media-record-symbolic", + }, + notifications: { + noisy: "preferences-system-notifications-symbolic", + silent: "notifications-disabled-symbolic", + critical: "messagebox_critical-symbolic", + chat: "notification-symbolic", + close: "window-close-symbolic", + }, + header: { + refresh: "view-refresh-symbolic", + settings: "settings-symbolic", + power: "system-shutdown-symbolic", + }, + trash: { + full: "user-trash-full-symbolic", + empty: "user-trash-symbolic", + }, + mpris: { + fallback: "audio-x-generic-symbolic", + shuffle: { + enabled: "media-playlist-shuffle-symbolic", + disabled: "media-playlist-no-shuffle-symbolic", + }, + loop: { + none: "media-playlist-no-repeat-symbolic", + track: "media-playlist-repeat-song-symbolic", + playlist: "media-playlist-repeat-symbolic", + }, + playing: "media-playback-pause-symbolic", + paused: "media-playback-start-symbolic", + stopped: "media-playback-stop-symbolic", + prev: "media-skip-backward-symbolic", + next: "media-skip-forward-symbolic", + }, + ui: { + send: "mail-send-symbolic", + arrow: { + right: "pan-end-symbolic", + left: "pan-start-symbolic", + down: "pan-down-symbolic", + up: "pan-up-symbolic", + }, + }, + speaker: { + overamplified: "\uf14b", + high: "\ue050", + medium: "\ue04d", + low: "\ue04e", + muted: "\ue04f", + }, + microphone: { + overamplified: "\ue029", + high: "\ue029", + medium: "\ue029", + low: "\ue029", + muted: "\ue02b", + }, + wired: { + power: "󰈀", + poweroff: "󱘖", + }, + wifi: { + none: "󰤭", + bad: "󰤠", + low: "󰤟", + normal: "󰤢", + good: "󰤨", + }, + system: { + cpu: "org.gnome.SystemMonitor-symbolic", + ram: "drive-harddisk-solidstate-symbolic", + temp: "temperature-symbolic", + }, +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/imports.js b/nyx/homes/notashelf/services/wayland/ags/js/imports.js new file mode 100644 index 0000000..400fbab --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/imports.js @@ -0,0 +1,27 @@ +export const require = async (file) => (await import(resource(file))).default; +export const resource = (file) => `resource:///com/github/Aylur/ags/${file}.js`; +export const fromService = async (file) => await require(`service/${file}`); +export const requireCustom = async (/** @type {string} */ path) => + (await import(path)).default; + +export const App = await require("app"); +export const GLib = await requireCustom("gi://GLib"); +export const Gtk = await requireCustom("gi://Gtk?version=3.0"); +export const Service = await require("service"); +export const Utils = await import(resource("utils")); +export const Variable = await require("variable"); +export const Widget = await require("widget"); + +// Services +export const Battery = await fromService("battery"); +export const Bluetooth = await fromService("bluetooth"); +export const Hyprland = await fromService("hyprland"); +export const Mpris = await fromService("mpris"); +export const Network = await fromService("network"); +export const Applications = await fromService("applications"); +export const Audio = await fromService("audio"); +export const Notifications = await fromService("notifications"); +export const SystemTray = await fromService("systemtray"); + +// Extras +export const Icons = await requireCustom("./utils/icons.js"); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/services/brightness.js b/nyx/homes/notashelf/services/wayland/ags/js/services/brightness.js new file mode 100644 index 0000000..6ad41a4 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/services/brightness.js @@ -0,0 +1,50 @@ +import { Service, Utils } from "../imports.js"; +const { exec } = Utils; + +class Brightness extends Service { + static { + Service.register( + this, + {}, + { + screen: ["float", "rw"], + }, + ); + } + + _screen = 0; + + get screen() { + return this._screen; + } + + set screen(percent) { + if (percent < 0) percent = 0; + + if (percent > 1) percent = 1; + + Utils.execAsync(`brightnessctl s ${percent * 100}% -q`) + .then(() => { + this._screen = percent; + this.changed("screen"); + }) + .catch(console.error); + } + + constructor() { + super(); + try { + this._screen = + Number(exec("brightnessctl g")) / + Number(exec("brightnessctl m")); + } catch (error) { + console.error("missing dependancy: brightnessctl"); + } + } +} + +const service = new Brightness(); + +globalThis.brightness = service; + +export default service; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/services/directoryMonitorService.js b/nyx/homes/notashelf/services/wayland/ags/js/services/directoryMonitorService.js new file mode 100644 index 0000000..4b4f439 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/services/directoryMonitorService.js @@ -0,0 +1,49 @@ +import { Service } from "../imports.js"; +const { Gio } = imports.gi; + +class DirectoryMonitorService extends Service { + static { + Service.register(this, {}, {}); + } + + _monitors = []; + + constructor() { + super(); + } + + recursiveDirectoryMonitor(directoryPath) { + const directory = Gio.File.new_for_path(directoryPath); + const monitor = directory.monitor_directory( + Gio.FileMonitorFlags.NONE, + null, + ); + this._monitors.push(monitor); + + monitor.connect( + "changed", + (fileMonitor, file, otherFile, eventType) => { + if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) { + this.emit("changed"); + } + }, + ); + + const enumerator = directory.enumerate_children( + "standard::*", + Gio.FileQueryInfoFlags.NONE, + null, + ); + + let fileInfo; + while ((fileInfo = enumerator.next_file(null)) !== null) { + const childPath = directoryPath + "/" + fileInfo.get_name(); + if (fileInfo.get_file_type() === Gio.FileType.DIRECTORY) { + this.recursiveDirectoryMonitor(childPath); + } + } + } +} + +const service = new DirectoryMonitorService(); +export default service; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/services/inputMonitor.js b/nyx/homes/notashelf/services/wayland/ags/js/services/inputMonitor.js new file mode 100644 index 0000000..0379704 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/services/inputMonitor.js @@ -0,0 +1,56 @@ +import { Utils, Service } from "../imports.js"; +const { subprocess } = Utils; + +class InputMonitorService extends Service { + static { + Service.register( + this, + { + keypress: ["jsobject"], + keyrelease: ["jsobject"], + keyrepeat: ["jsobject"], + event: ["jsobject"], + }, + {}, + ); + } + + constructor() { + super(); + this._evtest = subprocess("evtest /dev/input/event3", (str) => + this._handleEvent(str), + ); + } + + _handleEvent(event) { + //ignore initial output + if (!event.startsWith("Event")) return; + //ignore SYN_REPORTS + if (event.includes("SYN")) return; + const eventData = event.substring(7).split(", "); + const eventInfo = {}; + //evetnInfo structure: + //{ + // time: unix timstamp + // type: event type + // code: keycode (this is the harware keycode) + // value: depends on type, for EV_KEY 0->release, 1->press, 2->repeat(when holding) + //} + + eventData.forEach((data) => { + const [key, value, value2] = data.split(" "); + eventInfo[key] = isNaN(value) ? value : Number(value); + if (key === "code") eventInfo["name"] = value2.slice(1, -1); + }); + //only emit on EV_KEY + if (eventInfo.type === 1) { + if (eventInfo.value === 0) this.emit("keyrelease", eventInfo); + if (eventInfo.value === 1) this.emit("keypress", eventInfo); + if (eventInfo.value === 2) this.emit("keyrepeat", eventInfo); + } + //emit on every event, just in case, you need it + this.emit("event", eventInfo); + } +} + +export default new InputMonitorService(); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/appIcon.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/appIcon.js new file mode 100644 index 0000000..3413269 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/appIcon.js @@ -0,0 +1,21 @@ +import { Widget } from "../imports.js"; +import { queryExact } from "./global.js"; +const { Button, Icon } = Widget; + +export default ({ + appName, + onClicked = () => queryExact(appName).launch(), + icon = queryExact(appName).iconName, + size = 36, + ...props +}) => { + const appIcon = Button({ + onClicked, + child: Icon({ + icon, + size, + ...props, + }), + }); + return appIcon; +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/audio.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/audio.js new file mode 100644 index 0000000..2db7dd6 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/audio.js @@ -0,0 +1,62 @@ +import { Audio, Widget } from "../imports.js"; +const { Slider, Label } = Widget; +const { speaker } = Audio; + +const audio = { + mixer: "", + mic: { + muted: "microphone-disabled-symbolic", + low: "microphone-sensitivity-low-symbolic", + medium: "microphone-sensitivity-medium-symbolic", + high: "microphone-sensitivity-high-symbolic", + }, + volume: { + muted: "audio-volume-muted-symbolic", + low: "audio-volume-low-symbolic", + medium: "audio-volume-medium-symbolic", + high: "audio-volume-high-symbolic", + overamplified: "audio-volume-overamplified-symbolic", + }, + type: { + headset: "audio-headphones-symbolic", + speaker: "audio-speakers-symbolic", + card: "audio-card-symbolic", + }, +}; + +export const getAudioIcon = (self) => { + if (!Audio.speaker) return; + + const { muted, low, medium, high, overamplified } = audio.volume; + + if (Audio.speaker.is_muted) return (self.icon = muted); + + /** @type {Array<[number, string]>} */ + const cons = [ + [101, overamplified], + [67, high], + [34, medium], + [1, low], + [0, muted], + ]; + + self.icon = cons.find(([n]) => n <= Audio.speaker.volume * 100)?.[1] || ""; +}; + +export const getSliderIcon = () => + Label({ + className: "volPopupIcon", + label: speaker.bind("volume").as((/** @type {number} */ v) => { + return ["󰝟", "󰕿", "", "󰕾"][ + speaker.stream?.isMuted ? 0 : Math.floor((v * 100) / 26) + ]; + }), + }); + +export const volumePercentBar = () => + Slider({ + className: "volPopupBar", + drawValue: false, + value: speaker.bind("volume"), + onChange: ({ value }) => (speaker.volume = value), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/battery.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/battery.js new file mode 100644 index 0000000..d95779f --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/battery.js @@ -0,0 +1,57 @@ +import { Battery } from "../imports.js"; + +/** + * toTime converts a given value to a human-readable + * format where the number of hours and minutes are + * inferred from time, which is assumed to be in seconds. + * + * @param {number} time - time in seconds + */ +export const toTime = (time) => { + const MINUTE = 60; + const HOUR = MINUTE * 60; + + if (time > 24 * HOUR) return ""; + + const hours = Math.round(time / HOUR); + const minutes = Math.round((time - hours * HOUR) / MINUTE); + + const hoursDisplay = hours > 0 ? `${hours}h ` : ""; + const minutesDisplay = minutes > 0 ? `${minutes}m ` : ""; + + return `${hoursDisplay}${minutesDisplay}`; +}; + +export const getBatteryTime = () => { + const timeRemaining = Battery.timeRemaining; + return timeRemaining > 0 && toTime(timeRemaining) != "" + ? `${toTime(timeRemaining)}remaining` + : ""; +}; + +export const getBatteryPercentage = () => { + const percent = Battery.percent; + return percent > 0 && percent < 100 ? `${percent}%` : ""; +}; + +export const getBatteryTooltip = () => { + const time = getBatteryTime(); + const percent = Battery.percent; + + return `${percent}% | ${time}`; +}; + +export const getBatteryIcon = () => { + // if Battery.percent is not between 0 and 100, handle the error + if (Battery.percent < 0 || Battery.percent > 100) + return "Battery percentage is not a valid value!"; + + const icons = [ + ["󰂎", "󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"], + ["󰢟", "󰢜", "󰂆", "󰂇", "󰂈", "󰢝", "󰂉", "󰢞", "󰂊", "󰂋", "󰂅"], + ]; + + const chargingIndex = Battery.charging ? 1 : 0; + const percentIndex = Math.floor(Battery.percent / 10); + return icons[chargingIndex][percentIndex].toString(); +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/bluetooth.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/bluetooth.js new file mode 100644 index 0000000..cea1a11 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/bluetooth.js @@ -0,0 +1,53 @@ +import { Bluetooth, Icons } from "../imports.js"; + +export const getBluetoothDevice = (addr) => + Bluetooth.getDevice(addr).alias ?? Bluetooth.getDevice(addr).name; + +export const getBluetoothIcon = (connected) => { + if (!Bluetooth.enabled) return Icons.bluetooth.disabled; + if (connected.length > 0) return Icons.bluetooth.active; + return Icons.bluetooth.disconnected; +}; + +export const getBluetoothTooltip = (connected) => { + if (!Bluetooth.enabled) return "Bluetooth off"; + + if (connected.length > 0) { + const dev = Bluetooth.getDevice(connected[0].address); + let battery_str = ""; + + if (dev.battery_percentage > 0) { + battery_str += ` ${dev.battery_percentage}%`; + } + + return dev.name + battery_str; + } + + return "Bluetooth on"; +}; + +export const getBluetoothClass = (connected) => { + if (!Bluetooth.enabled) return "bluetooth-disabled"; + + if (connected.length > 0) { + const dev = Bluetooth.getDevice(connected.at(0).address); + + if (dev.battery_percentage <= 25) return "bluetooth-active-low-battery"; + + if (dev.battery_percentage > 25) return "bluetooth-paired"; + } + + return "bluetooth-active"; +}; + +export const getBluetoothLabel = (connected) => { + if (!Bluetooth.enabled) return "󰂲"; + + if (connected.length > 0) { + const dev = Bluetooth.getDevice(connected.at(0).address); + + if (dev.battery_percentage <= 25) return "󰥇"; + } + + return "󰂰"; +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/desktop.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/desktop.js new file mode 100644 index 0000000..068be76 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/desktop.js @@ -0,0 +1,36 @@ +import { Widget } from "../imports.js"; +import { queryExact } from "./global.js"; +const { Box, Icon, Label, Button } = Widget; + +/** + * Builds a desktop item with a specific name and label. + * It uses the `queryExact` function to find the exact application based on its name. + * Then, it creates a button widget with the application's icon and label. + * When the button is clicked, it launches the application. + * + * @function buildDesktopItem + * @param {string} name - The name of the application. + * @param {string} label - The label of the desktop item. + * @returns {Object} The desktop item widget. + */ +export const buildDesktopItem = (name, label) => { + const app = queryExact(name); + return Button({ + className: "desktopIcon", + cursor: "pointer", + onClicked: () => app.launch(), + child: Box({ + vertical: true, + children: [ + Icon({ + icon: app.iconName, + size: 48, + }), + Label({ + className: "desktopIconLabel", + label, + }), + ], + }), + }); +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/global.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/global.js new file mode 100644 index 0000000..ed0b07d --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/global.js @@ -0,0 +1,38 @@ +import { Applications, Utils } from "../imports.js"; +const { execAsync } = Utils; +const { list, query } = Applications; + +/** + * Queries the exact application based on its name. + * First tries to find the application in the list of applications. + * If it doesn't find it, then it queries the application by its name. + * + * @function queryExact + * @param {string} appName - The name of the application to query. + * @returns {Object} The queried application object. Returns null if the application is not found. + */ +export function queryExact(appName) { + return ( + list.filter( + (app) => app.name.toLowerCase() === appName.toLowerCase(), + )[0] ?? query(appName)[0] + ); +} + +/** + * Tries to launch an application based on its name. + * First it tries to kill the application if it's already running. + * Regardless of whether the killing has been successful or not, it + * tries to launch the application. + * + * @function launchApp + * @param {string} appName - The name of the application to launch. + * @returns {void} + */ +export function launchApp(appName) { + if (queryExact(appName)) { + execAsync(["sh", "-c", `killall ${appName}`]); + } + + execAsync(["sh", "-c", `${appName}`]); +} diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/hyprland.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/hyprland.js new file mode 100644 index 0000000..2752c6e --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/hyprland.js @@ -0,0 +1,12 @@ +import { Hyprland } from "../imports.js"; + +export const getFocusedWorkspace = (self) => + self.children.forEach((btn) => { + btn.className = + btn.attribute.index === Hyprland.active.workspace.id + ? "focused" + : ""; + btn.visible = Hyprland.workspaces.some( + (ws) => ws.id === btn.attribute.index, + ); + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/icons.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/icons.js new file mode 100644 index 0000000..e444e5a --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/icons.js @@ -0,0 +1,56 @@ +export default { + bluetooth: { + active: "bluetooth-active-symbolic", + disabled: "bluetooth-disabled-symbolic", + disconnected: "bluetooth-disconnected-symbolic", + }, + + brightness: "display-brightness-symbolic", + + media: { + play: "media-playback-start-symbolic", + pause: "media-playback-pause-symbolic", + next: "media-skip-forward-symbolic", + previous: "media-skip-backward-symbolic", + player: "multimedia-player-symbolic", + }, + + volume: { + muted: "audio-volume-muted-symbolic", + low: "audio-volume-low-symbolic", + medium: "audio-volume-medium-symbolic", + high: "audio-volume-high-symbolic", + overamplified: "audio-volume-overamplified-symbolic", + }, + + speaker: { + overamplified: "\uf14b", + high: "\ue050", + medium: "\ue04d", + low: "\ue04e", + muted: "\ue04f", + }, + + microphone: { + overamplified: "\ue029", + high: "\ue029", + medium: "\ue029", + low: "\ue029", + muted: "\ue02b", + }, + + wired: { + power: "󰈀", + poweroff: "󱘖", + }, + + wifi: { + none: "󰤭", + bad: "󰤠", + low: "󰤟", + normal: "󰤢", + good: "󰤨", + }, + + powerButton: "system-shutdown-symbolic", +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/launcher.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/launcher.js new file mode 100644 index 0000000..468b6a6 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/launcher.js @@ -0,0 +1,3 @@ +export const getLauncherIcon = (self, windowName, visible) => { + windowName === "launcher" && (self.child.label = visible ? "󱢡" : "󱢦"); +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/mpris.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/mpris.js new file mode 100644 index 0000000..4861b4d --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/mpris.js @@ -0,0 +1,46 @@ +import { Icons, Utils } from "../imports.js"; +import GLib from "gi://GLib"; + +export const findPlayer = (players) => { + // try to get the first active player + const activePlayer = players.find((p) => p.playBackStatus == "Playing"); + if (activePlayer != null) return activePlayer; + + // otherwise get the first "working" player + for (const p of players) { + if (p.title != "undefined") return p; + } +}; + +export const mprisStateIcon = (status) => { + const state = status == "Playing" ? "pause" : "play"; + return Icons.media[state]; +}; + +export const MEDIA_CACHE_PATH = Utils.CACHE_DIR + "/media"; +export const blurredPath = MEDIA_CACHE_PATH + "/blurred"; + +export const generateBackground = (cover_path) => { + const url = cover_path; + if (!url) return ""; + + const makeBg = (bg) => `background: center/cover url('${bg}')`; + + const blurred = blurredPath + url.substring(MEDIA_CACHE_PATH.length); + + if (GLib.file_test(blurred, GLib.FileTest.EXISTS)) { + return makeBg(blurred); + } + + Utils.ensureDirectory(blurredPath); + Utils.exec(`convert ${url} -blur 0x22 ${blurred}`); + + return makeBg(blurred); +}; + +export function lengthStr(length) { + const min = Math.floor(length / 60); + const sec = Math.floor(length % 60); + const sec0 = sec < 10 ? "0" : ""; + return `${min}:${sec0}${sec}`; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/network.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/network.js new file mode 100644 index 0000000..bf8f575 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/network.js @@ -0,0 +1,40 @@ +import { Network } from "../imports.js"; + +import { Icon } from "../icons.js"; +const { wifi, wired } = Icon; + +export const getWifiIcon = (strength) => { + if (strength < 0.1) return wifi.none; + if (strength < 0.26) return wifi.bad; + if (strength < 0.51) return wifi.low; + if (strength < 0.76) return wifi.normal; + if (strength > 0.76) return wifi.good; + else return wifi.none; +}; + +export const getWifiTooltip = (strength, ssid) => { + const wifi = Network.wifi; + const wifiStrength = `Strength: ${strength * 100}`; + + switch (wifi.internet) { + case "connected": + return `Connected to ${ssid} | Strength: ${wifiStrength}`; + case "connecting": + return `Connecting to ${ssid} | Strength: ${wifiStrength}`; + case "disconnected": + return `Disconnected from ${ssid} | Strength: ${wifiStrength}`; + default: + return `No connection | Strength: ${wifiStrength}`; + } +}; + +export const getWiredIcon = (internet) => { + if (internet === "connected") return wired.power; + if (internet === "connecting") return wired.poweroff; + if (internet === "disconnected") return wired.poweroff; + return wired.poweroff; +}; + +export const getWiredTooltip = (internet) => { + return `Status: ${internet}`; +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/popupWindow.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/popupWindow.js new file mode 100644 index 0000000..97af0e2 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/popupWindow.js @@ -0,0 +1,53 @@ +import { App, Widget, Utils } from "../imports.js"; +const { Box, Revealer, Window } = Widget; + +export default ({ + onOpen = () => {}, + onClose = () => {}, + + name, + child, + transition = "slide_up", + transitionDuration = 250, + ...props +}) => { + const window = Window({ + name, + visible: false, + ...props, + + child: Box({ + css: ` + min-height: 2px; + min-width: 2px; + `, + child: Revealer({ + transition, + transitionDuration, + child: child || Box(), + setup: (self) => { + self.hook(App, (rev, currentName, isOpen) => { + if (currentName === name) { + rev.revealChild = isOpen; + + if (isOpen) { + onOpen(window); + } else { + Utils.timeout(transitionDuration, () => { + onClose(window); + }); + } + } + }); + }, + }), + }), + }); + window.getChild = () => window.child.children[0].child; + window.setChild = (newChild) => { + window.child.children[0].child = newChild; + window.child.children[0].show_all(); + }; + + return window; +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/swallow.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/swallow.js new file mode 100644 index 0000000..71405d0 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/swallow.js @@ -0,0 +1,25 @@ +import { App, Utils } from "../imports.js"; +const { exec, execAsync } = Utils; + +function genCommand(arg) { + return ["sh", "-c", `${App.configDir}/bin/hyprctl_swallow ${arg}`]; +} + +const swallowQuery = genCommand("query"); +const swallowToggle = genCommand("toggle"); + +export const getSwallowStatus = () => { + execAsync(swallowQuery); + + let result = exec("hyprctl -j getoption misc:enable_swallow"); + return JSON.parse(result).set; +}; + +export const status = Variable(getSwallowStatus()); + +export const toggleSwallowStatus = () => { + execAsync(swallowToggle); + + // toggle swallow status + status.value = !status.value; +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/tray.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/tray.js new file mode 100644 index 0000000..93c51b1 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/tray.js @@ -0,0 +1,17 @@ +import { Widget, SystemTray } from "../imports.js"; +const { Button, Icon } = Widget; + +export const getTrayItems = (self) => { + self.children = SystemTray.items.map((item) => + Button({ + className: "trayIcon", + child: Icon({ + setup: (self) => self.bind("icon", item, "icon"), + }), + setup: (self) => + self.bind("tooltip-markup", item, "tooltip-markup"), + onPrimaryClick: (_, event) => item.activate(event), + onSecondaryClick: (_, event) => item.openMenu(event), + }), + ); +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/utils/weather.js b/nyx/homes/notashelf/services/wayland/ags/js/utils/weather.js new file mode 100644 index 0000000..47b9ab5 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/utils/weather.js @@ -0,0 +1,15 @@ +import { Variable, App } from "../imports.js"; + +export const WeatherValue = Variable( + {}, + { + poll: [ + 36000, + ["sh", "-c", `python ${App.configDir}/bin/weather`], + (out) => JSON.parse(out), + ], + }, +); + +export const getWeatherIcon = (value) => value.text || "..."; +export const getWeatherTooltip = (value) => value.tooltip || "..."; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/index.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/index.js new file mode 100644 index 0000000..ddb5052 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/index.js @@ -0,0 +1,71 @@ +import { Widget } from "../../imports.js"; +const { Window, Box, CenterBox } = Widget; + +// Widgets +import { LauncherIcon } from "./modules/launcher.js"; +import { Workspaces } from "./modules/workspaces.js"; +import { Tray } from "./modules/tray.js"; +import { BatteryWidget } from "./modules/battery.js"; +import { Clock } from "./modules/clock.js"; +import { PowerMenu } from "./modules/power.js"; +import { Swallow } from "./modules/swallow.js"; +import { BluetoothWidget } from "./modules/bluetooth.js"; +import { AudioWidget } from "./modules/audio.js"; +import { NetworkWidget } from "./modules/network.js"; +import { SystemUsage } from "./modules/system.js"; +import { Weather } from "./modules/weather.js"; + +const Top = () => + Box({ + className: "barTop", + vertical: true, + vpack: "start", + children: [LauncherIcon(), SystemUsage(), Weather()], + }); + +const Center = () => + Box({ + className: "barCenter", + vertical: true, + children: [Workspaces()], + }); + +const Bottom = () => + Box({ + className: "barBottom", + vertical: true, + vpack: "end", + children: [ + Tray(), + Box({ + className: "utilsBox", + vertical: true, + children: [ + BluetoothWidget(), + AudioWidget(), + Swallow(), + BatteryWidget(), + NetworkWidget(), + ], + }), + Clock(), + PowerMenu(), + ], + }); + +export const Bar = ({ monitor } = {}) => + Window({ + name: "bar", + anchor: ["top", "bottom", "left"], + exclusivity: "exclusive", + layer: "top", + margins: [8, 0, 8, 8], + monitor, + child: CenterBox({ + className: "bar", + vertical: true, + startWidget: Top(), + centerWidget: Center(), + endWidget: Bottom(), + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/audio.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/audio.js new file mode 100644 index 0000000..2a102bc --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/audio.js @@ -0,0 +1,22 @@ +import { Audio, Widget } from "../../../imports.js"; +import { getAudioIcon } from "../../../utils/audio.js"; +import { launchApp } from "../../../utils/global.js"; + +const { Button, Icon } = Widget; + +const AudioIcon = () => + Icon({ + setup: (self) => { + self.hook(Audio, getAudioIcon, "speaker-changed"); + }, + }); + +export const AudioWidget = () => { + return Button({ + className: "audio", + cursor: "pointer", + visible: true, + child: AudioIcon(), + onClicked: () => launchApp("pavucontrol"), + }); +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/battery.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/battery.js new file mode 100644 index 0000000..d713639 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/battery.js @@ -0,0 +1,35 @@ +import { Widget, Battery } from "../../../imports.js"; +import { + getBatteryPercentage, + getBatteryTooltip, + getBatteryIcon, +} from "../../../utils/battery.js"; +const { Button, Box, Label, Revealer } = Widget; + +const BatIcon = () => + Label({ className: "batIcon" }) + // NOTE: label needs to be used instead of icon here + .bind("label", Battery, "percent", getBatteryIcon) + .bind("tooltip-text", Battery, "percent", getBatteryTooltip); + +const BatStatus = () => + Revealer({ + transition: "slide_down", + transition_duration: 200, + child: Label().bind("label", Battery, "percent", getBatteryPercentage), + }); + +export const BatteryWidget = () => + Button({ + onPrimaryClick: (self) => { + self.child.children[1].revealChild = + !self.child.children[1].revealChild; + }, + child: Box({ + className: "battery", + cursor: "pointer", + vertical: true, + children: [BatIcon(), BatStatus()], + visible: Battery.bind("available"), + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/bluetooth.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/bluetooth.js new file mode 100644 index 0000000..82f823c --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/bluetooth.js @@ -0,0 +1,29 @@ +import { Bluetooth, Widget, Utils } from "../../../imports.js"; +import { + getBluetoothIcon, + getBluetoothLabel, + getBluetoothClass, + getBluetoothTooltip, +} from "../../../utils/bluetooth.js"; +const { Button, Label } = Widget; + +const BluetoothModule = () => + Label({ className: "bluetoothIcon" }) + .bind("label", Bluetooth, "connected-devices", getBluetoothIcon) + .bind("class", Bluetooth, "connected-devices", getBluetoothClass) + .bind("label", Bluetooth, "connected-devices", getBluetoothLabel) + .bind( + "tooltip-text", + Bluetooth, + "connected-devices", + getBluetoothTooltip, + ); + +export const BluetoothWidget = () => + Button({ + className: "bluetooth", + cursor: "pointer", + child: BluetoothModule(), + visible: Bluetooth.connectedDevices.length > 0, + onClicked: () => Utils.exec("blueman-applet"), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/clock.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/clock.js new file mode 100644 index 0000000..ccad41d --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/clock.js @@ -0,0 +1,26 @@ +import { Widget, Utils } from "../../../imports.js"; +const { exec, execAsync } = Utils; +const { Label, Box } = Widget; + +const Time = () => + Label({ + className: "timeLabel", + setup: (self) => { + // the current quote syntax is the only one that works + // eslint-disable-next-line quotes + self.poll(1000, (self) => (self.label = exec('date "+%H%n%M"'))); + self.poll(1000, (self) => + execAsync(["date", "+%H%n%M"]) + .then((time) => (self.label = time)) + // eslint-disable-next-line no-undef + .catch(print.error), + ); + }, + }); + +export const Clock = () => + Box({ + className: "clock", + vertical: true, + children: [Time()], + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/launcher.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/launcher.js new file mode 100644 index 0000000..9479461 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/launcher.js @@ -0,0 +1,15 @@ +import { Widget, App } from "../../../imports.js"; +import { getLauncherIcon } from "../../../utils/launcher.js"; +const { Button, Label } = Widget; + +export const LauncherIcon = () => + Button({ + vexpand: false, + className: "launcherIcon", + cursor: "pointer", + child: Label("󱢦"), + onClicked: () => App.toggleWindow("launcher"), + setup: (self) => { + self.hook(App, getLauncherIcon, "window-toggled"); + }, + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/lock.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/lock.js new file mode 100644 index 0000000..a91109e --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/lock.js @@ -0,0 +1,10 @@ +import { Widget, Utils } from "../../../imports.js"; +const { Button, Label } = Widget; + +export const Lock = () => + Button({ + className: "lock", + cursor: "pointer", + child: Label(""), + onClicked: () => Utils.exec("swaylock"), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/network.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/network.js new file mode 100644 index 0000000..b6a08ea --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/network.js @@ -0,0 +1,34 @@ +import { Network, Widget, Utils } from "../../../imports.js"; +import { + getWifiIcon, + getWifiTooltip, + getWiredIcon, + getWiredTooltip, +} from "../../../utils/network.js"; +const { Stack, Button, Label } = Widget; + +const WifiIndicator = () => + Label({ has_tooltip: true }) + .bind("label", Network.wifi, "strength", getWifiIcon) + .bind("tooltip-text", Network.wifi, "strength", getWifiTooltip); + +const WiredIndicator = () => + Label({ cursor: "pointer" }) + .bind("label", Network.wired, "internet", getWiredIcon) + .bind("tooltip-text", Network.wired, "internet", getWiredTooltip); + +export const NetworkWidget = () => + Button({ + className: "network", + cursor: "pointer", + onClicked: () => Utils.exec("nm-connection-editor"), + child: Stack({ + shown: Network.bind("primary").as( + (/** @type {any} */ p) => p || "wifi", + ), + children: { + wifi: WifiIndicator(), + wired: WiredIndicator(), + }, + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/power.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/power.js new file mode 100644 index 0000000..32f4be6 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/power.js @@ -0,0 +1,10 @@ +import { Widget } from "../../../imports.js"; +const { Button, Label } = Widget; + +export const PowerMenu = () => + Button({ + vexpand: false, + className: "power", + cursor: "pointer", + child: Label(""), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/swallow.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/swallow.js new file mode 100644 index 0000000..a17fb98 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/swallow.js @@ -0,0 +1,15 @@ +import { Widget } from "../../../imports.js"; +const { Label, Button } = Widget; + +import { toggleSwallowStatus, status } from "../../../utils/swallow.js"; + +export const Swallow = () => + Button({ + className: "swallow", + cursor: "pointer", + tooltipText: `Swallow: ${status.value}`, + onPrimaryClick: toggleSwallowStatus, + child: Label({ + label: "󰊰", + }), + }).hook(status, (self) => (self.tooltipText = `${status.value}`)); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/system.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/system.js new file mode 100644 index 0000000..3ef8ca1 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/system.js @@ -0,0 +1,134 @@ +import { Variable, Widget } from "../../../imports.js"; +const { Button, Revealer, Box, Label, CircularProgress } = Widget; + +const getMemClass = (v) => { + const val = v * 100; + const className = [ + [100, "memCritical"], + [75, "memHigh"], + [35, "memMod"], + [5, "memLow"], + [0, "memIdle"], + [-1, "memRevealer"], + ].find(([threshold]) => threshold <= val)[1]; + + return className; +}; + +const getCpuClass = (v) => { + const val = v * 100; + + const className = [ + [100, "cpuCritical"], + [75, "cpuHigh"], + [35, "cpuMod"], + [5, "cpuLow"], + [0, "cpuIdle"], + [-1, "cpuRevealer"], + ].find(([threshold]) => threshold <= val)[1]; + + return className; +}; + +const divide = ([total, free]) => free / total; + +const cpu = Variable(0, { + poll: [ + 2000, + "top -b -n 1", + (out) => + divide([ + 100, + out + .split("\n") + .find((line) => line.includes("Cpu(s)")) + .split(/\s+/)[1] + .replace(",", "."), + ]), + ], +}); + +const mem = Variable(0, { + poll: [ + 2000, + "free", + (out) => + divide( + out + .split("\n") + .find((line) => line.includes("Mem:")) + .split(/\s+/) + .splice(1, 2), + ), + ], +}); + +/** + * @param {string} name + * @param {typeof cpu | typeof ram} process + * @param {Array} extraChildren + * @param {() => void} onPrimary + */ +const systemWidget = (name, process, extraChildren = [], onPrimary) => + Button({ + className: name + "Button", + onPrimaryClick: onPrimary, + child: Box({ + className: name, + vertical: true, + children: [ + CircularProgress({ + className: name + "Progress", + // binds: [["value", process]], + rounded: true, + inverted: false, + startAt: 0.27, + }).bind("value", process), + ...extraChildren, + ], + }), + }); + +const CPU = systemWidget( + "cpu", + cpu, + [ + Revealer({ + transition: "slide_down", + child: Label() + .bind("label", cpu, "value", (v) => `${Math.floor(v * 100)}%`) + .bind("className", cpu, "value", getCpuClass), + transition_duration: 250, + }), + ], + (self) => { + self.child.children[1].revealChild = + !self.child.children[1].revealChild; + }, +); + +const MEM = systemWidget( + "mem", + mem, + [ + Revealer({ + transition: "slide_down", + child: Label() + .bind("label", mem, "value", (v) => `${Math.floor(v * 100)}%`) + .bind("className", cpu, "value", getMemClass), + transition_duration: 250, + }), + ], + (self) => { + self.child.children[1].revealChild = + !self.child.children[1].revealChild; + }, +); + +export const SystemUsage = () => + Box({ + className: "systemUsage", + vertical: true, + cursor: "pointer", + children: [CPU, MEM], + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/tray.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/tray.js new file mode 100644 index 0000000..d5e0d3e --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/tray.js @@ -0,0 +1,40 @@ +import { Widget, SystemTray } from "../../../imports.js"; +import { getTrayItems } from "../../../utils/tray.js"; +const { Box, EventBox, Label, Revealer } = Widget; + +const RevIcon = () => + Label({ + className: "trayChevron", + label: "", + }); + +const TrayItems = () => + Box({ + className: "trayIcons", + vertical: true, + setup: (self) => { + self.hook(SystemTray, getTrayItems); + }, + }); + +export const Tray = () => + EventBox({ + onPrimaryClick: (self) => { + self.child.children[0].label = self.child.children[1].revealChild + ? "" + : ""; + self.child.children[1].revealChild = + !self.child.children[1].revealChild; + }, + child: Box({ + className: "tray", + vertical: true, + children: [ + RevIcon(), + Revealer({ + transition: "slide_up", + child: TrayItems(), + }), + ], + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/weather.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/weather.js new file mode 100644 index 0000000..25a2692 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/weather.js @@ -0,0 +1,24 @@ +import { Widget } from "../../../imports.js"; +import { + WeatherValue, + getWeatherIcon, + getWeatherTooltip, +} from "../../../utils/weather.js"; +const { Label } = Widget; + +const weatherWidget = () => + Label({ + hexpand: false, + vexpand: false, + class_name: "weather", + setup: (self) => { + self.bind("label", WeatherValue, "value", getWeatherIcon); + self.bind("tooltip-text", WeatherValue, "value", getWeatherTooltip); + }, + }); + +export const Weather = () => + Widget.CenterBox({ + vertical: true, + centerWidget: weatherWidget(), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/workspaces.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/workspaces.js new file mode 100644 index 0000000..ed164b9 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/bar/modules/workspaces.js @@ -0,0 +1,25 @@ +import { Widget, Hyprland } from "../../../imports.js"; +import { getFocusedWorkspace } from "../../../utils/hyprland.js"; +const { Box, Button } = Widget; +const { messageAsync } = Hyprland; + +export const Workspaces = () => + Box({ + className: "workspaces", + child: Box({ + vertical: true, + children: Array.from({ length: 10 }, (_, i) => i + 1).map((i) => + Button({ + cursor: "pointer", + attribute: { index: i }, + onClicked: () => messageAsync(`dispatch workspace ${i}`), + onSecondaryClick: () => + messageAsync(`dispatch movetoworkspacesilent ${i}`), + }), + ), + + setup: (self) => { + self.hook(Hyprland, getFocusedWorkspace); + }, + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/desktopIcons.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/desktopIcons.js new file mode 100644 index 0000000..ce60fca --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/desktopIcons.js @@ -0,0 +1,11 @@ +import { Widget } from "../../imports.js"; +const { Box } = Widget; + +export const DesktopIcons = () => + Box({ + className: "desktopIcons", + vertical: true, + hpack: "start", + vpack: "start", + children: [], + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/desktopMenu.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/desktopMenu.js new file mode 100644 index 0000000..6f9bc24 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/desktopMenu.js @@ -0,0 +1,98 @@ +import { Widget, Utils } from "../../imports.js"; +const { Box, EventBox, Label, MenuItem, Menu } = Widget; +const { exec, execAsync } = Utils; + +/** + * Creates a menu item with an icon. + * @param {string} icon - The icon to display for the menu item. + * @param {string} itemLabel - The label for the menu item. + * @param {Function} onClick - The function to be executed when the menu item is activated. + * @returns {Object} A menu item object with the specified icon, label, and click action. + */ +function ItemWithIcon(icon, itemLabel, onClick) { + return MenuItem({ + className: "desktopMenuItem", + child: Box({ + children: [ + Label({ + className: "desktopMenuItemIcon", + label: icon, + }), + Label(itemLabel), + ], + }), + onActivate: onClick, + }); +} + +const Separator = () => + MenuItem({ + child: Box({ + className: "separator", + css: ` + min-height: 1px; + margin: 3px 6px; + `, + }), + }); + +const rioMenu = () => { + return [ + ItemWithIcon("󰆍", "Terminal", () => + exec( + 'sh -c "$HOME/.config/ags/bin/open_window `slurp -d -c 999999 -w 2` foot"', + ), + ), + ItemWithIcon("󰘖", "Resize", () => + exec( + 'sh -c "$HOME/.config/ags/bin/move_window `slurp -d -c 999999 -w 2`"', + ), + ), + ItemWithIcon("󰁁", "Move", () => exec("hyprctl dispatch submap move")), + ItemWithIcon("󰅖", "Delete", () => exec("hyprctl kill")), + Separator(), + ]; +}; + +const Powermenu = () => { + return MenuItem({ + className: "desktopMenuItem", + child: Box({ + children: [ + Label({ + className: "desktopMenuItemIcon", + label: "󰐥", + }), + Label("Powermenu"), + ], + }), + submenu: Menu({ + className: "desktopMenu", + children: [ + ItemWithIcon("󰍁", "Lock", () => Utils.exec("gtklock")), + ItemWithIcon("󰍃", "Log Out", () => + exec("hyprctl dispatch exit"), + ), + ItemWithIcon("󰖔", "Suspend", () => exec("systemctl suspend")), + ItemWithIcon("󰜉", "Reboot", () => exec("systemctl reboot")), + ItemWithIcon("󰐥", "Shutdown", () => exec("systemctl poweroff")), + ], + }), + }); +}; + +export const DesktopMenu = () => + EventBox({ + onSecondaryClick: (_, event) => + Menu({ + className: "desktopMenu", + children: [ + ...rioMenu(), + ItemWithIcon("󰈊", "Colorpicker", () => + execAsync(["hyprpicker", "-a", "wl-copy"]), + ), + Separator(), + Powermenu(), + ], + }).popup_at_pointer(event), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/index.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/index.js new file mode 100644 index 0000000..69b1826 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/desktop/index.js @@ -0,0 +1,17 @@ +import { Widget } from "../../imports.js"; +const { Window } = Widget; + +import { DesktopMenu } from "./desktopMenu.js"; +import { DesktopIcons } from "./desktopIcons.js"; + +export const Desktop = ({ monitor } = {}) => + Window({ + name: "desktop", + anchor: ["top", "bottom", "left", "right"], + layer: "bottom", + monitor, + child: Widget.Overlay({ + child: DesktopMenu(), + overlays: [DesktopIcons()], + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/launcher/index.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/launcher/index.js new file mode 100644 index 0000000..bff4d08 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/launcher/index.js @@ -0,0 +1,113 @@ +import { Widget, App, Applications, Utils, Hyprland } from "../../imports.js"; +import PopupWindow from "../../utils/popupWindow.js"; +const { Box, Button, Icon, Label, Scrollable, Entry } = Widget; + +const WINDOW_NAME = "launcher"; + +const truncateString = (str, maxLength) => + str.length > maxLength ? `${str.slice(0, maxLength)}...` : str; + +const AppItem = (app) => + Button({ + className: "launcherApp", + onClicked: () => { + App.closeWindow(WINDOW_NAME); + Hyprland.messageAsync(`dispatch exec gtk-launch ${app.desktop}`); + ++app.frequency; + }, + setup: (self) => (self.app = app), + child: Box({ + children: [ + Icon({ + className: "launcherItemIcon", + icon: app.iconName || "", + size: 24, + }), + Box({ + className: "launcherItem", + vertical: true, + vpack: "center", + children: [ + Label({ + className: "launcherItemTitle", + label: app.name, + xalign: 0, + vpack: "center", + truncate: "end", + }), + !!app.description && + Widget.Label({ + className: "launcherItemDescription", + label: + truncateString(app.description, 75) || "", + wrap: true, + xalign: 0, + justification: "left", + vpack: "center", + }), + ], + }), + ], + }), + }); + +const Launcher = () => { + const list = Box({ vertical: true }); + + const entry = Entry({ + className: "launcherEntry", + hexpand: true, + text: "-", + onAccept: ({ text }) => { + const isCommand = text.startsWith(">"); + const appList = Applications.query(text || ""); + if (isCommand === true) { + App.toggleWindow(WINDOW_NAME); + Utils.execAsync(text.slice(1)); + } else if (appList[0]) { + App.toggleWindow(WINDOW_NAME); + appList[0].launch(); + } + }, + onChange: ({ text }) => + list.children.map((item) => { + item.visible = item.app.match(text); + }), + }); + + return Widget.Box({ + className: "launcher", + vertical: true, + setup: (self) => { + self.hook(App, (_, name, visible) => { + if (name !== WINDOW_NAME) return; + + list.children = Applications.list.map(AppItem); + + entry.text = ""; + if (visible) entry.grab_focus(); + }); + }, + children: [ + entry, + Scrollable({ + hscroll: "never", + css: "min-width: 250px; min-height: 360px;", + child: list, + }), + ], + }); +}; + +export const AppLauncher = () => + PopupWindow({ + name: WINDOW_NAME, + anchor: ["top", "bottom", "right"], + margins: [13, 13, 0, 13], + layer: "overlay", + transition: "slide_down", + transitionDuration: 150, + popup: true, + keymode: "on-demand", + child: Launcher(), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/music/controls.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/controls.js new file mode 100644 index 0000000..759eb7a --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/controls.js @@ -0,0 +1,29 @@ +import { Icons, Widget } from "../../imports.js"; +import { mprisStateIcon } from "../../utils/mpris.js"; + +export default (player) => + Widget.CenterBox({ + className: "controls", + hpack: "center", + + startWidget: Widget.Button({ + onClicked: () => player.previous(), + child: Widget.Icon(Icons.media.previous), + }), + + centerWidget: Widget.Button({ + onClicked: () => player.playPause(), + + child: Widget.Icon().bind( + "icon", + player, + "play-back-status", + mprisStateIcon, + ), + }), + + endWidget: Widget.Button({ + onClicked: () => player.next(), + child: Widget.Icon(Icons.media.next), + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/music/cover.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/cover.js new file mode 100644 index 0000000..d6e1495 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/cover.js @@ -0,0 +1,9 @@ +import { Widget } from "../../imports.js"; + +export default (player) => + Widget.Box({ className: "cover" }).bind( + "css", + player, + "cover-path", + (cover) => `background-image: url('${cover ?? ""}')`, + ); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/music/index.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/index.js new file mode 100644 index 0000000..59e2ffa --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/index.js @@ -0,0 +1,45 @@ +import { Mpris, Widget } from "../../imports.js"; +import { findPlayer, generateBackground } from "../../utils/mpris.js"; +import PopupWindow from "./popup_window.js"; + +import Cover from "./cover.js"; +import { Artists, Title } from "./title_artists.js"; +import TimeInfo from "./time_info.js"; +import Controls from "./controls.js"; +import PlayerInfo from "./player_info.js"; + +const Info = (player) => + Widget.Box({ + className: "info", + vertical: true, + vexpand: false, + hexpand: false, + homogeneous: true, + + children: [ + PlayerInfo(player), + Title(player), + Artists(player), + Controls(player), + TimeInfo(player), + ], + }); + +const MusicBox = (player) => + Widget.Box({ + className: "music window", + children: [Cover(player), Info(player)], + }).bind("css", player, "cover-path", generateBackground); + +export const Media = () => + PopupWindow({ + monitor: 0, + anchor: ["top"], + layer: "top", + margins: [8, 0, 0, 0], + name: "music", + child: Widget.Box(), + }).bind("child", Mpris, "players", (players) => { + if (players.length == 0) return Widget.Box(); + return MusicBox(findPlayer(players)); + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/music/player_info.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/player_info.js new file mode 100644 index 0000000..3a7afb2 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/player_info.js @@ -0,0 +1,23 @@ +import { Icons, Utils, Widget } from "../../imports.js"; + +export default (player) => + Widget.Box({ + className: "player-info", + vexpand: true, + vpack: "start", + + children: [ + Widget.Icon({ + hexpand: true, + hpack: "end", + className: "player-icon", + tooltipText: player.identity ?? "", + }).bind("icon", player, "entry", (entry) => { + // the Spotify icon is called spotify-client + if (entry == "spotify") entry = "spotify-client"; + return Utils.lookUpIcon(entry ?? "") + ? entry + : Icons.media.player; + }), + ], + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/music/popup_window.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/popup_window.js new file mode 100644 index 0000000..ed48d0b --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/popup_window.js @@ -0,0 +1,46 @@ +import App from "resource:///com/github/Aylur/ags/app.js"; +import { Widget } from "../../imports.js"; +const { Box, Revealer, Window } = Widget; + +export default ({ + name, + child, + revealerSetup = null, + transition = "crossfade", + transitionDuration = 200, + ...props +}) => { + const window = Window({ + name, + popup: false, + focusable: false, + visible: false, + ...props, + + setup: (self) => (self.getChild = () => child), + + child: Box({ + css: ` + min-height: 1px; + min-width: 1px; + padding: 1px; + `, + child: Revealer({ + transition, + transitionDuration, + child: child, + + setup: + revealerSetup ?? + ((self) => + self.hook(App, (self, currentName, visible) => { + if (currentName === name) { + self.reveal_child = visible; + } + })), + }), + }), + }); + + return window; +}; diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/music/time_info.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/time_info.js new file mode 100644 index 0000000..43c3f6b --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/time_info.js @@ -0,0 +1,67 @@ +import { Widget } from "../../imports.js"; +import { lengthStr } from "../../utils/mpris.js"; + +export const PositionLabel = (player) => + Widget.Label({ + className: "position", + hexpand: true, + xalign: 0, + + setup: (self) => { + const update = (_, time) => { + player.length > 0 + ? (self.label = lengthStr(time || player.position)) + : (self.visible = !!player); + }; + + self.hook(player, update, "position").poll(1000, update); + }, + }); + +export const LengthLabel = (player) => + Widget.Label({ + className: "length", + hexpand: true, + xalign: 1, + }) + .bind("visible", player, "length", (length) => length > 0) + .bind("label", player, "length", (length) => lengthStr(length)); + +export const Position = (player) => + Widget.Slider({ + className: "position", + draw_value: false, + + onChange: ({ value }) => (player.position = player.length * value), + + setup: (self) => { + const update = () => { + if (self.dragging) return; + + self.visible = player.length > 0; + + if (player.length > 0) { + self.value = player.position / player.length; + } + }; + + self.hook(player, update) + .hook(player, update, "position") + .poll(1000, update); + }, + }); + +export default (player) => + Widget.Box({ + vertical: true, + vexpand: true, + vpack: "end", + + children: [ + Widget.Box({ + hexpand: true, + children: [PositionLabel(player), LengthLabel(player)], + }), + Position(player), + ], + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/music/title_artists.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/title_artists.js new file mode 100644 index 0000000..bf0e691 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/music/title_artists.js @@ -0,0 +1,32 @@ +import { Widget } from "../../imports.js"; + +export const Title = (player) => + Widget.Scrollable({ + className: "title", + vscroll: "never", + hscroll: "automatic", + + child: Widget.Label({ + className: "title", + label: "Nothing playing", + }).bind( + "label", + player, + "track-title", + (title) => title ?? "Nothing playing", + ), + }); + +export const Artists = (player) => + Widget.Scrollable({ + className: "artists", + vscroll: "never", + hscroll: "automatic", + + child: Widget.Label({ className: "artists" }).bind( + "label", + player, + "track-artists", + (artists) => artists.join(", ") ?? "", + ), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/notifications/index.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/notifications/index.js new file mode 100644 index 0000000..ed349b1 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/notifications/index.js @@ -0,0 +1,134 @@ +import { Hyprland, Notifications, Utils, Widget } from "../../imports.js"; +const { Box, Icon, Label, Button, EventBox, Window } = Widget; +const { lookUpIcon } = Utils; + +const closeAll = () => { + Notifications.popups.map((n) => n.dismiss()); +}; + +const NotificationIcon = ({ app_entry, app_icon, image }) => { + if (image) { + return Box({ + css: ` + background-image: url("${image}"); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + `, + }); + } + + if (lookUpIcon(app_icon)) { + return Icon(app_icon); + } + + if (app_entry && lookUpIcon(app_entry)) { + return Icon(app_entry); + } + + return null; +}; + +const Notification = (notif) => { + const icon = Box({ + vpack: "start", + class_name: "icon", + // @ts-ignore + setup: (/** @type {{ child: any; }} */ self) => { + const icon = NotificationIcon(notif); + if (icon !== null) self.child = icon; + }, + }); + + const title = Label({ + class_name: "title", + xalign: 0, + justification: "left", + hexpand: true, + max_width_chars: 24, + truncate: "end", + wrap: true, + label: notif.summary, + use_markup: true, + }); + + const body = Label({ + class_name: "body", + hexpand: true, + use_markup: true, + xalign: 0, + justification: "left", + max_width_chars: 100, + wrap: true, + label: notif.body, + }); + + const actions = Box({ + class_name: "actions", + children: notif.actions + .filter(({ id }) => id != "default") + .map(({ id, label }) => + Button({ + class_name: "action-button", + on_clicked: () => notif.invoke(id), + hexpand: true, + child: Label(label), + }), + ), + }); + + return EventBox({ + on_primary_click: () => { + if (notif.actions.length > 0) notif.invoke(notif.actions[0].id); + }, + on_middle_click: closeAll, + on_secondary_click: () => notif.dismiss(), + child: Box({ + class_name: `notification ${notif.urgency}`, + vertical: true, + + children: [ + Box({ + class_name: "info", + children: [ + icon, + Box({ + vertical: true, + class_name: "text", + vpack: "center", + + setup: (self) => { + if (notif.body.length > 0) + self.children = [title, body]; + else self.children = [title]; + }, + }), + ], + }), + actions, + ], + }), + }); +}; + +let lastMonitor; +export const Notifs = () => + Window({ + name: "notifications", + anchor: ["top", "right"], + margins: [8, 8, 8, 0], + child: Box({ + css: "padding: 1px;", + class_name: "notifications", + vertical: true, + // @ts-ignore + children: Notifications.bind("popups").transform((popups) => { + return popups.map(Notification); + }), + }), + }).hook(Hyprland.active, (self) => { + // prevent useless resets + if (lastMonitor === Hyprland.active.monitor) return; + + self.monitor = Hyprland.active.monitor.id; + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/brightnessPopup.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/brightnessPopup.js new file mode 100644 index 0000000..ec828fc --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/brightnessPopup.js @@ -0,0 +1,58 @@ +import { Widget, Utils } from "../../imports.js"; +import Brightness from "../../services/brightness.js"; +const { Box, Slider, Label, Revealer } = Widget; + +const BrightnessIcon = () => + Label({ + className: "brtPopupIcon", + setup: (self) => { + self.hook(Brightness, (self) => { + const icons = ["", "", "", "", "", "", "", "", ""]; + + let index = Math.floor((Brightness.screen * 100) / 11); + index = Math.max(0, Math.min(index, icons.length - 1)); + + if (index >= 0 && index < icons.length) { + self.label = icons[index].toString(); + } else { + log("Index out of bounds:", index); + } + }); + }, + }); + +const PercentBar = () => + Slider({ + className: "brtPopupBar", + drawValue: false, + onChange: ({ value }) => (Brightness.screen = value), + setup: (self) => { + self.hook(Brightness, (self) => (self.value = Brightness.screen)); + }, + }); + +export const BrightnessPopup = () => + Box({ + css: `min-height: 1px; + min-width: 1px;`, + child: Revealer({ + transition: "slide_up", + child: Box({ + className: "brightnessPopup", + children: [BrightnessIcon(), PercentBar()], + }), + attribute: { count: 0 }, + setup: (self) => { + self.hook(Brightness, (self) => { + self.revealChild = true; + self.attribute.count++; + Utils.timeout(1500, () => { + self.attribute.count--; + + if (self.attribute.count === 0) + self.revealChild = false; + }); + }); + }, + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/index.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/index.js new file mode 100644 index 0000000..307c9ee --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/index.js @@ -0,0 +1,18 @@ +import { Widget } from "../../imports.js"; + +// Widgets +import { BrightnessPopup } from "./brightnessPopup.js"; +import { VolumePopup } from "./volumePopup.js"; + +export const Popups = () => + Widget.Window({ + name: "popups", + className: "popups", + anchor: ["bottom", "right"], + layer: "overlay", + margins: [0, 12, 8, 0], + child: Widget.Box({ + vertical: true, + children: [BrightnessPopup(), VolumePopup()], + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/volumePopup.js b/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/volumePopup.js new file mode 100644 index 0000000..df8b928 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/js/windows/popups/volumePopup.js @@ -0,0 +1,36 @@ +import { Widget, Utils, Audio } from "../../imports.js"; +import { getSliderIcon, volumePercentBar } from "../../utils/audio.js"; +const { Box, Revealer } = Widget; +const { speaker } = Audio; +const { timeout } = Utils; + +export const VolumePopup = () => + Box({ + css: ` + min-height: 2px; + min-width: 2px; + `, + child: Revealer({ + transition: "slide_up", + child: Box({ + className: "volumePopup", + children: [getSliderIcon(), volumePercentBar()], + }), + attribute: { count: 0 }, + setup: (self) => + self.hook( + speaker, + () => { + self.reveal_child = true; + self.attribute.count++; + timeout(1500, () => { + self.attribute.count--; + + if (self.attribute.count === 0) + self.reveal_child = false; + }); + }, + "notify::volume", + ), + }), + }); diff --git a/nyx/homes/notashelf/services/wayland/ags/package.json b/nyx/homes/notashelf/services/wayland/ags/package.json new file mode 100644 index 0000000..f4c80cd --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/package.json @@ -0,0 +1,18 @@ +{ + "name": "nyx-ags", + "version": "1.5.5", + "author": "NotAShelf", + "description": "The ags configuretion segment of my NixOS configurations.", + "main": "config.js", + "scripts": { + "lint": "eslint . --fix", + "stylelint": "stylelint ./scss --fix", + "all": "nix-shell -p nodejs --run \"npm install\" && npm run lint && npm run stylelint && rm -rf node_modules" + }, + "devDependencies": { + "stylelint-config-standard-scss": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^5.33.0", + "@typescript-eslint/parser": "^5.33.0", + "eslint": "^8.44.0" + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/pnpm-lock.yaml b/nyx/homes/notashelf/services/wayland/ags/pnpm-lock.yaml new file mode 100644 index 0000000..f35ebbf --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/pnpm-lock.yaml @@ -0,0 +1,1709 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +devDependencies: + '@typescript-eslint/eslint-plugin': + specifier: ^5.33.0 + version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/parser': + specifier: ^5.33.0 + version: 5.62.0(eslint@8.57.0)(typescript@5.3.3) + eslint: + specifier: ^8.44.0 + version: 8.57.0 + stylelint-config-standard-scss: + specifier: ^10.0.0 + version: 10.0.0(postcss@8.4.35)(stylelint@15.11.0) + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@csstools/css-parser-algorithms@2.6.0(@csstools/css-tokenizer@2.2.3): + resolution: {integrity: sha512-YfEHq0eRH98ffb5/EsrrDspVWAuph6gDggAE74ZtjecsmyyWpW768hOyiONa8zwWGbIWYfa2Xp4tRTrpQQ00CQ==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-tokenizer': ^2.2.3 + dependencies: + '@csstools/css-tokenizer': 2.2.3 + dev: true + + /@csstools/css-tokenizer@2.2.3: + resolution: {integrity: sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg==} + engines: {node: ^14 || ^16 || >=18} + dev: true + + /@csstools/media-query-list-parser@2.1.8(@csstools/css-parser-algorithms@2.6.0)(@csstools/css-tokenizer@2.2.3): + resolution: {integrity: sha512-DiD3vG5ciNzeuTEoh74S+JMjQDs50R3zlxHnBnfd04YYfA/kh2KiBCGhzqLxlJcNq+7yNQ3stuZZYLX6wK/U2g==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-parser-algorithms': ^2.6.0 + '@csstools/css-tokenizer': ^2.2.3 + dependencies: + '@csstools/css-parser-algorithms': 2.6.0(@csstools/css-tokenizer@2.2.3) + '@csstools/css-tokenizer': 2.2.3 + dev: true + + /@csstools/selector-specificity@3.0.2(postcss-selector-parser@6.0.15): + resolution: {integrity: sha512-RpHaZ1h9LE7aALeQXmXrJkRG84ZxIsctEN2biEUmFyKpzFM3zZ35eUMcIzZFsw/2olQE6v69+esEqU2f1MKycg==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss-selector-parser: ^6.0.13 + dependencies: + postcss-selector-parser: 6.0.15 + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.2 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + dev: true + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/minimist@1.2.5: + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + dev: true + + /@types/normalize-package-data@2.4.4: + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + dev: true + + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + dev: true + + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.3.3) + debug: 4.3.4 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare-lite: 1.4.0 + semver: 7.6.0 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3) + debug: 4.3.4 + eslint: 8.57.0 + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + dev: true + + /@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.3.3) + debug: 4.3.4 + eslint: 8.57.0 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.3.3): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.6.0 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.3.3): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3) + eslint: 8.57.0 + eslint-scope: 5.1.1 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /acorn-jsx@5.3.2(acorn@8.11.3): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.3 + dev: true + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + dev: true + + /astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /balanced-match@2.0.0: + resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase-keys@7.0.2: + resolution: {integrity: sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==} + engines: {node: '>=12'} + dependencies: + camelcase: 6.3.0 + map-obj: 4.3.0 + quick-lru: 5.1.1 + type-fest: 1.4.0 + dev: true + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /cosmiconfig@8.3.6(typescript@5.3.3): + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + typescript: 5.3.3 + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /css-functions-list@3.2.1: + resolution: {integrity: sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==} + engines: {node: '>=12 || >=16'} + dev: true + + /css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.0.2 + dev: true + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /decamelize-keys@1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + dev: true + + /decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: true + + /decamelize@5.0.1: + resolution: {integrity: sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==} + engines: {node: '>=10'} + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 3.4.3 + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + dev: true + + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + dev: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.2.0 + dev: true + + /file-entry-cache@7.0.2: + resolution: {integrity: sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==} + engines: {node: '>=12.0.0'} + dependencies: + flat-cache: 3.2.0 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + dependencies: + global-prefix: 3.0.0 + dev: true + + /global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + dev: true + + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /globjoin@0.1.4: + resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /hasown@2.0.1: + resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + dependencies: + lru-cache: 6.0.0 + dev: true + + /html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + dev: true + + /ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.1 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + dev: true + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: true + + /known-css-properties@0.29.0: + resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==} + dev: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + dev: true + + /map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: true + + /mathml-tag-names@2.1.3: + resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + dev: true + + /mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: true + + /meow@10.1.5: + resolution: {integrity: sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + '@types/minimist': 1.2.5 + camelcase-keys: 7.0.2 + decamelize: 5.0.1 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 8.0.0 + redent: 4.0.0 + trim-newlines: 4.1.1 + type-fest: 1.4.0 + yargs-parser: 20.2.9 + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimist-options@4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /normalize-package-data@3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.13.1 + semver: 7.6.0 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.23.5 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /postcss-media-query-parser@0.2.3: + resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} + dev: true + + /postcss-resolve-nested-selector@0.1.1: + resolution: {integrity: sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==} + dev: true + + /postcss-safe-parser@6.0.0(postcss@8.4.35): + resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.3.3 + dependencies: + postcss: 8.4.35 + dev: true + + /postcss-scss@4.0.9(postcss@8.4.35): + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + dependencies: + postcss: 8.4.35 + dev: true + + /postcss-selector-parser@6.0.15: + resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + + /postcss@8.4.35: + resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: true + + /read-pkg-up@8.0.0: + resolution: {integrity: sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==} + engines: {node: '>=12'} + dependencies: + find-up: 5.0.0 + read-pkg: 6.0.0 + type-fest: 1.4.0 + dev: true + + /read-pkg@6.0.0: + resolution: {integrity: sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==} + engines: {node: '>=12'} + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 3.0.3 + parse-json: 5.2.0 + type-fest: 1.4.0 + dev: true + + /redent@4.0.0: + resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==} + engines: {node: '>=12'} + dependencies: + indent-string: 5.0.0 + strip-indent: 4.0.0 + dev: true + + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.17 + dev: true + + /spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + dev: true + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.17 + dev: true + + /spdx-license-ids@3.0.17: + resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-indent@4.0.0: + resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} + engines: {node: '>=12'} + dependencies: + min-indent: 1.0.1 + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /style-search@0.1.0: + resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} + dev: true + + /stylelint-config-recommended-scss@12.0.0(postcss@8.4.35)(stylelint@15.11.0): + resolution: {integrity: sha512-5Bb2mlGy6WLa30oNeKpZvavv2lowJUsUJO25+OA68GFTemlwd1zbFsL7q0bReKipOSU3sG47hKneZ6Nd+ctrFA==} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^15.5.0 + peerDependenciesMeta: + postcss: + optional: true + dependencies: + postcss: 8.4.35 + postcss-scss: 4.0.9(postcss@8.4.35) + stylelint: 15.11.0(typescript@5.3.3) + stylelint-config-recommended: 12.0.0(stylelint@15.11.0) + stylelint-scss: 5.3.2(stylelint@15.11.0) + dev: true + + /stylelint-config-recommended@12.0.0(stylelint@15.11.0): + resolution: {integrity: sha512-x6x8QNARrGO2sG6iURkzqL+Dp+4bJorPMMRNPScdvaUK8PsynriOcMW7AFDKqkWAS5wbue/u8fUT/4ynzcmqdQ==} + peerDependencies: + stylelint: ^15.5.0 + dependencies: + stylelint: 15.11.0(typescript@5.3.3) + dev: true + + /stylelint-config-standard-scss@10.0.0(postcss@8.4.35)(stylelint@15.11.0): + resolution: {integrity: sha512-bChBEo1p3xUVWh/wenJI+josoMk21f2yuLDGzGjmKYcALfl2u3DFltY+n4UHswYiXghqXaA8mRh+bFy/q1hQlg==} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^15.5.0 + peerDependenciesMeta: + postcss: + optional: true + dependencies: + postcss: 8.4.35 + stylelint: 15.11.0(typescript@5.3.3) + stylelint-config-recommended-scss: 12.0.0(postcss@8.4.35)(stylelint@15.11.0) + stylelint-config-standard: 33.0.0(stylelint@15.11.0) + dev: true + + /stylelint-config-standard@33.0.0(stylelint@15.11.0): + resolution: {integrity: sha512-eyxnLWoXImUn77+ODIuW9qXBDNM+ALN68L3wT1lN2oNspZ7D9NVGlNHb2QCUn4xDug6VZLsh0tF8NyoYzkgTzg==} + peerDependencies: + stylelint: ^15.5.0 + dependencies: + stylelint: 15.11.0(typescript@5.3.3) + stylelint-config-recommended: 12.0.0(stylelint@15.11.0) + dev: true + + /stylelint-scss@5.3.2(stylelint@15.11.0): + resolution: {integrity: sha512-4LzLaayFhFyneJwLo0IUa8knuIvj+zF0vBFueQs4e3tEaAMIQX8q5th8ziKkgOavr6y/y9yoBe+RXN/edwLzsQ==} + peerDependencies: + stylelint: ^14.5.1 || ^15.0.0 + dependencies: + known-css-properties: 0.29.0 + postcss-media-query-parser: 0.2.3 + postcss-resolve-nested-selector: 0.1.1 + postcss-selector-parser: 6.0.15 + postcss-value-parser: 4.2.0 + stylelint: 15.11.0(typescript@5.3.3) + dev: true + + /stylelint@15.11.0(typescript@5.3.3): + resolution: {integrity: sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==} + engines: {node: ^14.13.1 || >=16.0.0} + hasBin: true + dependencies: + '@csstools/css-parser-algorithms': 2.6.0(@csstools/css-tokenizer@2.2.3) + '@csstools/css-tokenizer': 2.2.3 + '@csstools/media-query-list-parser': 2.1.8(@csstools/css-parser-algorithms@2.6.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/selector-specificity': 3.0.2(postcss-selector-parser@6.0.15) + balanced-match: 2.0.0 + colord: 2.9.3 + cosmiconfig: 8.3.6(typescript@5.3.3) + css-functions-list: 3.2.1 + css-tree: 2.3.1 + debug: 4.3.4 + fast-glob: 3.3.2 + fastest-levenshtein: 1.0.16 + file-entry-cache: 7.0.2 + global-modules: 2.0.0 + globby: 11.1.0 + globjoin: 0.1.4 + html-tags: 3.3.1 + ignore: 5.3.1 + import-lazy: 4.0.0 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.29.0 + mathml-tag-names: 2.1.3 + meow: 10.1.5 + micromatch: 4.0.5 + normalize-path: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.35 + postcss-resolve-nested-selector: 0.1.1 + postcss-safe-parser: 6.0.0(postcss@8.4.35) + postcss-selector-parser: 6.0.15 + postcss-value-parser: 4.2.0 + resolve-from: 5.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + style-search: 0.1.0 + supports-hyperlinks: 3.0.0 + svg-tags: 1.0.0 + table: 6.8.1 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-hyperlinks@3.0.0: + resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + engines: {node: '>=14.18'} + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + dev: true + + /svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + dev: true + + /table@6.8.1: + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} + engines: {node: '>=10.0.0'} + dependencies: + ajv: 8.12.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /trim-newlines@4.1.1: + resolution: {integrity: sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==} + engines: {node: '>=12'} + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tsutils@3.21.0(typescript@5.3.3): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 5.3.3 + dev: true + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: true + + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: true + + /which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/nyx/homes/notashelf/services/wayland/ags/shell.nix b/nyx/homes/notashelf/services/wayland/ags/shell.nix new file mode 100644 index 0000000..e6b6b31 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/shell.nix @@ -0,0 +1,28 @@ +{pkgs ? import {}}: let + # trivial builders + inherit (pkgs) mkShell writeShellScriptBin; +in + mkShell { + buildInputs = with pkgs; [ + nodejs-slim + # python3 w/ requests is necessary for weather data fetch + # ags actually doesn't start without it since it's stored + # as a variable + (python3.withPackages (ps: [ps.requests])) + + # while developing locally, you need types and other eslint deps + # so that our eslint config works properly + # pnpm is used to fetch the deps from package.json + nodePackages.pnpm + + # dart-sass is for compiling the stylesheets + dart-sass + (writeShellScriptBin "compile-stylesheet" '' + # compile scss files + ${dart-sass}/bin/sass --verbose \ + --style compressed \ + --no-source-map --fatal-deprecation --future-deprecation \ + ./style/main.scss > ./style.css + '') + ]; + } diff --git a/nyx/homes/notashelf/services/wayland/ags/style.css b/nyx/homes/notashelf/services/wayland/ags/style.css new file mode 100644 index 0000000..2d7f75b --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style.css @@ -0,0 +1 @@ +*{all:unset;text-shadow:0 2px 3px rgba(0,0,0,.2);font-family:"Material Design Icons","Iosevka Nerd Font Mono",Inter,Roboto,sans-serif}tooltip{border-radius:calc(12px + 2px);background:#1e1e2e}.launcherIcon{background:#313244;font-family:symbolsnerdfontmono;border-radius:12px;margin:6px 4px;padding:6px;min-height:1.5rem;transition:all .2s cubic-bezier(0.3, 0, 1, 1)}.launcherIcon:hover{background:#3c3d53}.systemUsage{color:#cdd6f4;background:#313244;font-family:symbolsnerdfontmono;border-radius:12px;margin:4px}.cpuButton{padding:6px 2px 3px 2px;margin:1px}.cpuProgress{color:#b4befe;padding:4px 4px;margin:.1rem;font-size:4px;background:#1e1e2e;min-height:1.2rem;min-width:1.2rem}.memButton{padding:3px 2px 6px 2px;margin:1px}.memProgress{color:#89b4fa;padding:4px 4px;margin:.1rem;font-size:4px;background:#1e1e2e;min-height:1.2rem;min-width:1.2rem}.weather{background:#313244;font-family:"Material Symbols Sharp",Roboto;border-radius:12px;margin:6px 4px;padding:4px;min-height:1.5rem;min-width:1rem;transition:all .2s cubic-bezier(0.3, 0, 1, 1)}.weather:hover{background:#3c3d53}.workspaces{background:rgba(0,0,0,0);padding:14px}.workspaces button{transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1);margin:6px 3px;color:#cdd6f4;background:#313244;margin:5px 3px;min-width:.6rem;min-height:.6rem;color:rgba(0,0,0,0);background:#cdd6f4;border-radius:99px}.workspaces button:hover{color:#b4befe}.workspaces button:hover{background:#b4befe}.workspaces button.focused{border-radius:18px;background:#89b4fa;padding:8px 0}.tray{margin:0}.trayChevron{font-family:symbolsnerdfontmono}.trayIcons{margin:3px 0 0}.trayIcon{margin:0 0 3px}.battery{transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1);margin:6px 3px;color:#cdd6f4;background:#313244}.battery:hover{color:#b4befe}.bluetooth{transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1);margin:6px 3px;color:#cdd6f4;background:#313244}.bluetooth:hover{color:#b4befe}.bluetooth-paired{color:#cdd6f4}.bluetooth-active{color:#cdd6f4}.bluetooth-disabled{color:#74769a;transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1)}.bluetooth-disabled:hover{color:#f38ba8}.lock{background:#313244;font-size:24px;border-radius:12px;margin:2px 4px;padding:2px}.swallow{transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1);margin:6px 3px;color:#cdd6f4;background:#313244}.swallow:hover{color:#b4befe}.audio{transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1);margin:6px 3px;color:#cdd6f4;background:#313244}.audio:hover{color:#b4befe}.network{transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1);margin:6px 3px;color:#cdd6f4;background:#313244}.network:hover{color:#b4befe}.clock{background:#313244;color:#cdd6f4;font-family:robotomono;font-weight:800;border-radius:12px;margin:6px 4px;padding:6px}.power{color:#f38ba8;background:#313244;font-size:24px;border-radius:12px;margin:6px 4px;padding:6px;min-height:1.5rem;transition:all .2s cubic-bezier(0.3, 0, 1, 1)}.power:hover{background:#3c3d53;color:#f5a2b9}.bar{border-radius:calc(12px + 2px);color:#cdd6f4;background:#1e1e2e;font-family:roboto;border-radius:14px;padding:2px}.utilsBox{border-radius:12px;color:#cdd6f4;background:#313244;font-family:symbolsnerdfontmono;margin:4px;padding:6px}.systemInfo{border-radius:12px;color:#cdd6f4;background:#313244;font-family:symbolsnerdfontmono;margin:4px;padding:6px}.launcher{color:#cdd6f4;background:#1e1e2e;font-family:roboto;border-radius:12px;margin:0 0 16px;padding:6px}.launcherApp{border-radius:12px;margin:3px;padding:3px}.launcherApp:focus{background:#313244}.launcherEntry{caret-color:#cdd6f4;background:#313244;border-radius:10px;margin:6px;padding:3px 12px}.launcherItemIcon{margin:3px 6px}.launcherItemTitle{font-size:16px;font-weight:bold}.launcherItemDescription{font-size:12px}.desktopMenu{background:#1e1e2e;color:#cdd6f4;font-family:roboto;border-radius:14px;padding:6px 3px}.desktopMenuItem{border-radius:14px;margin:0 3px;padding:6px 12px;transition:all .2s cubic-bezier(0.3, 0, 1, 1)}.desktopMenuItem:hover{background:#3c3d53;color:#e2e7f9}.desktopMenuItemIcon{font-family:symbolsnerdfontmono;padding:2px 8px 2px 2px}.separator{background:#313244;padding:1px 3px}.desktopIcons{margin:24px 0 0 24px}.desktopIcon{border-radius:6px;padding:6px;transition:all 200ms cubic-bezier(0, 0, 1, 1)}.desktopIcon:hover{background:rgba(180,190,254,.7)}.desktopIconLabel{color:#313244;font-family:roboto}.brightnessPopup{background:#1e1e2e;border-radius:12px;margin:6px;padding:12px;min-width:200px}.brtPopupIcon{font-family:symbolsnerdfontmono;margin:0 6px 0 0}.brtPopupBar{min-width:200px}.brtPopupBar scale{min-height:12px}.brtPopupBar trough{background:rgba(49,50,68,.5);border-radius:24px;min-height:12px}.brtPopupBar highlight{background:#cdd6f4;border-radius:24px;min-width:12px}.volumePopup{background:#1e1e2e;border-radius:12px;margin:6px;padding:12px;min-width:200px}.volPopupIcon{font-family:symbolsnerdfontmono;margin:0 6px 0 0}.volPopupBar{min-width:200px}.volPopupBar scale{min-height:12px}.volPopupBar trough{background:rgba(49,50,68,.5);border-radius:24px;min-height:12px}.volPopupBar highlight{background:#cdd6f4;border-radius:24px;min-width:12px}.music.window{background:rgba(0,0,0,.5);margin:5px 10px 15px;padding:2px}.music.window .cover{background-position:center;background-size:cover;border-radius:12px;box-shadow:0 1px 2px -1px rgba(0,0,0,.5);margin:.4rem;min-height:13rem;min-width:13rem}.music.window .info{margin:.5rem}.music.window .info label,.music.window .info scale{margin:.3rem 0}.music.window .info label.position,.music.window .info label.length{font-size:.8rem;margin-bottom:0}.music.window .info scale{margin-top:0;margin-bottom:0}.music.window .info .title{font-size:1.5rem;font-weight:bold;min-width:14rem}.music.window .controls button{margin:0 .2rem;font-size:1.5rem}.music.window .player-info{margin-bottom:0}.music.window .player-info .player-icon{font-size:1.2rem}.notification{border-radius:calc(12px + 2px);margin:5px 5px 5px 12px;min-width:25rem;background-color:#1e1e2e;color:#cdd6f4}.notification.low{border:1.5px solid #b4befe}.notification.normal{border:1.5px solid #89b4fa}.notification.critical{border:1.5px solid #f38ba8}.notifications widget:last-child .notification{margin-bottom:15px}.notification .icon image{font-size:5rem;margin:.5rem;min-height:5rem;min-width:5rem}.notification .icon>box{border-radius:12px;margin:.5rem;min-height:5rem;min-width:5rem}.notification .actions .action-button{border-radius:calc(12px + 2px);transition:all .3s cubic-bezier(0.2, 0, 0, 1),border .35s cubic-bezier(0.2, 0, 0, 1);padding:4px 0}.notification .actions .action-button:hover{background:#cdd6f4}.notification .text{margin:6px 4px}.notification .text .title{margin:4px 6px;color:#cdd6f4;font-weight:900}.notification .text .body{margin:4px 6px;color:#cdd6f4;font-weight:600} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/_bar.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/_bar.scss new file mode 100644 index 0000000..d237a5a --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/_bar.scss @@ -0,0 +1,34 @@ +// Components +// top +@import "modules/launcher"; +@import "modules/system"; +@import "modules/weather"; + +// center +@import "modules/workspaces"; + +// bottom +@import "modules/tray"; +@import "modules/battery"; +@import "modules/bluetooth"; +@import "modules/lock"; +@import "modules/swallow"; +@import "modules/audio"; +@import "modules/net"; +@import "modules/clock"; +@import "modules/power"; + +// general config +.bar { + @include barWindow; +} + +// top section +.utilsBox { + @include barSection; +} + +// bottom section +.systemInfo { + @include barSection; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_audio.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_audio.scss new file mode 100644 index 0000000..fe36a6f --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_audio.scss @@ -0,0 +1,3 @@ +.audio { + @include barModule; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_battery.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_battery.scss new file mode 100644 index 0000000..0c6291b --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_battery.scss @@ -0,0 +1,3 @@ +.battery { + @include barModule; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_bluetooth.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_bluetooth.scss new file mode 100644 index 0000000..1174bd9 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_bluetooth.scss @@ -0,0 +1,28 @@ +// default state of the bluetooth icon +.bluetooth { + @include barModule; +} + +// if bluetooth is paired +// but not active +.bluetooth-paired { + color: $onSurface; +} + +// if bluetooth is paired +// and active +.bluetooth-active { + color: $onSurface; +} + +// if bluetooth is disabled +.bluetooth-disabled { + color: lighten($surfaceVariant, 30%); + transition: + all 0.3s $materialStandard, + border 0.35s $materialStandard; + + &:hover { + color: $red; + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_clock.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_clock.scss new file mode 100644 index 0000000..205212b --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_clock.scss @@ -0,0 +1,9 @@ +.clock { + background: $surfaceVariant; + color: $onPrimary; + font-family: $monoFont; + font-weight: 800; + border-radius: 12px; + margin: 6px 4px; + padding: 6px; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_launcher.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_launcher.scss new file mode 100644 index 0000000..10dce27 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_launcher.scss @@ -0,0 +1,13 @@ +.launcherIcon { + background: $surfaceVariant; + font-family: $iconFont; + border-radius: 12px; + margin: 6px 4px; + padding: 6px; + min-height: 1.5rem; + transition: all 0.2s $materialAccel; + + &:hover { + background: lighten($surfaceVariant, 5%); + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_lock.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_lock.scss new file mode 100644 index 0000000..4a6cc72 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_lock.scss @@ -0,0 +1,7 @@ +.lock { + background: $surface; + font-size: 24px; + border-radius: 12px; + margin: 2px 4px; + padding: 2px; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_net.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_net.scss new file mode 100644 index 0000000..179ad65 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_net.scss @@ -0,0 +1,3 @@ +.network { + @include barModule; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_power.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_power.scss new file mode 100644 index 0000000..1f73e6b --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_power.scss @@ -0,0 +1,15 @@ +.power { + color: $red; + background: $surface; + font-size: 24px; + border-radius: 12px; + margin: 6px 4px; + padding: 6px; + min-height: 1.5rem; + transition: all 0.2s $materialAccel; + + &:hover { + background: lighten($surfaceVariant, 5%); + color: lighten($red, 5%); + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_swallow.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_swallow.scss new file mode 100644 index 0000000..2aa9ac8 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_swallow.scss @@ -0,0 +1,3 @@ +.swallow { + @include barModule; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_system.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_system.scss new file mode 100644 index 0000000..ee014f2 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_system.scss @@ -0,0 +1,41 @@ +$size: 1.2rem; + +.systemUsage { + color: $onSurface; + background: $surfaceVariant; + font-family: $iconFont; + border-radius: 12px; + margin: 4px; +} + +// cpu indicator +.cpuButton { + padding: 6px 2px 3px 2px; + margin: 1px; +} + +.cpuProgress { + color: $lavender; + padding: 4px 4px; + margin: 0.1rem; + font-size: 4px; + background: $primary; + min-height: $size; + min-width: $size; +} + +// memory indicator +.memButton { + padding: 3px 2px 6px 2px; + margin: 1px; +} + +.memProgress { + color: $blue; + padding: 4px 4px; + margin: 0.1rem; + font-size: 4px; + background: $primary; + min-height: $size; + min-width: $size; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_tray.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_tray.scss new file mode 100644 index 0000000..e6d23e1 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_tray.scss @@ -0,0 +1,15 @@ +.tray { + margin: 0; +} + +.trayChevron { + font-family: $iconFont; +} + +.trayIcons { + margin: 3px 0 0; +} + +.trayIcon { + margin: 0 0 3px; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_weather.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_weather.scss new file mode 100644 index 0000000..67a3d40 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_weather.scss @@ -0,0 +1,14 @@ +.weather { + background: $surfaceVariant; + font-family: "Material Symbols Sharp", Roboto; + border-radius: 12px; + margin: 6px 4px; + padding: 4px; + min-height: 1.5rem; + min-width: 1rem; + transition: all 0.2s $materialAccel; + + &:hover { + background: lighten($surfaceVariant, 5%); + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_workspaces.scss b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_workspaces.scss new file mode 100644 index 0000000..71c7573 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/bar/modules/_workspaces.scss @@ -0,0 +1,29 @@ +.workspaces { + background: transparent; + padding: 14px; + + button { + @include barModule; + + // override some styles provided by barModule + // to better suit the position of the workspaces + // module + margin: 5px 3px; + min-width: 0.6rem; + min-height: 0.6rem; + + color: transparent; + background: $onSurface; + border-radius: 99px; + + &:hover { + background: $lavender; + } + + &.focused { + border-radius: 18px; + background: $blue; + padding: 8px 0; + } + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/beziers.scss b/nyx/homes/notashelf/services/wayland/ags/style/beziers.scss new file mode 100644 index 0000000..b9953fc --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/beziers.scss @@ -0,0 +1,3 @@ +$materialStandard: cubic-bezier(0.2, 0, 0, 1); +$materialDecel: cubic-bezier(0, 0, 0, 1); +$materialAccel: cubic-bezier(0.3, 0, 1, 1); diff --git a/nyx/homes/notashelf/services/wayland/ags/style/colors.scss b/nyx/homes/notashelf/services/wayland/ags/style/colors.scss new file mode 100644 index 0000000..6efeee2 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/colors.scss @@ -0,0 +1,16 @@ +$primary: #1e1e2e; +$onPrimary: #cdd6f4; +$secondary: #181825; +$onSecondary: #cdd6f4; +$surface: #313244; +$onSurface: #cdd6f4; +$surfaceVariant: #313244; +$onSurfaceVariant: #cdd6f4; +$shadow: #000; + +// other colors +$red: #f38ba8; +$yellow: #f9e2af; +$green: #a6e3a1; +$blue: #89b4fa; +$lavender: #b4befe; diff --git a/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktop.scss b/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktop.scss new file mode 100644 index 0000000..9c65fe7 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktop.scss @@ -0,0 +1,3 @@ +// Components +@import "desktopMenu"; +@import "desktopIcons"; diff --git a/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktopIcons.scss b/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktopIcons.scss new file mode 100644 index 0000000..bca379f --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktopIcons.scss @@ -0,0 +1,18 @@ +.desktopIcons { + margin: 24px 0 0 24px; +} + +.desktopIcon { + border-radius: 6px; + padding: 6px; + transition: all 200ms cubic-bezier(0, 0, 1, 1); + + &:hover { + background: transparentize($lavender, 0.3); + } +} + +.desktopIconLabel { + color: $surface; + font-family: $font; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktopMenu.scss b/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktopMenu.scss new file mode 100644 index 0000000..ab7238e --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/desktop/_desktopMenu.scss @@ -0,0 +1,29 @@ +.desktopMenu { + background: $primary; + color: $onSurface; + font-family: $font; + border-radius: 14px; + padding: 6px 3px; +} + +.desktopMenuItem { + border-radius: 14px; + margin: 0 3px; + padding: 6px 12px; + transition: all 0.2s $materialAccel; + + &:hover { + background: lighten($surfaceVariant, 5%); + color: lighten($onSurface, 5%); + } +} + +.desktopMenuItemIcon { + font-family: $iconFont; + padding: 2px 8px 2px 2px; +} + +.separator { + background: $surface; + padding: 1px 3px; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/fonts.scss b/nyx/homes/notashelf/services/wayland/ags/style/fonts.scss new file mode 100644 index 0000000..6a789db --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/fonts.scss @@ -0,0 +1,3 @@ +$font: roboto; +$monoFont: robotomono; +$iconFont: symbolsnerdfontmono; diff --git a/nyx/homes/notashelf/services/wayland/ags/style/launcher/_launcher.scss b/nyx/homes/notashelf/services/wayland/ags/style/launcher/_launcher.scss new file mode 100644 index 0000000..1459e6d --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/launcher/_launcher.scss @@ -0,0 +1,42 @@ +.launcher { + color: $onSurface; + background: $primary; + font-family: $font; + border-radius: 12px; + margin: 0 0 16px; + padding: 6px; +} + +.launcherApp { + border-radius: 12px; + margin: 3px; + padding: 3px; + + &:focus { + background: $surfaceVariant; + } +} + +.launcherEntry { + caret-color: $onSurface; + background: $surfaceVariant; + border-radius: 10px; + margin: 6px; + padding: 3px 12px; +} + +.launcherItem { +} + +.launcherItemIcon { + margin: 3px 6px; +} + +.launcherItemTitle { + font-size: 16px; + font-weight: bold; +} + +.launcherItemDescription { + font-size: 12px; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/main.scss b/nyx/homes/notashelf/services/wayland/ags/style/main.scss new file mode 100644 index 0000000..74a5a24 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/main.scss @@ -0,0 +1,14 @@ +// common components +@import "colors"; +@import "beziers"; +@import "fonts"; +@import "mixins"; +@import "prelude"; + +// modules and widgets +@import "bar/bar"; +@import "launcher/launcher"; +@import "desktop/desktop"; +@import "popups/popups"; +@import "music/music"; +@import "notifications/notifications"; diff --git a/nyx/homes/notashelf/services/wayland/ags/style/mixins.scss b/nyx/homes/notashelf/services/wayland/ags/style/mixins.scss new file mode 100644 index 0000000..e0638ed --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/mixins.scss @@ -0,0 +1,93 @@ +$rounding: 12px; // intter rounding +$padding: 2px; // component padding + +// general mixins +@mixin animated { + transition: + all 0.3s $materialStandard, + border 0.35s $materialStandard; +} + +@mixin roundingOuter { + // Outer rounding = inner rounding + padding + border-radius: calc(#{$rounding} + #{$padding}); +} + +@mixin roundingInner { + border-radius: $rounding; +} + +// window mixin represents a top-level window +// e.g. the bar or a music widget +@mixin window { + @include roundingOuter; +} + +// bar window +@mixin barWindow { + @include window; + color: $onSurface; + background: $primary; + font-family: $font; + border-radius: 14px; + padding: 2px; +} + +@mixin barSection { + @include roundingInner; + color: $onSurface; + background: $surfaceVariant; + font-family: $iconFont; + margin: 4px; + padding: 6px; +} + +@mixin barModule { + // include animations + @include animated; + + // standard widget dimensions + margin: 6px 3px; + + // and styling + color: $onSurface; + background: $surfaceVariant; + + &:hover { + color: $lavender; + } +} + +// popup windows +@mixin popup { + background: $primary; + border-radius: 12px; + margin: 6px; + padding: 12px; + min-width: 200px; +} + +@mixin popupIcon { + font-family: $iconFont; + margin: 0 6px 0 0; +} + +@mixin popupBar { + min-width: 200px; + + & scale { + min-height: 12px; + } + + & trough { + background: transparentize($surfaceVariant, 0.5); + border-radius: 24px; + min-height: 12px; + } + + & highlight { + background: $onSurface; + border-radius: 24px; + min-width: 12px; + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/music/_music.scss b/nyx/homes/notashelf/services/wayland/ags/style/music/_music.scss new file mode 100644 index 0000000..76a51d8 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/music/_music.scss @@ -0,0 +1,56 @@ +.music.window { + background: rgba(0, 0, 0, 0.5); + margin: 5px 10px 15px; + padding: $padding; + + .cover { + background-position: center; + background-size: cover; + border-radius: $rounding; + box-shadow: 0 1px 2px -1px rgba(0, 0, 0, 0.5); + margin: 0.4rem; + min-height: 13rem; + min-width: 13rem; + } +} + +.music.window .info { + margin: 0.5rem; + + label, + scale { + margin: 0.3rem 0; + } + + label.position, + label.length { + font-size: 0.8rem; + margin-bottom: 0; + } + + scale { + margin-top: 0; + margin-bottom: 0; + } + + .title { + font-size: 1.5rem; + font-weight: bold; + min-width: 14rem; + } +} + +.music.window .controls { + button { + margin: 0 0.2rem; + font-size: 1.5rem; + } +} + +.music.window .player-info { + margin-bottom: 0; + + .player-icon { + font-size: 1.2rem; + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/notifications/notifications.scss b/nyx/homes/notashelf/services/wayland/ags/style/notifications/notifications.scss new file mode 100644 index 0000000..346b38d --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/notifications/notifications.scss @@ -0,0 +1,69 @@ +.notification { + @include window; + margin: 5px 5px 5px 12px; + min-width: 25rem; + + background-color: $primary; + color: $onPrimary; + + // low priority + &.low { + border: 1.5px solid $lavender; + } + + // medium priority + &.normal { + border: 1.5px solid $blue; + } + + // critical priority + &.critical { + border: 1.5px solid $red; + } +} + +.notifications widget:last-child .notification { + margin-bottom: 15px; +} + +.notification .icon { + image { + font-size: 5rem; + margin: 0.5rem; + min-height: 5rem; + min-width: 5rem; + } + + > box { + border-radius: $rounding; + margin: 0.5rem; + min-height: 5rem; + min-width: 5rem; + } +} + +.notification .actions .action-button { + @include window; + @include animated; + padding: 4px 0; + + &:hover { + background: $onSurfaceVariant; + } +} + +.notification .text { + margin: 6px 4px; + + .title { + margin: 4px 6px; + color: $onPrimary; + font-weight: 900; + } + + .body { + margin: 4px 6px; + color: $onPrimary; + font-weight: 600; + } +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/popups/_brightnessPopup.scss b/nyx/homes/notashelf/services/wayland/ags/style/popups/_brightnessPopup.scss new file mode 100644 index 0000000..f1cf2e1 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/popups/_brightnessPopup.scss @@ -0,0 +1,11 @@ +.brightnessPopup { + @include popup; +} + +.brtPopupIcon { + @include popupIcon; +} + +.brtPopupBar { + @include popupBar; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/popups/_popups.scss b/nyx/homes/notashelf/services/wayland/ags/style/popups/_popups.scss new file mode 100644 index 0000000..2ca56a1 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/popups/_popups.scss @@ -0,0 +1,3 @@ +// Components +@import "brightnessPopup"; +@import "volumePopup"; diff --git a/nyx/homes/notashelf/services/wayland/ags/style/popups/_volumePopup.scss b/nyx/homes/notashelf/services/wayland/ags/style/popups/_volumePopup.scss new file mode 100644 index 0000000..175bd1b --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/popups/_volumePopup.scss @@ -0,0 +1,11 @@ +.volumePopup { + @include popup; +} + +.volPopupIcon { + @include popupIcon; +} + +.volPopupBar { + @include popupBar; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/style/prelude.scss b/nyx/homes/notashelf/services/wayland/ags/style/prelude.scss new file mode 100644 index 0000000..6f53da6 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/style/prelude.scss @@ -0,0 +1,12 @@ +* { + all: unset; + text-shadow: 0 2px 3px rgba(0, 0, 0, 0.2); + font-family: "Material Design Icons", "Iosevka Nerd Font Mono", Inter, + Roboto, sans-serif; +} + +// restore tooltip styling that got unset in the above class +tooltip { + @include roundingOuter; + background: $primary; +} diff --git a/nyx/homes/notashelf/services/wayland/ags/tsconfig.json b/nyx/homes/notashelf/services/wayland/ags/tsconfig.json new file mode 100644 index 0000000..8f9cb82 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/ags/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "lib": ["ES2022"], + "allowJs": true, + "checkJs": true, + "strict": true, + "noImplicitAny": false, + "baseUrl": ".", + "typeRoots": ["./types"], + "skipLibCheck": true, + }, +} diff --git a/nyx/homes/notashelf/services/wayland/clipboard/default.nix b/nyx/homes/notashelf/services/wayland/clipboard/default.nix new file mode 100644 index 0000000..11848b6 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/clipboard/default.nix @@ -0,0 +1,29 @@ +{ + pkgs, + lib, + osConfig, + ... +}: let + inherit (lib) mkIf mkGraphicalService getExe; + inherit (osConfig) meta; +in { + config = mkIf meta.isWayland { + systemd.user.services = { + cliphist = mkGraphicalService { + Unit.Description = "Clipboard history service"; + Service = { + ExecStart = "${pkgs.wl-clipboard}/bin/wl-paste --watch ${getExe pkgs.cliphist} store"; + Restart = "always"; + }; + }; + + wl-clip-persist = mkGraphicalService { + Unit.Description = "Persistent clipboard for Wayland"; + Service = { + ExecStart = "${getExe pkgs.wl-clip-persist} --clipboard both"; + Restart = "always"; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/default.nix b/nyx/homes/notashelf/services/wayland/default.nix new file mode 100644 index 0000000..aa421d4 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/default.nix @@ -0,0 +1,11 @@ +{ + imports = [ + ./ags + ./clipboard + ./gammastep + ./hyprpaper + ./swaybg + ./swayidle + ./waybar + ]; +} diff --git a/nyx/homes/notashelf/services/wayland/gammastep/default.nix b/nyx/homes/notashelf/services/wayland/gammastep/default.nix new file mode 100644 index 0000000..ebe64d7 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/gammastep/default.nix @@ -0,0 +1,15 @@ +{ + lib, + osConfig, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig) meta; +in { + config = mkIf meta.isWayland { + services.gammastep = { + enable = true; + provider = "geoclue2"; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/hyprpaper/default.nix b/nyx/homes/notashelf/services/wayland/hyprpaper/default.nix new file mode 100644 index 0000000..d39cfe7 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/hyprpaper/default.nix @@ -0,0 +1,35 @@ +{ + osConfig, + pkgs, + lib, + inputs, + ... +}: let + env = osConfig.modules.usrEnv; + sys = osConfig.modules.system; + + monitors = osConfig.modules.device.monitors; + + hyprpaper = inputs.hyprpaper.packages.${pkgs.system}.default; + wallpkgs = inputs.wallpkgs.packages.${pkgs.system}; +in { + config = lib.mkIf ((sys.video.enable) && (env.isWayland && (env.desktop == "Hyprland"))) { + systemd.user.services.hyprpaper = lib.mkHyprlandService { + Unit.Description = "Hyprland wallpaper daemon"; + Service = { + Type = "simple"; + ExecStart = "${lib.getExe hyprpaper}"; + Restart = "on-failure"; + }; + }; + xdg.configFile."hypr/hyprpaper.conf" = { + text = let + wallpaper = "${wallpkgs.catppuccin}/share/wallpapers/catppuccin/01.png"; + in '' + preload=${wallpaper} + ${builtins.concatStringsSep "\n" (builtins.map (monitor: ''wallpaper=${monitor},${wallpaper}'') monitors)} + ipc=off + ''; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/mako/default.nix b/nyx/homes/notashelf/services/wayland/mako/default.nix new file mode 100644 index 0000000..b0cc96f --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/mako/default.nix @@ -0,0 +1,20 @@ +_: { + programs.mako = { + enable = false; + + backgroundColor = "#303446"; + textColor = "#c6d0f5"; + borderColor = "#8caaee"; + padding = "15"; + defaultTimeout = 7000; + borderSize = 3; + borderRadius = 10; + height = 300; + font = "monospace 15"; + + extraConfig = '' + [urgency=high] + border-color=#ef9f76 + ''; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/swaybg/default.nix b/nyx/homes/notashelf/services/wayland/swaybg/default.nix new file mode 100644 index 0000000..cf42059 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/swaybg/default.nix @@ -0,0 +1,28 @@ +{ + pkgs, + lib, + osConfig, + ... +}: let + inherit (lib) mkIf getExe mkGraphicalService; + inherit (osConfig) modules meta; + + env = modules.usrEnv; +in { + config = mkIf (meta.isWayland && (env.desktop != "Hyprland")) { + systemd.user.services = { + swaybg = mkGraphicalService { + Unit.Description = "Wallpaper chooser service"; + Service = let + wall = builtins.fetchurl { + url = "https://raw.githubusercontent.com/catppuccin/wallpapers/main/wallpapers/catppuccin/01.png"; + sha256 = lib.fakeHash; + }; + in { + ExecStart = "${getExe pkgs.swaybg} -i ${wall}"; + Restart = "always"; + }; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/swayidle/default.nix b/nyx/homes/notashelf/services/wayland/swayidle/default.nix new file mode 100644 index 0000000..4f935c6 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/swayidle/default.nix @@ -0,0 +1,53 @@ +{ + osConfig, + config, + pkgs, + lib, + ... +}: let + inherit (lib) getExe mkIf; + + env = osConfig.modules.usrEnv; + locker = getExe env.programs.screenlock.package; + + systemctl = "${pkgs.systemd}/bin/systemctl"; + suspendScript = pkgs.writeShellScript "suspend-script" '' + ${pkgs.pipewire}/bin/pw-cli i all | ${pkgs.ripgrep}/bin/rg running + # only suspend if audio isn't running + if [ $? == 1 ]; then + ${systemctl} suspend + fi + ''; +in { + # TODO: can we make it so that it works with sway *or* hyprland based on which one is enabled? + config = mkIf env.desktops.hyprland.enable { + systemd.user.services.swayidle.Install.WantedBy = ["hyprland-session.target"]; + + # screen idle + services.swayidle = { + enable = true; + extraArgs = ["-d" "-w"]; + events = [ + { + event = "before-sleep"; + command = "${pkgs.systemd}/bin/loginctl lock-session"; + } + { + event = "lock"; + command = "${locker}"; + } + ]; + timeouts = [ + { + timeout = 900; + command = suspendScript.outPath; + } + { + timeout = 1200; + command = "${config.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms off"; + resumeCommand = "${config.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms on"; + } + ]; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/waybar/default.nix b/nyx/homes/notashelf/services/wayland/waybar/default.nix new file mode 100644 index 0000000..4006a30 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/waybar/default.nix @@ -0,0 +1,27 @@ +{ + pkgs, + lib, + config, + osConfig, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig.modules) device; + inherit (osConfig.modules.style.colorScheme) slug colors; + + waybar_config = import ./presets/${slug}/config.nix {inherit osConfig config lib pkgs;}; + waybar_style = import ./presets/${slug}/style.nix {inherit colors;}; + + acceptedTypes = ["desktop" "laptop" "lite" "hybrid"]; +in { + config = mkIf (builtins.elem device.type acceptedTypes) { + home.packages = with pkgs.python3Packages; [requests]; + programs.waybar = { + enable = false; + systemd.enable = true; + package = pkgs.waybar; + settings = waybar_config; + style = waybar_style; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/waybar/presets/catppuccin-mocha/config.nix b/nyx/homes/notashelf/services/wayland/waybar/presets/catppuccin-mocha/config.nix new file mode 100644 index 0000000..2cec84f --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/waybar/presets/catppuccin-mocha/config.nix @@ -0,0 +1,277 @@ +{ + config, + pkgs, + lib, + osConfig, + ... +}: let + inherit (lib) optionalString primaryMonitor; + + sys = osConfig.modules.system; +in { + mainBar = { + layer = "top"; + position = "left"; + # monitor configuration, kind of dirty since it assumes DP-1 is my main monitor + output = primaryMonitor osConfig; #builtins.elemAt monitors 0; + width = 55; + spacing = 7; + margin-left = 6; + margin-top = 9; + margin-bottom = 9; + margin-right = null; + fixed-center = true; + exclusive = true; + modules-left = [ + "custom/search" + "hyprland/workspaces" + "custom/lock" + "backlight" + "battery" + "custom/weather" + "custom/todo" + ]; + modules-center = []; + modules-right = [ + "cpu" + (optionalString sys.bluetooth.enable "bluetooth") + "gamemode" + "pulseaudio" + "network" + "custom/swallow" + "clock" + "custom/power" + ]; + + "hyprland/workspaces" = let + hyprctl = config.wayland.windowManager.hyprland.package + "/bin/hyprctl"; + in { + on-click = "activate"; + on-scroll-up = "${hyprctl} dispatch workspace m+1"; + on-scroll-down = "${hyprctl} dispatch workspace m-1"; + format = "{icon}"; + active-only = true; + all-outputs = true; + format-icons = { + "1" = "一"; + "2" = "二"; + "3" = "三"; + "4" = "四"; + "5" = "五"; + "6" = "六"; + "7" = "七"; + "8" = "八"; + "9" = "九"; + "10" = "十"; + }; + }; + + "custom/search" = { + format = " "; + tooltip = false; + on-click = "${lib.getExe pkgs.killall} rofi || run-as-service $(rofi -show drun)"; + }; + + "custom/todo" = { + format = "{}"; + tooltip = true; + interval = 7; + exec = let + todo = pkgs.todo + "/bin/todo"; + sed = pkgs.gnused + "/bin/sed"; + wc = pkgs.coreutils + "/bin/wc"; + in + pkgs.writeShellScript "todo-waybar" '' + #!/bin/sh + + total_todo=$(${todo} | ${wc} -l) + todo_raw_done=$(${todo} raw done | ${sed} 's/^/ ◉ /' | ${sed} -z 's/\n/\\n/g') + todo_raw_undone=$(${todo} raw todo | ${sed} 's/^/ ◉ /' | ${sed} -z 's/\n/\\n/g') + done=$(${todo} raw done | ${wc} -l) + undone=$(${todo} raw todo | ${wc} -l) + tooltip=$(${todo}) + + left="$done/$total_todo" + + header="todo\\n\\n" + tooltip="" + if [[ $total_todo -gt 0 ]]; then + if [[ $undone -gt 0 ]]; then + export tooltip="$header👷 Today, you need to do:\\n\\n $(echo $todo_raw_undone)\\n\\n✅ You have already done:\\n\\n $(echo $todo_raw_done)" + export output=" 🗒️ \\n $left" + else + export tooltip="$header✅ All done!\\n🥤 Remember to stay hydrated!" + export output=" 🎉 \\n $left" + fi + else + export tooltip="" + export output="" + fi + + printf '{"text": "%s", "tooltip": "%s" }' "$output" "$tooltip" + ''; + return-type = "json"; + }; + + "custom/weather" = let + waybar-wttr = pkgs.stdenv.mkDerivation { + name = "waybar-wttr"; + buildInputs = [(pkgs.python3.withPackages (pythonPackages: with pythonPackages; [requests]))]; + unpackPhase = "true"; + installPhase = '' + mkdir -p $out/bin + cp ${../../scripts/waybar-wttr.py} $out/bin/waybar-wttr + chmod +x $out/bin/waybar-wttr + ''; + }; + in { + format = "{}"; + tooltip = true; + interval = 30; + exec = "${waybar-wttr}/bin/waybar-wttr"; + return-type = "json"; + }; + + "custom/lock" = { + tooltip = false; + on-click = "${pkgs.bash}/bin/bash -c '(sleep 0.5s; ${lib.getExe pkgs.swaylock-effects} --grace 0)' & disown"; + format = ""; + }; + + "custom/swallow" = { + tooltip = false; + on-click = let + hyprctl = config.wayland.windowManager.hyprland.package + "/bin/hyprctl"; + notify-send = pkgs.libnotify + "/bin/notify-send"; + rg = pkgs.ripgrep + "/bin/rg"; + in + pkgs.writeShellScript "waybar-swallow" '' + #!/bin/sh + if ${hyprctl} getoption misc:enable_swallow | ${rg} -q "int: 1"; then + ${hyprctl} keyword misc:enable_swallow false >/dev/null && + ${notify-send} "Hyprland" "Turned off swallowing" + else + ${hyprctl} keyword misc:enable_swallow true >/dev/null && + ${notify-send} "Hyprland" "Turned on swallowing" + fi + ''; + format = "󰊰"; + }; + + "custom/power" = { + tooltip = false; + on-click = let + sudo = pkgs.sudo + "/bin/sudo"; + rofi = config.programs.rofi.package + "/bin/rofi"; + poweroff = pkgs.systemd + "/bin/poweroff"; + reboot = pkgs.systemd + "/bin/reboot"; + in + pkgs.writeShellScript "shutdown-waybar" '' + + #!/bin/sh + + off=" Shutdown" + reboot=" Reboot" + cancel="󰅖 Cancel" + + sure="$(printf '%s\n%s\n%s' "$off" "$reboot" "$cancel" | + ${rofi} -dmenu -p ' Are you sure?')" + + if [ "$sure" = "$off" ]; then + ${sudo} ${poweroff} + elif [ "$sure" = "$reboot" ]; then + ${sudo} ${reboot} + fi + ''; + format = "󰐥"; + }; + clock = { + format = '' + {:%H + %M}''; + tooltip-format = '' + {:%Y %B} + {calendar} + ''; + }; + + backlight = let + brightnessctl = lib.getExe pkgs.brightnessctl; + in { + format = "{icon}"; + format-icons = ["󰋙" "󰫃" "󰫄" "󰫅" "󰫆" "󰫇" "󰫈"]; + #format-icons = ["" "" "" "" "" "" "" "" ""]; + on-scroll-up = "${brightnessctl} s 1%-"; + on-scroll-down = "${brightnessctl} s +1%"; + }; + + battery = { + states = { + warning = 30; + critical = 15; + }; + format = "{icon}"; + format-charging = "󰂄"; + format-plugged = "󰂄"; + format-alt = "{icon}"; + format-icons = ["󰂃" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹"]; + }; + network = let + nm-editor = "${pkgs.networkmanagerapplet}/bin/nm-connection-editor"; + in { + format-wifi = "󰤨"; + format-ethernet = "󰈀"; + format-alt = "󱛇"; + format-disconnected = "󰤭"; + tooltip-format = "{ipaddr}/{ifname} via {gwaddr} ({signalStrength}%)"; + on-click-right = "${nm-editor}"; + }; + + pulseaudio = { + scroll-step = 5; + tooltip = true; + tooltip-format = "{volume}"; + on-click = "${pkgs.killall}/bin/killall pavucontrol || ${pkgs.pavucontrol}/bin/pavucontrol"; + format = "{icon}"; + format-muted = "󰝟"; + format-icons = { + default = ["" "" ""]; + }; + }; + + cpu = { + interval = 10; + format = ""; + max-length = 10; + states = { + "50" = 50; + "60" = 75; + "70" = 90; + }; + }; + + bluetooth = { + # controller = "controller1", // specify the alias of the controller if there are more than 1 on the system + format = ""; + format-disabled = "󰂲"; # an empty format will hide the module + format-connected = "󰂱"; + tooltip-format = "{controller_alias}\t{controller_address}"; + tooltip-format-connected = "{controller_alias}\t{controller_address}\n\n{device_enumerate}"; + tooltip-format-disabled = ""; + tooltip-format-enumerate-connected = "{device_alias}\t{device_address}"; + }; + + gamemode = { + format = "󰊴"; + format-alt = "{glyph}"; + glyph = "󰊴"; + hide-not-running = true; + use-icon = true; + icon-name = "input-gaming-symbolic"; + icon-spacing = 4; + icon-size = 20; + tooltip = true; + tooltip-format = "Games running: {count}"; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/waybar/presets/catppuccin-mocha/style.nix b/nyx/homes/notashelf/services/wayland/waybar/presets/catppuccin-mocha/style.nix new file mode 100644 index 0000000..4b1cdc9 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/waybar/presets/catppuccin-mocha/style.nix @@ -0,0 +1,224 @@ +{colors}: +with colors; let + OSLogo = builtins.fetchurl rec { + name = "OSLogo-${sha256}.png"; + sha256 = "14mbpw8jv1w2c5wvfvj8clmjw0fi956bq5xf9s2q3my14far0as8"; + url = "https://raw.githubusercontent.com/NixOS/nixos-artwork/master/logo/nix-snowflake.svg"; + }; +in '' + * { + font-family: Material Design Icons, Iosevka Nerd Font Mono; + font-size: 19px; + } + + window#waybar { + background-color: #${base00}; + border: .5px solid #${base01}; + border-radius: 20px; + box-shadow: 2 3 2 2px #151515; + color: #${base05}; + margin: 16px 16px; + transition-property: background-color; + transition-duration: .5s; + } + + window#waybar.hidden { + opacity: 0.2; + } + + #custom-weather, + #clock, + #network, + #custom-swallow, + #custom-power, + #cpu, + #battery, + #backlight, + #memory, + #workspaces, + #custom-search, + #custom-power, + #custom-todo, + #custom-lock, + #custom-weather, + #volume, + #cpu, + #bluetooth, + #gamemode, + #pulseaudio { + border-radius: 15px; + margin: 0px 7px 0px 7px; + background-color: #${base02}; + padding: 10px 0px 10px 0px; + } + + + #workspaces button { + background-color: transparent; + /* Use box-shadow instead of border so the text isn't offset */ + color: #${base0D}; + font-size: 21px; + /* padding-left: 6px; */ + box-shadow: inset 0 -3px transparent; + } + + #workspaces button:hover { + color: #${base0C}; + box-shadow: inherit; + text-shadow: inherit; + } + + #workspaces button.active { + color: #${base0A}; + } + + #workspaces button.urgent { + color: #${base08}; + } + + #custom-power { + color: #${base08}; + } + + #workspaces { + font-size: 15px; + background-color: #${base02}; + } + + #network { + color: #${base0D}; + padding: 14px 0px 14px 0px; + } + + #gamemode { + color: #${base0D}; + } + + #custom-weather { + color: #${base05}; + background-color: #${base02}; + } + + #cpu { + color: rgba(0, 0, 0, 0.0); + background-color: rgba(0, 0, 0, 0.0); + margin: -50; + } + + #cpu.50 { + color: #${base06}; + background-color: #${base02}; + border-radius: 15px; + margin: 0px 7px 0px 7px; + padding: 10px 0px 10px 0px; + } + + #cpu.60 { + color: #${base09}; + background-color: #${base02}; + border-radius: 15px; + margin: 0px 7px 0px 7px; + padding: 10px 0px 10px 0px; + } + + #cpu.70 { + color: #${base08}; + background-color: #${base02}; + border-radius: 15px; + margin: 0px 7px 0px 7px; + padding: 10px 0px 10px 0px; + } + + #bluetooth { + color: #${base0E}; + } + + #bluetooth.off, + #bluetooth.pairable, + #bluetooth.discovering, + #bluetooth.disabled { + color: rgba(0, 0, 0, 0.0); + background-color: rgba(0, 0, 0, 0.0); + margin: -50; + } + + #clock { + color: #${base05}; + background-color: #${base02}; + font-weight: 700; + font-size: 20px; + padding: 5px 0px 5px 0px; + font-family: "Iosevka Term"; + } + + #pulseaudio { + color: #${base0B}; + padding: 5px 0px 5px 0px; + font-size: 30; + } + + #pulseaudio.source-muted, + #pulseaudio.muted { + color: #${base08}; + padding: 16px 0px 16px 0px; + font-size: 15; + } + + #custom-swallow { + color: #${base0E}; + padding: 14px 0px 14px 0px; + } + + #custom-lock { + color: #${base0D}; + font-size: 27; + padding: 6px 0px 6px 0px; + } + + #custom-todo { + color: #${base05}; + padding-left: 2px; + } + + #custom-power { + margin-bottom: 7px; + padding: 14px 0px 14px 0px; + } + + #custom-search { + background-image: url("${OSLogo}"); + background-size: 65%; + background-position: center; + background-repeat: no-repeat; + margin-top: 7px; + } + + #backlight { + color: #${base0A}; + } + + #battery { + color: #${base0C}; + } + + #battery.warning { + color: #${base09}; + } + + #battery.critical:not(.charging) { + color: #${base08}; + } + + tooltip { + font-family: 'Lato', sans-serif; + border-radius: 15px; + padding: 20px; + margin: 30px; + } + + tooltip label { + font-family: 'Lato', sans-serif; + padding: 20px; + } + +'' diff --git a/nyx/homes/notashelf/services/wayland/waybar/presets/oxocarbon-dark/config.nix b/nyx/homes/notashelf/services/wayland/waybar/presets/oxocarbon-dark/config.nix new file mode 100644 index 0000000..87fc0e6 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/waybar/presets/oxocarbon-dark/config.nix @@ -0,0 +1,276 @@ +{ + config, + pkgs, + lib, + osConfig, + ... +}: let + inherit (lib) optionalString primaryMonitor; + + sys = osConfig.modules.system; +in { + mainBar = { + layer = "top"; + position = "left"; + # monitor configuration, kind of dirty since it assumes DP-1 is my main monitor + output = primaryMonitor osConfig; + width = 55; + spacing = 7; + margin-left = 6; + margin-top = 9; + margin-bottom = 9; + margin-right = null; + fixed-center = true; + exclusive = true; + modules-left = [ + "custom/search" + "hyprland/workspaces" + "backlight" + "battery" + "custom/weather" + "custom/todo" + ]; + modules-center = []; + modules-right = [ + "cpu" + (optionalString sys.bluetooth.enable "bluetooth") + "gamemode" + "pulseaudio" + "network" + "custom/swallow" + "clock" + "custom/power" + ]; + + "hyprland/workspaces" = let + hyprctl = config.wayland.windowManager.hyprland.package + "/bin/hyprctl"; + in { + on-click = "activate"; + on-scroll-up = "${hyprctl} dispatch workspace m+1"; + on-scroll-down = "${hyprctl} dispatch workspace m-1"; + format = "{icon}"; + active-only = true; + all-outputs = true; + format-icons = { + "1" = "一"; + "2" = "二"; + "3" = "三"; + "4" = "四"; + "5" = "五"; + "6" = "六"; + "7" = "七"; + "8" = "八"; + "9" = "九"; + "10" = "十"; + }; + }; + + "custom/search" = { + format = " "; + tooltip = false; + on-click = "${lib.getExe pkgs.killall} rofi || run-as-service $(rofi -show drun)"; + }; + + "custom/todo" = { + format = "{}"; + tooltip = true; + interval = 7; + exec = let + todo = pkgs.todo + "/bin/todo"; + sed = pkgs.gnused + "/bin/sed"; + wc = pkgs.coreutils + "/bin/wc"; + in + pkgs.writeShellScript "todo-waybar" '' + #!/bin/sh + + total_todo=$(${todo} | ${wc} -l) + todo_raw_done=$(${todo} raw done | ${sed} 's/^/ ◉ /' | ${sed} -z 's/\n/\\n/g') + todo_raw_undone=$(${todo} raw todo | ${sed} 's/^/ ◉ /' | ${sed} -z 's/\n/\\n/g') + done=$(${todo} raw done | ${wc} -l) + undone=$(${todo} raw todo | ${wc} -l) + tooltip=$(${todo}) + + left="$done/$total_todo" + + header="todo\\n\\n" + tooltip="" + if [[ $total_todo -gt 0 ]]; then + if [[ $undone -gt 0 ]]; then + export tooltip="$header👷 Today, you need to do:\\n\\n $(echo $todo_raw_undone)\\n\\n✅ You have already done:\\n\\n $(echo $todo_raw_done)" + export output=" 🗒️ \\n $left" + else + export tooltip="$header✅ All done!\\n🥤 Remember to stay hydrated!" + export output=" 🎉 \\n $left" + fi + else + export tooltip="" + export output="" + fi + + printf '{"text": "%s", "tooltip": "%s" }' "$output" "$tooltip" + ''; + return-type = "json"; + }; + + "custom/weather" = let + waybar-wttr = pkgs.stdenv.mkDerivation { + name = "waybar-wttr"; + buildInputs = [(pkgs.python3.withPackages (pythonPackages: with pythonPackages; [requests]))]; + unpackPhase = "true"; + installPhase = '' + mkdir -p $out/bin + cp ${../../scripts/waybar-wttr.py} $out/bin/waybar-wttr + chmod +x $out/bin/waybar-wttr + ''; + }; + in { + format = "{}"; + tooltip = true; + interval = 30; + exec = "${waybar-wttr}/bin/waybar-wttr"; + return-type = "json"; + }; + + "custom/lock" = { + tooltip = false; + on-click = "${pkgs.bash}/bin/bash -c '(sleep 0.5s; ${lib.getExe pkgs.swaylock-effects} --grace 0)' & disown"; + format = ""; + }; + + "custom/swallow" = { + tooltip = false; + on-click = let + hyprctl = config.wayland.windowManager.hyprland.package + "/bin/hyprctl"; + notify-send = pkgs.libnotify + "/bin/notify-send"; + rg = pkgs.ripgrep + "/bin/rg"; + in + pkgs.writeShellScript "waybar-swallow" '' + #!/bin/sh + if ${hyprctl} getoption misc:enable_swallow | ${rg} -q "int: 1"; then + ${hyprctl} keyword misc:enable_swallow false >/dev/null && + ${notify-send} "Hyprland" "Turned off swallowing" + else + ${hyprctl} keyword misc:enable_swallow true >/dev/null && + ${notify-send} "Hyprland" "Turned on swallowing" + fi + ''; + format = "󰊰"; + }; + + "custom/power" = { + tooltip = false; + on-click = let + sudo = pkgs.sudo + "/bin/sudo"; + rofi = config.programs.rofi.package + "/bin/rofi"; + poweroff = pkgs.systemd + "/bin/poweroff"; + reboot = pkgs.systemd + "/bin/reboot"; + in + pkgs.writeShellScript "shutdown-waybar" '' + + #!/bin/sh + + off=" Shutdown" + reboot=" Reboot" + cancel="󰅖 Cancel" + + sure="$(printf '%s\n%s\n%s' "$off" "$reboot" "$cancel" | + ${rofi} -dmenu -p ' Are you sure?')" + + if [ "$sure" = "$off" ]; then + ${sudo} ${poweroff} + elif [ "$sure" = "$reboot" ]; then + ${sudo} ${reboot} + fi + ''; + format = "󰐥"; + }; + clock = { + format = '' + {:%H + %M}''; + tooltip-format = '' + {:%Y %B} + {calendar} + ''; + }; + + backlight = let + brightnessctl = lib.getExe pkgs.brightnessctl; + in { + format = "{icon}"; + format-icons = ["󰋙" "󰫃" "󰫄" "󰫅" "󰫆" "󰫇" "󰫈"]; + #format-icons = ["" "" "" "" "" "" "" "" ""]; + on-scroll-up = "${brightnessctl} s 1%-"; + on-scroll-down = "${brightnessctl} s +1%"; + }; + + battery = { + states = { + warning = 30; + critical = 15; + }; + format = "{icon}"; + format-charging = "󰂄"; + format-plugged = "󰂄"; + format-alt = "{icon}"; + format-icons = ["󰂃" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹"]; + }; + network = let + nm-editor = "${pkgs.networkmanagerapplet}/bin/nm-connection-editor"; + in { + format-wifi = "󰤨"; + format-ethernet = "󰈀"; + format-alt = "󱛇"; + format-disconnected = "󰤭"; + tooltip-format = "{ipaddr}/{ifname} via {gwaddr} ({signalStrength}%)"; + on-click-right = "${nm-editor}"; + }; + + pulseaudio = { + scroll-step = 5; + tooltip = true; + tooltip-format = "{volume}"; + on-click = "${pkgs.killall}/bin/killall pavucontrol || ${pkgs.pavucontrol}/bin/pavucontrol"; + format = "{icon}"; + format-muted = "󰝟"; + format-icons = { + default = ["" "" ""]; + }; + }; + + cpu = { + interval = 10; + format = ""; + max-length = 10; + states = { + "50" = 50; + "60" = 75; + "70" = 90; + }; + }; + + bluetooth = { + # controller = "controller1", // specify the alias of the controller if there are more than 1 on the system + format = ""; + format-disabled = "󰂲"; # an empty format will hide the module + format-connected = "󰂱"; + tooltip-format = "{controller_alias}\t{controller_address}"; + tooltip-format-connected = "{controller_alias}\t{controller_address}\n\n{device_enumerate}"; + tooltip-format-disabled = ""; + tooltip-format-enumerate-connected = "{device_alias}\t{device_address}"; + }; + + gamemode = { + format = "󰊴"; + format-alt = "{glyph}"; + glyph = "󰊴"; + hide-not-running = true; + use-icon = true; + icon-name = "input-gaming-symbolic"; + icon-spacing = 4; + icon-size = 20; + tooltip = true; + tooltip-format = "Games running: {count}"; + }; + }; +} diff --git a/nyx/homes/notashelf/services/wayland/waybar/presets/oxocarbon-dark/style.nix b/nyx/homes/notashelf/services/wayland/waybar/presets/oxocarbon-dark/style.nix new file mode 100644 index 0000000..172a4f8 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/waybar/presets/oxocarbon-dark/style.nix @@ -0,0 +1,201 @@ +{colors}: +with colors; let + OSLogo = builtins.fetchurl rec { + name = "OSLogo-${sha256}.png"; + sha256 = "14mbpw8jv1w2c5wvfvj8clmjw0fi956bq5xf9s2q3my14far0as8"; + url = "https://raw.githubusercontent.com/NixOS/nixos-artwork/master/logo/nix-snowflake.svg"; + }; +in '' + * { + font-family: Material Design Icons, Iosevka Nerd Font Mono; + font-size: 19px; + border-radius: 12px; + } + + window#waybar { + background-color: #${base00}; + border: .5px solid #${base01}; + border-radius: 14px; + box-shadow: 2 3 2 2px #151515; + color: #${base05}; + margin: 16px 16px; + transition-property: background-color; + transition-duration: .5s; + } + + window#waybar.hidden { + opacity: 0.2; + } + + #clock, + #network, + #custom-power, + #cpu, + #battery, + #backlight, + #memory, + #workspaces, + #custom-search, + #custom-power, + #custom-todo, + #custom-lock, + #custom-weather, + #custom-swallow, + #volume, + #bluetooth, + #gamemode, + #pulseaudio { + border-radius: 14px; + margin: 0px 7px 0px 7px; + background-color: #${base01}; + padding: 10px 0px 10px 0px; + } + + #workspaces { + font-size: 14px; + background-color: #${base01}; + } + + #workspaces button { + background-color: transparent; + border-radius: 14px; + color: #${base04}; + font-size: 21px; + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -3px transparent; + } + + #workspaces button:hover { + color: #${base0C}; + box-shadow: inherit; + text-shadow: inherit; + } + + #workspaces button.active { + color: #${base0A}; + } + + #workspaces button.urgent { + color: #${base08}; + } + + #network { + /* prevents the network icon from being too squashed */ + padding: 14px 0px 14px 0px; + } + + #cpu { + color: rgba(0, 0, 0, 0.0); + background-color: rgba(0, 0, 0, 0.0); + margin: -50; + border-radius: 16px; + } + + #cpu.50 { + color: #${base06}; + background-color: #${base02}; + border-radius: 15px; + margin: 0px 7px 0px 7px; + padding: 10px 0px 10px 0px; + } + + #cpu.60 { + color: #${base09}; + background-color: #${base02}; + border-radius: 15px; + margin: 0px 7px 0px 7px; + padding: 10px 0px 10px 0px; + } + + #cpu.70 { + color: #${base08}; + background-color: #${base02}; + border-radius: 15px; + margin: 0px 7px 0px 7px; + padding: 10px 0px 10px 0px; + } + + #bluetooth.off, + #bluetooth.pairable, + #bluetooth.discovering, + #bluetooth.disabled { + color: rgba(0, 0, 0, 0.0); + background-color: rgba(0, 0, 0, 0.0); + margin: -50; + border-radius: 16px; + } + + #clock { + color: #${base05}; + background-color: #${base01}; + font-weight: 700; + font-size: 20px; + padding: 5px 0px 5px 0px; + font-family: "Iosevka Term"; + } + + #pulseaudio { + padding: 5px 0px 5px 0px; + font-size: 30; + } + + #pulseaudio.source-muted, + #pulseaudio.muted { + color: #${base08}; + padding: 16px 0px 16px 0px; + font-size: 15; + } + + #custom-swallow { + padding: 14px 0px 14px 0px; + } + + #custom-todo { + padding-left: 2px; + background-color: #${base01}; + } + + #custom-power { + margin-bottom: 7px; + padding: 14px 0px 14px 0px; + } + + #custom-search { + background-image: url("${OSLogo}"); + background-size: 65%; + background-position: center; + background-repeat: no-repeat; + margin-top: 7px; + } + + #custom-power { + margin-bottom: 7px; + padding: 14px 0px 14px 0px; + color: #${base0A}; + } + + #battery { + border-radius: 14px; + } + + #battery.warning { + color: #${base09}; + } + + #battery.critical:not(.charging) { + color: #${base08}; + } + + tooltip { + font-family: 'Lato', sans-serif; + border-radius: 14px; + padding: 20px; + margin: 30px; + } + + tooltip label { + font-family: 'Lato', sans-serif; + padding: 20px; + } + +'' diff --git a/nyx/homes/notashelf/services/wayland/waybar/scripts/waybar-wttr.py b/nyx/homes/notashelf/services/wayland/waybar/scripts/waybar-wttr.py new file mode 100755 index 0000000..ef42447 --- /dev/null +++ b/nyx/homes/notashelf/services/wayland/waybar/scripts/waybar-wttr.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python + +import os +import json +import requests +import logging +from datetime import datetime, timedelta + +logging.basicConfig(level=logging.ERROR) +logger = logging.getLogger(__name__) + +CACHE_EXPIRATION = 60 +XDG_CACHE_HOME = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache")) +CACHE_DIR = os.path.join(XDG_CACHE_HOME, "waybar-wttr") +FALLBACK_CACHE_DIR = "/tmp" +CACHE_FILE = os.path.join(CACHE_DIR, "weather_cache.json") + +SUNNY = "☀️" +CLOUDY = "☁️" +RAIN = "🌧️" +SNOW = "❄️" +THUNDERSTORM = "⛈️" +PARTLY_CLOUDY = "⛅️" +CLEAR = "☀️" + +HOURS_AGO_THRESHOLD = 2 +TEMP_THRESHOLD_COLD = 10 +TEMP_THRESHOLD_HOT = 0 + + +def ensure_cache_directory(): + try: + if not os.path.exists(CACHE_DIR): + os.makedirs(CACHE_DIR, exist_ok=True) + except Exception as e: + logger.error(f"Error creating cache directory: {e}") + + +def get_weather_data(): + ensure_cache_directory() + try: + response = requests.get("https://wttr.in/?format=j1") + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + logger.error(f"Error fetching weather data: {e}") + return None + + +def get_cached_weather_data(): + try: + if os.path.exists(CACHE_FILE): + with open(CACHE_FILE, "r") as cache_file: + cached_data = json.load(cache_file) + cache_time = datetime.strptime( + cached_data["timestamp"], "%Y-%m-%d %H:%M:%S" + ) + if datetime.now() - cache_time < timedelta(minutes=CACHE_EXPIRATION): + return cached_data["data"] + except Exception as e: + logger.error(f"Error loading cached data: {e}") + return None + + +def cache_weather_data(data): + try: + with open(CACHE_FILE, "w") as cache_file: + cached_data = { + "data": data, + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + } + json.dump(cached_data, cache_file) + except Exception as e: + logger.error(f"Error caching data: {e}") + + +def format_time(time): + return time.replace("00", "").zfill(2) + + +def format_temp(temp): + return f"{temp}°".ljust(4) + + +def get_emoji_for_condition(condition): + emoji_map = { + "Sunny": SUNNY, + "Cloudy": CLOUDY, + "Rain": RAIN, + "Snow": SNOW, + "Thunder": THUNDERSTORM, + "Partly Cloudy": PARTLY_CLOUDY, + "Clear": CLEAR, + } + return emoji_map.get(condition, "") + + +def format_conditions(hour): + condition_probabilities = { + "chanceoffog": "Fog", + "chanceoffrost": "Frost", + "chanceofovercast": "Overcast", + "chanceofrain": "Rain", + "chanceofsnow": "Snow", + "chanceofsunshine": "Sunshine", + "chanceofthunder": "Thunder", + "chanceofwindy": "Wind", + } + if "chanceofpartlycloudy" in hour: + condition_probabilities["chanceofpartlycloudy"] = "Partly Cloudy" + conditions = [] + for event, description in condition_probabilities.items(): + if event in hour: + probability = int(hour[event]) + if probability > 0: + emoji = get_emoji_for_condition(description) + conditions.append(f"{emoji} {description} {probability}%") + return ", ".join(conditions) + + +def format_weather_data(weather_data): + current_condition = weather_data["current_condition"][0] + temp = int(current_condition["FeelsLikeC"]) + temp_sign = "+" if TEMP_THRESHOLD_HOT > temp > TEMP_THRESHOLD_COLD else "" + formatted_data = { + "text": f" {SUNNY} \n {temp_sign}{temp}°", + "tooltip": f"{current_condition['weatherDesc'][0]['value']} {current_condition['temp_C']}°\n" + f"Feels like: {current_condition['FeelsLikeC']}°\n" + f"Wind: {current_condition['windspeedKmph']}Km/h\n" + f"Humidity: {current_condition['humidity']}%\n", + } + for i, day in enumerate(weather_data["weather"]): + formatted_data["tooltip"] += f"\n" + if i == 0: + formatted_data["tooltip"] += "Today, " + if i == 1: + formatted_data["tooltip"] += "Tomorrow, " + formatted_data["tooltip"] += f"{day['date']}\n" + formatted_data["tooltip"] += f"⬆️ {day['maxtempC']}° ⬇️ {day['mintempC']}° " + formatted_data[ + "tooltip" + ] += f"🌅 {day['astronomy'][0]['sunrise']} 🌇 {day['astronomy'][0]['sunset']}\n" + now = datetime.now() + for hour in day["hourly"]: + hour_time = format_time(hour["time"]) + if i == 0 and int(hour_time) < now.hour - HOURS_AGO_THRESHOLD: + continue + formatted_data[ + "tooltip" + ] += f"{hour_time} {get_emoji_for_condition(hour['weatherDesc'][0]['value'])} {format_temp(hour['FeelsLikeC'])} {hour['weatherDesc'][0]['value']}, {format_conditions(hour)}\n" + return formatted_data + + +def main(): + ensure_cache_directory() + cached_data = get_cached_weather_data() + if cached_data: + print(json.dumps(cached_data)) + return + weather_data = get_weather_data() + if weather_data: + formatted_data = format_weather_data(weather_data) + cache_weather_data(formatted_data) + print(json.dumps(formatted_data)) + + +if __name__ == "__main__": + main() diff --git a/nyx/homes/notashelf/services/x11/default.nix b/nyx/homes/notashelf/services/x11/default.nix new file mode 100644 index 0000000..eed7124 --- /dev/null +++ b/nyx/homes/notashelf/services/x11/default.nix @@ -0,0 +1 @@ +_: {} diff --git a/nyx/homes/notashelf/themes/default.nix b/nyx/homes/notashelf/themes/default.nix new file mode 100644 index 0000000..b614cfc --- /dev/null +++ b/nyx/homes/notashelf/themes/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./gtk.nix + ./qt.nix + ./global.nix + ]; +} diff --git a/nyx/homes/notashelf/themes/global.nix b/nyx/homes/notashelf/themes/global.nix new file mode 100644 index 0000000..1ccee7f --- /dev/null +++ b/nyx/homes/notashelf/themes/global.nix @@ -0,0 +1,14 @@ +{osConfig, ...}: let + cfg = osConfig.modules.style; +in { + # cursor theme + home = { + pointerCursor = { + package = cfg.pointerCursor.package; # pkgs.bibata-cursors; + name = cfg.pointerCursor.name; # "Bibata-Modern-Classic"; + size = cfg.pointerCursor.size; + gtk.enable = true; + x11.enable = true; + }; + }; +} diff --git a/nyx/homes/notashelf/themes/gtk.nix b/nyx/homes/notashelf/themes/gtk.nix new file mode 100644 index 0000000..f6a8399 --- /dev/null +++ b/nyx/homes/notashelf/themes/gtk.nix @@ -0,0 +1,89 @@ +{ + osConfig, + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (osConfig.modules) device; + cfg = osConfig.modules.style; + + acceptedTypes = ["laptop" "desktop" "hybrid" "lite"]; +in { + config = mkIf (builtins.elem device.type acceptedTypes) { + xdg.systemDirs.data = let + schema = pkgs.gsettings-desktop-schemas; + in ["${schema}/share/gsettings-schemas/${schema.name}"]; + + home = { + packages = with pkgs; [ + glib # gsettings + cfg.gtk.theme.package + cfg.gtk.iconTheme.package + ]; + + sessionVariables = { + # set GTK theme to the name specified by the gtk theme package + GTK_THEME = "${cfg.gtk.theme.name}"; + + # gtk applications should use filepickers specified by xdg + GTK_USE_PORTAL = "${toString (lib.boolToNum cfg.gtk.usePortal)}"; + }; + }; + + gtk = { + enable = true; + theme = { + name = cfg.gtk.theme.name; + package = cfg.gtk.theme.package; + }; + + iconTheme = { + name = cfg.gtk.iconTheme.name; + package = cfg.gtk.iconTheme.package; + }; + + font = { + name = cfg.gtk.font.name; + size = cfg.gtk.font.size; + }; + + gtk2 = { + configLocation = "${config.xdg.configHome}/gtk-2.0/gtkrc"; + extraConfig = '' + gtk-xft-antialias=1 + gtk-xft-hinting=1 + gtk-xft-hintstyle="hintslight" + gtk-xft-rgba="rgb" + ''; + }; + + gtk3.extraConfig = { + gtk-toolbar-style = "GTK_TOOLBAR_BOTH"; + gtk-toolbar-icon-size = "GTK_ICON_SIZE_LARGE_TOOLBAR"; + gtk-decoration-layout = "appmenu:none"; + gtk-button-images = 1; + gtk-menu-images = 1; + gtk-enable-event-sounds = 0; + gtk-enable-input-feedback-sounds = 0; + gtk-xft-antialias = 1; + gtk-xft-hinting = 1; + gtk-xft-hintstyle = "hintslight"; + gtk-error-bell = 0; + gtk-application-prefer-dark-theme = true; + }; + + gtk4.extraConfig = { + gtk-decoration-layout = "appmenu:none"; + gtk-enable-event-sounds = 0; + gtk-enable-input-feedback-sounds = 0; + gtk-xft-antialias = 1; + gtk-xft-hinting = 1; + gtk-xft-hintstyle = "hintslight"; + gtk-error-bell = 0; + gtk-application-prefer-dark-theme = true; + }; + }; + }; +} diff --git a/nyx/homes/notashelf/themes/qt.nix b/nyx/homes/notashelf/themes/qt.nix new file mode 100644 index 0000000..752c374 --- /dev/null +++ b/nyx/homes/notashelf/themes/qt.nix @@ -0,0 +1,76 @@ +{ + pkgs, + lib, + osConfig, + ... +}: let + inherit (lib) mkIf optionals; + + dev = osConfig.modules.device; + sys = osConfig.modules.system; + cfg = osConfig.modules.style; + + acceptedTypes = ["laptop" "desktop" "hybrid" "lite"]; +in { + config = mkIf (builtins.elem dev.type acceptedTypes && sys.video.enable) { + xdg.configFile = { + "kdeglobals".source = cfg.qt.kdeglobals.source; + + "Kvantum/kvantum.kvconfig".source = (pkgs.formats.ini {}).generate "kvantum.kvconfig" { + General.theme = "catppuccin"; + Applications.catppuccin = '' + qt5ct, org.kde.dolphin, org.kde.kalendar, org.qbittorrent.qBittorrent, hyprland-share-picker, dolphin-emu, Nextcloud, nextcloud, cantata, org.kde.kid3-qt + ''; + }; + + "Kvantum/catppuccin/catppuccin.kvconfig".source = builtins.fetchurl { + url = "https://raw.githubusercontent.com/catppuccin/Kvantum/main/src/Catppuccin-Mocha-Blue/Catppuccin-Mocha-Blue.kvconfig"; + sha256 = "1f8xicnc5696g0a7wak749hf85ynfq16jyf4jjg4dad56y4csm6s"; + }; + + "Kvantum/catppuccin/catppuccin.svg".source = builtins.fetchurl { + url = "https://raw.githubusercontent.com/catppuccin/Kvantum/main/src/Catppuccin-Mocha-Blue/Catppuccin-Mocha-Blue.svg"; + sha256 = "0vys09k1jj8hv4ra4qvnrhwxhn48c2gxbxmagb3dyg7kywh49wvg"; + }; + }; + + qt = { + enable = true; + platformTheme = mkIf cfg.forceGtk "gtk"; # just an override for QT_QPA_PLATFORMTHEME, takes “gtk”, “gnome”, “qtct” or “kde” + style = mkIf (!cfg.forceGtk) { + name = cfg.qt.theme.name; + package = cfg.qt.theme.package; + }; + }; + + home.packages = with pkgs; + [ + libsForQt5.qt5ct + breeze-icons + + # add theme package to path just in case + cfg.qt.theme.package + ] + ++ optionals cfg.useKvantum [ + qt6Packages.qtstyleplugin-kvantum + libsForQt5.qtstyleplugin-kvantum + ]; + + home.sessionVariables = { + # scaling - 1 means no scaling + QT_AUTO_SCREEN_SCALE_FACTOR = "1"; + + # use wayland as the default backend, fallback to xcb if wayland is not available + QT_QPA_PLATFORM = "wayland;xcb"; + + # disable window decorations everywhere + QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; + + # remain backwards compatible with qt5 + DISABLE_QT5_COMPAT = "0"; + + # tell calibre to use the dark theme, because the light one hurts my eyes + CALIBRE_USE_DARK_PALETTE = "1"; + }; + }; +} diff --git a/nyx/hosts/README.md b/nyx/hosts/README.md new file mode 100644 index 0000000..c626f36 --- /dev/null +++ b/nyx/hosts/README.md @@ -0,0 +1,33 @@ +# Design Considerations + +## Imports + +> Guidelines for importing files within the `hosts` directory + +- Only importing downwards. This means **no** `imports = [ ../../foo/bar/some-module.nix ];` - this is a + classic pattern in NixOS configurations, but only gets more out of hand in time. +- Only one level of imports. Which means `imports = [./foo.nix]` is fine, but `imports = [ ./foo/bar/baz.nix ]` **is not**. +- Do not import defined modules outside `hosts/default.nix`. Meaning `hosts/enyo/default.nix` + **cannot** have `../../../modules/..` in its configurations. + +## Module System + +> Guidelines for using the local module system for enabling or disabling services and programs + +- Hosts should properly define their type and equipment. + This means adequately defined `device.type`, `device.cpu` and `device.gpu` at the very least +- A host should contain at least **2** files/directories: `modules/` and `default.nix` importing the rest of the files + - `modules/` should follow my local module system: `config.modules.{device,system,usrEnv,theme}` where applicable + - `default.nix` may not contain anything other than an `imports = [ ... ]` importing rest of the files +- Additional host-specific configurations may either go into `system.nix` (e.g. kernel configuration) + or have their own file (i.e Wireguard or hardware mount configurations) with their own file (i.e `mounts.nix`) + +## Per-host hardware + +> Guidelines for using `hardware-configuration.nix` + +Previously I have required `hardware-configuration.nix` to be available (under the name `hardware.nix`) for each host. This is +no longer a requirement as almost all host-specific hardware configuration have been moved to hardware mixins located in `modules/`. + +This further reinforces the requirement for the local module system, meaning hosts **must** specify things like CPU vendors +or hardware specific kernel modules under `modules.device` or `modules.system`. diff --git a/nyx/hosts/apollon/default.nix b/nyx/hosts/apollon/default.nix new file mode 100644 index 0000000..732138c --- /dev/null +++ b/nyx/hosts/apollon/default.nix @@ -0,0 +1,5 @@ +_: { + imports = [ + ./system.nix + ]; +} diff --git a/nyx/hosts/apollon/system.nix b/nyx/hosts/apollon/system.nix new file mode 100644 index 0000000..08852fc --- /dev/null +++ b/nyx/hosts/apollon/system.nix @@ -0,0 +1,85 @@ +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/virtualisation/qemu-vm.nix") + ]; + + config = { + modules.device.type = "vm"; + zramSwap.enable = lib.mkForce false; + services.thermald.enable = lib.mkForce false; + + boot = { + initrd = { + supportedFilesystems = ["bcachefs"]; # make bcachefs work + availableKernelModules = ["bcache"]; + }; + + kernelPackages = lib.mkOverride 0 pkgs.linuxPackages_testing; + }; + + environment = { + systemPackages = [ + pkgs.bcachefs-tools + ]; + }; + + programs.zsh = { + enable = true; + enableCompletion = true; + promptInit = '' + eval "$(${lib.getExe pkgs.starship} init zsh)" + ''; + }; + + users.users."user" = { + description = "Testing user with sudo access and no password"; + isNormalUser = true; + password = ""; + extraGroups = ["wheel" "networkmanager"]; + shell = pkgs.zsh; + }; + + security.sudo.wheelNeedsPassword = false; + + virtualisation = { + memorySize = 2048; + diskSize = 4096; + cores = 3; + useDefaultFilesystems = false; + rootDevice = "/dev/vda1"; + + fileSystems = { + "/" = { + device = "${config.virtualisation.rootDevice}:/dev/vda2"; + fsType = lib.mkForce "bcachefs"; + }; + }; + + interfaces = { + vm0 = { + vlan = 1; + }; + }; + }; + + boot.initrd.postDeviceCommands = with pkgs; '' + if ! test -b /dev/vda1; then + ${parted}/bin/parted --script /dev/vda -- mklabel gpt + ${parted}/bin/parted --script /dev/vda -- mkpart primary 1MiB 50% + ${parted}/bin/parted --script /dev/vda -- mkpart primary 50% 100% + sync + fi + + FSTYPE=$(blkid -o value -s TYPE /dev/vda1 || true) + if test -z "$FSTYPE"; then + ${bcachefs-tools}/bin/bcachefs format /dev/vda1 /dev/vda2 --replicas=2 --label=root + fi + ''; + }; +} diff --git a/nyx/hosts/artemis/default.nix b/nyx/hosts/artemis/default.nix new file mode 100644 index 0000000..732138c --- /dev/null +++ b/nyx/hosts/artemis/default.nix @@ -0,0 +1,5 @@ +_: { + imports = [ + ./system.nix + ]; +} diff --git a/nyx/hosts/artemis/system.nix b/nyx/hosts/artemis/system.nix new file mode 100644 index 0000000..86ad0dc --- /dev/null +++ b/nyx/hosts/artemis/system.nix @@ -0,0 +1,87 @@ +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/virtualisation/qemu-vm.nix") + ]; + + config = { + modules.device.type = "vm"; + zramSwap.enable = lib.mkForce false; + + boot = { + initrd = { + supportedFilesystems = ["bcachefs"]; # make bcachefs work + availableKernelModules = ["bcache"]; + }; + + kernelPackages = lib.mkOverride 0 pkgs.linuxPackages_latest; + }; + + environment = { + shells = with pkgs; [bash zsh]; + + systemPackages = with pkgs; [ + bcachefs-tools + starship # having starship here means pkgs.startship will be stored during build and not during promptInit + ]; + }; + + programs.zsh = { + enable = true; + enableCompletion = true; + promptInit = '' + eval "$(${lib.getExe pkgs.starship} init zsh)" + ''; + }; + + users.users."user" = { + description = "Testing user with sudo access and no password"; + isNormalUser = true; + password = ""; + extraGroups = ["wheel" "networkmanager"]; + shell = pkgs.zsh; + }; + + security.sudo.wheelNeedsPassword = false; + + virtualisation = { + memorySize = 2048; + diskSize = 4096; + cores = 3; + useDefaultFilesystems = false; + rootDevice = "/dev/vda1"; + + fileSystems = { + "/" = { + device = "${config.virtualisation.rootDevice}:/dev/vda2"; + fsType = lib.mkForce "bcachefs"; + }; + }; + + interfaces = { + vm0 = { + vlan = 1; + }; + }; + }; + + boot.initrd.postDeviceCommands = with pkgs; '' + if ! test -b /dev/vda1; then + ${parted}/bin/parted --script /dev/vda -- mklabel gpt + ${parted}/bin/parted --script /dev/vda -- mkpart primary 1MiB 25% + ${parted}/bin/parted --script /dev/vda -- mkpart primary 25% 100% + sync + fi + + FSTYPE=$(blkid -o value -s TYPE /dev/vda1 || true) + if test -z "$FSTYPE"; then + ${bcachefs-tools}/bin/bcachefs format /dev/vda1 /dev/vda2 --replicas=2 --label=root + fi + ''; + }; +} diff --git a/nyx/hosts/atlas/default.nix b/nyx/hosts/atlas/default.nix new file mode 100644 index 0000000..e4fcecb --- /dev/null +++ b/nyx/hosts/atlas/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./fs + ./modules + + ./system.nix + ]; +} diff --git a/nyx/hosts/atlas/fs/default.nix b/nyx/hosts/atlas/fs/default.nix new file mode 100644 index 0000000..35b46c9 --- /dev/null +++ b/nyx/hosts/atlas/fs/default.nix @@ -0,0 +1,9 @@ +{ + fileSystems."/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + options = ["noatime"]; + }; + + swapDevices = []; +} diff --git a/nyx/hosts/atlas/modules/default.nix b/nyx/hosts/atlas/modules/default.nix new file mode 100644 index 0000000..43e67d0 --- /dev/null +++ b/nyx/hosts/atlas/modules/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./device.nix + ./system.nix + ./usrEnv.nix + ]; +} diff --git a/nyx/hosts/atlas/modules/device.nix b/nyx/hosts/atlas/modules/device.nix new file mode 100644 index 0000000..e078ce6 --- /dev/null +++ b/nyx/hosts/atlas/modules/device.nix @@ -0,0 +1,11 @@ +{ + config.modules.device = { + type = "server"; + cpu.type = "pi"; + gpu.type = "pi"; + monitors = ["HDMI-A-1"]; + hasBluetooth = false; + hasSound = false; + hasTPM = false; + }; +} diff --git a/nyx/hosts/atlas/modules/system.nix b/nyx/hosts/atlas/modules/system.nix new file mode 100644 index 0000000..24f9bd9 --- /dev/null +++ b/nyx/hosts/atlas/modules/system.nix @@ -0,0 +1,39 @@ +{ + config.modules.system = { + mainUser = "notashelf"; + fs = ["ext4" "vfat" "ntfs" "exfat"]; + autoLogin = false; + + boot = { + loader = "none"; + enableKernelTweaks = true; + initrd.enableTweaks = true; + tmpOnTmpfs = false; + }; + + video.enable = false; + sound.enable = false; + bluetooth.enable = false; + printing.enable = false; + emulation.enable = false; + + virtualization.enable = false; + + networking = { + optimizeTcp = true; + nftables.enable = true; + tailscale = { + enable = true; + isClient = true; + isServer = false; + }; + }; + + security = { + tor.enable = true; + fixWebcam = false; + lockModules = true; + auditd.enable = true; + }; + }; +} diff --git a/nyx/hosts/atlas/modules/usrEnv.nix b/nyx/hosts/atlas/modules/usrEnv.nix new file mode 100644 index 0000000..d70020e --- /dev/null +++ b/nyx/hosts/atlas/modules/usrEnv.nix @@ -0,0 +1,7 @@ +{ + config.modules.usrEnv = { + isWayland = false; + desktop = "Hyprland"; + useHomeManager = true; + }; +} diff --git a/nyx/hosts/atlas/system.nix b/nyx/hosts/atlas/system.nix new file mode 100644 index 0000000..f8ca3cc --- /dev/null +++ b/nyx/hosts/atlas/system.nix @@ -0,0 +1,49 @@ +{ + modulesPath, + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkForce; +in { + config = { + environment.systemPackages = with pkgs; [ + libraspberrypi + raspberrypi-eeprom + git + neovim + ]; + + hardware = { + raspberry-pi."4" = { + # Enable GPU acceleration + fkms-3d.enable = true; + apply-overlays-dtmerge.enable = true; + }; + + deviceTree.enable = true; + + opengl = { + # this only takes effect in 64 bit systems + driSupport32Bit = mkForce false; + }; + }; + + boot = { + kernelModules = lib.mkForce ["bridge" "macvlan" "tap" "tun" "loop" "atkbd" "ctr"]; + supportedFilesystems = lib.mkForce ["ext4" "vfat"]; + loader.grub.enable = mkForce false; + }; + + nixpkgs = { + config.allowUnsupportedSystem = true; + hostPlatform.system = "armv7l-linux"; + buildPlatform.system = "x86_64-linux"; + }; + + console.enable = false; + + system.stateVersion = "24.05"; + }; +} diff --git a/nyx/hosts/default.nix b/nyx/hosts/default.nix new file mode 100644 index 0000000..d6fbfac --- /dev/null +++ b/nyx/hosts/default.nix @@ -0,0 +1,255 @@ +{ + withSystem, + inputs, + ... +}: let + # self.lib is an extended version of nixpkgs.lib + # mkNixosIso and mkNixosSystem are my own builders for assembling a nixos system + # provided by my local extended library + inherit (inputs.self) lib; + inherit (lib) concatLists mkNixosIso mkNixosSystem; + + ## flake inputs ## + hw = inputs.nixos-hardware.nixosModules; # hardware compat for pi4 and other quirky devices + agenix = inputs.agenix.nixosModules.default; # secret encryption via age + hm = inputs.home-manager.nixosModules.home-manager; # home-manager nixos module + + # serializing the modulePath to a variable + # this is in case the modulePath changes depth (i.e modules becomes nixos/modules) + modulePath = ../modules; + + coreModules = modulePath + /core; # the path where common modules reside + extraModules = modulePath + /extra; # the path where extra modules reside + options = modulePath + /options; # the module that provides the options for my system configuration + + # common modules + # to be shared across all systems without exception + common = coreModules + /common; # the self-proclaimed sane defaults for all my systems + profiles = coreModules + /profiles; # force defaults based on selected profile + + # roles + iso = coreModules + /roles/iso; # for providing a uniform ISO configuration for live systems - only the build setup + headless = coreModules + /roles/headless; # for devices that are of the headless type - provides no GUI + graphical = coreModules + /roles/graphical; # for devices that are of the graphical type - provides a GUI + workstation = coreModules + /roles/workstation; # for devices that are of workstation type - any device that is for daily use + server = coreModules + /roles/server; # for devices that are of the server type - provides online services + laptop = coreModules + /roles/laptop; # for devices that are of the laptop type - provides power optimizations + + # extra modules - optional but likely critical to a successful build + sharedModules = extraModules + /shared; # the path where shared modules reside + + # home-manager # + homesDir = ../homes; # home-manager configurations for hosts that need home-manager + homes = [hm homesDir]; # combine hm flake input and the home module to be imported together + + # a list of shared modules that ALL systems need + shared = [ + common # the "sane" default shared across systems + options # provide options for defined modules across the system + sharedModules # consume my flake's own nixosModules + agenix # age encryption for secrets + profiles # profiles program overrides per-host + ]; +in { + # My main desktop boasting a RX 6700XT and a Ryzen 5 3600x + # fully free from nvidia + # fuck nvidia - Linus "the linux" Torvalds + enyo = mkNixosSystem { + inherit withSystem; + hostname = "enyo"; + system = "x86_64-linux"; + modules = + [ + ./enyo + graphical + workstation + ] + ++ concatLists [shared homes]; + specialArgs = {inherit lib;}; + }; + + # HP Pavillion from 2016 + # superseded by epimetheus + prometheus = mkNixosSystem { + inherit withSystem; + hostname = "prometheus"; + system = "x86_64-linux"; + modules = + [ + ./prometheus + graphical + workstation + laptop + ] + ++ concatLists [shared homes]; + specialArgs = {inherit lib;}; + }; + + # Identical twin host for Prometheus + # provides full disk encryption + # with passkey/USB authentication + epimetheus = mkNixosSystem { + inherit withSystem; + hostname = "epimetheus"; + system = "x86_64-linux"; + modules = + [ + ./epimetheus + graphical + workstation + laptop + ] + ++ concatLists [shared homes]; + specialArgs = {inherit lib;}; + }; + + # HP Pavillion laptop from 2023 + # equipped a Ryzen 7 7730U + # usually acts as my portable workstation + # similar to epimetheus, has full disk + # encryption with ephemeral root using impermanence + hermes = mkNixosSystem { + inherit withSystem; + hostname = "hermes"; + system = "x86_64-linux"; + modules = + [ + ./hermes + graphical + workstation + laptop + ] + ++ concatLists [shared homes]; + specialArgs = {inherit lib;}; + }; + + # Hetzner VPS to replace my previous server machines + # hosts some of my infrastructure + helios = mkNixosSystem { + inherit withSystem; + hostname = "helios"; + system = "x86_64-linux"; + modules = + [ + ./helios + server + headless + ] + ++ concatLists [shared homes]; + specialArgs = {inherit lib;}; + }; + + # Lenovo Ideapad from 2014 + # Hybrid device + # acts as a portable server and a "workstation" + icarus = mkNixosSystem { + inherit withSystem; + hostname = "icarus"; + system = "x86_64-linux"; + modules = + [ + ./icarus + graphical + workstation + laptop + server + ] + ++ concatLists [shared homes]; + specialArgs = {inherit lib;}; + }; + + # Raspberry Pi 400 + # My Pi400 homelab + # used mostly for testing networking/cloud services + atlas = mkNixosSystem { + inherit withSystem; + hostname = "atlas"; + system = "aarch64-linux"; + modules = + [ + ./atlas + server + headless + + # get raspbery pi 4 modules from nixos-hardware + hw.raspberry-pi-4 + ] + ++ shared; + specialArgs = {inherit lib;}; + }; + + # Self-made live recovery environment that overrides or/and configures certain default programs + # provides tools and fixes the keymaps for my keyboard + gaea = mkNixosIso { + hostname = "gaea"; + system = "x86_64-linux"; + modules = [ + ./gaea + iso + headless + ]; + specialArgs = {inherit lib;}; + }; + + # An air-gapped NixOS live media to deal with + # sensitive tooling (e.g. Yubikey, GPG, etc.) + # isolated from all networking + erebus = mkNixosIso { + inherit withSystem; + hostname = "erebus"; + system = "x86_64-linux"; + modules = [ + ./erebus + iso + ]; + specialArgs = {inherit lib;}; + }; + + # Pretty beefy VM running on my dedicated server + # is mostly for testing, but can run services at will + leto = mkNixosSystem { + inherit withSystem; + hostname = "leto"; + system = "x86_64-linux"; + modules = + [ + ./leto + server + headless + ] + ++ concatLists [shared homes]; + specialArgs = {inherit lib;}; + }; + + # Twin virtual machine hosts + # Artemis is x86_64-linux + artemis = mkNixosSystem { + inherit withSystem; + hostname = "artemis"; + system = "x86_64-linux"; + modules = + [ + ./artemis + server + headless + ] + ++ shared; + specialArgs = {inherit lib;}; + }; + + # Apollon is also x86_64-linux + # but is for testing server-specific services + apollon = mkNixosSystem { + inherit withSystem; + hostname = "apollon"; + system = "aarch64-linux"; + modules = + [ + ./apollon + server + headless + ] + ++ shared; + specialArgs = {inherit lib;}; + }; +} diff --git a/nyx/hosts/enyo/btrfs.nix b/nyx/hosts/enyo/btrfs.nix new file mode 100644 index 0000000..3b1ba25 --- /dev/null +++ b/nyx/hosts/enyo/btrfs.nix @@ -0,0 +1,46 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib.modules) mkIf; + inherit (lib.attrsets) filterAttrs; + + btrfsMounts = filterAttrs (_: mount: mount.fsType == "btrfs") config.fileSystems; + hasHomeSubvolume = (filterAttrs (_: mount: mount.mountPoint == "/home") btrfsMounts) != {}; +in { + config = mkIf (btrfsMounts != {}) { + systemd = { + # create the snapshots directory + # it will linger for 30 days before it's dropped + # this serves as an easy way to persist the snapshots + # for a set amount of time + tmpfiles.settings."10-snapshots"."/var/lib/snapshots".d = { + user = "root"; + group = "root"; + age = "30d"; + }; + + # run the snapshots on a weekly timer + timers.snapshot-home = { + enable = hasHomeSubvolume; + description = "snapshot home subvolume"; + wantedBy = ["multi-user.target"]; + timerConfig = { + OnCalendar = "weekly"; + Persistent = true; + }; + }; + + # create a snapshot of the /home subvolume + # it will be stored in /var/lib/snapshots with a timestamp + # %s - seconds since the Epoch (1970-01-01 00:00 UTC) + services.snapshot-home = { + enable = hasHomeSubvolume; + path = [pkgs.btrfs-progs]; + script = "btrfs subvolume snapshot /home /var/lib/snapshots/$(date +%s)"; + }; + }; + }; +} diff --git a/nyx/hosts/enyo/default.nix b/nyx/hosts/enyo/default.nix new file mode 100644 index 0000000..7d9d8be --- /dev/null +++ b/nyx/hosts/enyo/default.nix @@ -0,0 +1,12 @@ +{ + imports = [ + ./fs + ./kernel + ./modules + + ./btrfs.nix + ./networking.nix + ./system.nix + ./wireguard.nix # TODO: abstract + ]; +} diff --git a/nyx/hosts/enyo/fs/default.nix b/nyx/hosts/enyo/fs/default.nix new file mode 100644 index 0000000..10bed07 --- /dev/null +++ b/nyx/hosts/enyo/fs/default.nix @@ -0,0 +1,44 @@ +{ + imports = [./external.nix]; + config = { + fileSystems = { + "/boot" = { + device = "/dev/disk/by-uuid/E20E-9940"; + fsType = "vfat"; + }; + + "/" = { + device = "/dev/disk/by-uuid/e1f1186b-2143-4bf7-8b99-8da1434520c6"; + fsType = "btrfs"; + options = ["subvol=root" "compress=zstd" "noatime"]; + }; + + "/nix" = { + device = "/dev/disk/by-uuid/e1f1186b-2143-4bf7-8b99-8da1434520c6"; + fsType = "btrfs"; + options = ["subvol=nix" "compress=zstd" "noatime"]; + }; + + "/home" = { + device = "/dev/disk/by-uuid/e1f1186b-2143-4bf7-8b99-8da1434520c6"; + fsType = "btrfs"; + options = ["subvol=home" "compress=zstd"]; + }; + + "/persist" = { + device = "/dev/disk/by-uuid/e1f1186b-2143-4bf7-8b99-8da1434520c6"; + fsType = "btrfs"; + options = ["subvol=persist" "compress=zstd" "noatime"]; + }; + + "/var/log" = { + device = "/dev/disk/by-uuid/e1f1186b-2143-4bf7-8b99-8da1434520c6"; + fsType = "btrfs"; + options = ["subvol=log" "compress=zstd" "noatime"]; + }; + }; + + # Swap Devices + swapDevices = [{device = "/dev/disk/by-uuid/62fc1f62-55ae-432d-8623-74ea6511410c";}]; + }; +} diff --git a/nyx/hosts/enyo/fs/external.nix b/nyx/hosts/enyo/fs/external.nix new file mode 100644 index 0000000..dcabba3 --- /dev/null +++ b/nyx/hosts/enyo/fs/external.nix @@ -0,0 +1,42 @@ +let + homeDir = "/home/notashelf"; +in { + fileSystems = { + # External Devices + "/mnt/SLib1" = { + label = "SteamLib1"; + device = "/dev/disk/by-uuid/4345570b-2bd6-4cb8-8ca1-eb05bcf12c05"; + fsType = "btrfs"; + options = ["nofail" "rw" "compress=zstd"]; + }; + + "/mnt/SLib2" = { + label = "SteamLib2"; + device = "/dev/disk/by-uuid/080006fe-b012-4363-b596-c183b012c1de"; + fsType = "btrfs"; + options = ["nofail" "rw" "compress=zstd"]; + }; + + "/mnt/Storage" = { + label = "Storage"; + device = "/dev/disk/by-uuid/eb25f034-e5de-4c6c-89e9-f3dea10159a5"; + fsType = "btrfs"; + options = ["nofail" "rw" "compress=zstd"]; + }; + + "/mnt/Expansion" = { + label = "Expansion"; + device = "/dev/disk/by-uuid/9381fba0-e9b5-4574-9007-a0911cae4a08"; + fsType = "btrfs"; + options = ["nofail" "rw" "compress=zstd"]; + }; + + "${homeDir}/Media/Music" = { + label = "Music"; + device = "/dev/disk/by-uuid/68a2203f-5ecd-4ddb-b66a-76eb8dcf328c"; + fsType = "btrfs"; + options = ["nofail" "rw" "compress=zstd"]; + noCheck = true; + }; + }; +} diff --git a/nyx/hosts/enyo/kernel/config/amd.nix b/nyx/hosts/enyo/kernel/config/amd.nix new file mode 100644 index 0000000..7afd7da --- /dev/null +++ b/nyx/hosts/enyo/kernel/config/amd.nix @@ -0,0 +1,33 @@ +{lib, ...}: let + inherit (lib.kernel) yes no; + inherit (lib.attrsets) mapAttrs; + inherit (lib.modules) mkForce; +in { + boot.kernelPatches = [ + { + # recompile with AMD platform specific optimizations + name = "amd-platform-patches"; + patch = null; # no patch is needed, just apply the options + extraStructuredConfig = mapAttrs (_: mkForce) { + # enable compiler optimizations for AMD + MNATIVE_AMD = yes; + X86_USE_PPRO_CHECKSUM = yes; + X86_AMD_PSTATE = yes; + + X86_EXTENDED_PLATFORM = no; # disable support for other x86 platforms + X86_MCE_INTEL = no; # disable support for intel mce + + # multigen LRU + LRU_GEN = yes; + LRU_GEN_ENABLED = yes; + + # collect CPU frequency statistics + CPU_FREQ_STAT = yes; + + # Optimized for performance + # this is already set on the Xanmod kernel + # CC_OPTIMIZE_FOR_PERFORMANCE_O3 = yes; + }; + } + ]; +} diff --git a/nyx/hosts/enyo/kernel/config/base.nix b/nyx/hosts/enyo/kernel/config/base.nix new file mode 100644 index 0000000..297cfa3 --- /dev/null +++ b/nyx/hosts/enyo/kernel/config/base.nix @@ -0,0 +1,31 @@ +{lib, ...}: let + inherit (lib.kernel) yes no module; + inherit (lib.attrsets) mapAttrs; + inherit (lib.modules) mkForce; +in { + boot.kernelPatches = [ + { + # + # + name = "bbr-and-cake"; + patch = null; + extraStructuredConfig = mapAttrs (_: mkForce) { + TCP_CONG_CUBIC = module; + NET_SCH_CAKE = module; + + # xanmod defaults + TCP_CONG_BBR = yes; + DEFAULT_BBR = yes; + }; + } + { + name = "zstd-module-compression"; + patch = null; + extraStructuredConfig = mapAttrs (_: mkForce) { + KERNEL_ZSTD = yes; + MODULE_COMPRESS_ZSTD = yes; + MODULE_COMPRESS_XZ = no; + }; + } + ]; +} diff --git a/nyx/hosts/enyo/kernel/config/default.nix b/nyx/hosts/enyo/kernel/config/default.nix new file mode 100644 index 0000000..529a268 --- /dev/null +++ b/nyx/hosts/enyo/kernel/config/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./amd.nix + ./base.nix + ./security.nix + ./unused.nix + ]; +} diff --git a/nyx/hosts/enyo/kernel/config/security.nix b/nyx/hosts/enyo/kernel/config/security.nix new file mode 100644 index 0000000..4b3e307 --- /dev/null +++ b/nyx/hosts/enyo/kernel/config/security.nix @@ -0,0 +1,26 @@ +{lib, ...}: let + inherit (lib.kernel) yes; + inherit (lib.attrsets) mapAttrs; + inherit (lib.modules) mkForce; +in { + boot.kernelPatches = [ + { + # enable lockdown LSM + name = "kernel-lockdown-lsm"; + patch = null; + extraStructuredConfig = mapAttrs (_: mkForce) { + SECURITY_LOCKDOWN_LSM = yes; + LOCKDOWN_LSM_EARLY = yes; + LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY = yes; + + MODULE_SIG = yes; + MODULE_SIG_SHA512 = yes; + MODULE_SIG_FORCE = yes; + + # used to avoid a systemd error: + # systemd[1]: bpf-lsm: Failed to load BPF object: Invalid argument + BPF_LSM = yes; + }; + } + ]; +} diff --git a/nyx/hosts/enyo/kernel/config/unused.nix b/nyx/hosts/enyo/kernel/config/unused.nix new file mode 100644 index 0000000..f6200c2 --- /dev/null +++ b/nyx/hosts/enyo/kernel/config/unused.nix @@ -0,0 +1,239 @@ +{lib, ...}: let + inherit (lib.kernel) no; + inherit (lib.attrsets) mapAttrs; + inherit (lib.modules) mkForce; +in { + boot.kernelPatches = [ + { + name = "disable-unused-features"; + patch = null; + extraStructuredConfig = mapAttrs (_: mkForce) { + CRYPTO_842 = no; + DEBUG_MISC = no; + DEBUG_PREEMPT = no; + HIBERNATION = no; + KEXEC = no; + KEXEC_FILE = no; + + "60XX_WDT" = no; + "6LOWPAN" = no; + "8139CP" = no; + "8139TOO" = no; + "8139TOO_8129" = no; + + ALIENWARE_WMI = no; + ALIM1535_WDT = no; + ALIM7101_WDT = no; + ALTERA_MBOX = no; + ALTERA_MSGDMA = no; + ALTERA_TSE = no; + ALX = no; + + CONFIG_GENERIC_ADC_BATTERY = no; + CONFIG_IP5XXX_POWER = no; + CONFIG_TEST_POWER = no; + CONFIG_CHARGER_ADP5061 = no; + CONFIG_BATTERY_CW2015 = no; + CONFIG_BATTERY_DS2760 = no; + CONFIG_BATTERY_DS2780 = no; + CONFIG_BATTERY_DS2781 = no; + CONFIG_BATTERY_DS2782 = no; + CONFIG_BATTERY_SAMSUNG_SDI = no; + CONFIG_BATTERY_SBS = no; + CONFIG_CHARGER_SBS = no; + CONFIG_MANAGER_SBS = no; + CONFIG_BATTERY_BQ27XXX = no; + CONFIG_BATTERY_BQ27XXX_I2C = no; + CONFIG_BATTERY_BQ27XXX_HDQ = no; + CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM = no; + CONFIG_CHARGER_DA9150 = no; + CONFIG_BATTERY_AXP20X = no; + CONFIG_AXP20X_POWER = no; + CONFIG_AXP288_CHARGER = no; + CONFIG_AXP288_FUEL_GAUGE = no; + CONFIG_BATTERY_MAX17040 = no; + CONFIG_BATTERY_MAX17042 = no; + CONFIG_BATTERY_MAX1721X = no; + CONFIG_CHARGER_PCF50633 = no; + CONFIG_CHARGER_ISP1704 = no; + CONFIG_CHARGER_MAX8903 = no; + CONFIG_CHARGER_LP8727 = no; + CONFIG_CHARGER_GPIO = no; + CONFIG_CHARGER_MANAGER = no; + CONFIG_CHARGER_LT3651 = no; + CONFIG_CHARGER_LTC4162L = no; + CONFIG_CHARGER_MAX14577 = no; + CONFIG_CHARGER_MAX77693 = no; + CONFIG_CHARGER_MAX77976 = no; + CONFIG_CHARGER_MP2629 = no; + CONFIG_CHARGER_MT6360 = no; + CONFIG_CHARGER_MT6370 = no; + CONFIG_CHARGER_BQ2415X = no; + CONFIG_CHARGER_BQ24190 = no; + CONFIG_CHARGER_BQ24257 = no; + CONFIG_CHARGER_BQ24735 = no; + CONFIG_CHARGER_BQ2515X = no; + CONFIG_CHARGER_BQ25890 = no; + CONFIG_CHARGER_BQ25980 = no; + CONFIG_CHARGER_BQ256XX = no; + CONFIG_CHARGER_SMB347 = no; + CONFIG_BATTERY_GAUGE_LTC2941 = no; + CONFIG_BATTERY_GOLDFISH = no; + CONFIG_BATTERY_RT5033 = no; + CONFIG_CHARGER_RT5033 = no; + CONFIG_CHARGER_RT9455 = no; + CONFIG_CHARGER_RT9467 = no; + CONFIG_CHARGER_RT9471 = no; + CONFIG_CHARGER_CROS_USBPD = no; + CONFIG_CHARGER_CROS_PCHG = no; + CONFIG_CHARGER_BD99954 = no; + CONFIG_CHARGER_WILCO = no; + CONFIG_BATTERY_SURFACE = no; + CONFIG_CHARGER_SURFACE = no; + CONFIG_BATTERY_UG3105 = no; + CONFIG_FUEL_GAUGE_MM8013 = no; + + CONFIG_GENERIC_IRQ_DEBUGFS = no; + + # Remove samba support + CONFIG_CIFS = no; + CONFIG_CIFS_ROOT = no; + + # Disable AMDGPU CIK support + CONFIG_DRM_AMDGPU_CIK = no; + + # Disable radeon drivers + CONFIG_DRM_RADEON = no; + CONFIG_FB_RADEON = no; + CONFIG_FB_RADEON_I2C = no; + CONFIG_FB_RADEON_BACKLIGHT = no; + + # Disable ngreedia drivers + CONFIG_NET_VENDOR_NVIDIA = no; + CONFIG_I2C_NVIDIA_GPU = no; + CONFIG_FB_NVIDIA = no; + CONFIG_FB_NVIDIA_I2C = no; + CONFIG_FB_NVIDIA_BACKLIGHT = no; + CONFIG_HID_NVIDIA_SHIELD = no; + CONFIG_TYPEC_NVIDIA_ALTMODE = no; + CONFIG_NVIDIA_WMI_EC_BACKLIGHT = no; + + # Firewire + CONFIG_FIREWIRE = no; + CONFIG_FIREWIRE_OHCI = no; + CONFIG_FIREWIRE_SBP2 = no; + CONFIG_FIREWIRE_NET = no; + CONFIG_FIREWIRE_NOSY = no; + + # MS surface HID + CONFIG_SURFACE_AGGREGATOR = no; + + DELL_RBTN = no; + DELL_RBU = no; + DELL_SMBIOS = no; + DELL_WMI = no; + DELL_WMI_AIO = no; + DELL_WMI_DESCRIPTOR = no; + DELL_WMI_LED = no; + DELL_WMI_SYSMAN = no; + + HID_A4TECH = no; + HID_ACRUX = no; + HID_ALPS = no; + HID_APPLEIR = no; + HID_ASUS = no; + HID_AUREAL = no; + HID_BETOP_FF = no; + HID_BIGBEN_FF = no; + HID_CMEDIA = no; + HID_COUGAR = no; + HID_CREATIVE_SB0540 = no; + HID_CYPRESS = no; + HID_DRAGONRISE = no; + HID_ELAN = no; + HID_ELECOM = no; + HID_ELO = no; + HID_EMS_FF = no; + HID_EZKEY = no; + HID_GEMBIRD = no; + HID_GFRM = no; + HID_GOOGLE_HAMMER = no; + HID_GREENASIA = no; + HID_GT683R = no; + HID_GYRATION = no; + HID_HOLTEK = no; + HID_HYPERV_MOUSE = no; + HID_ICADE = no; + HID_ITE = no; + HID_KEYTOUCH = no; + HID_KYE = no; + HID_LCPOWER = no; + HID_LED = no; + HID_MALTRON = no; + HID_MCP2221 = no; + HID_MONTEREY = no; + HID_MULTITOUCH = no; + HID_NTI = no; + HID_NTRIG = no; + HID_PANTHERLORD = no; + HID_PENMOUNT = no; + HID_PETALYNX = no; + HID_PICOLCD = no; + HID_PLAYSTATION = no; + HID_PRIMAX = no; + HID_REDRAGON = no; + HID_RETRODE = no; + HID_RMI = no; + HID_RMI4 = no; + HID_SAITEK = no; + HID_SAMSUNG = no; + HID_SEMITEK = no; + HID_SMARTJOYPLUS = no; + HID_SONY = no; + HID_SPEEDLINK = no; + HID_SUNPLUS = no; + HID_THINGM = no; + HID_THRUSTMASTER = no; + HID_TIVO = no; + HID_TOPSEED = no; + HID_TWINHAN = no; + HID_U2FZERO = no; + HID_UCLOGIC = no; + HID_UDRAW_PS3 = no; + HID_VIEWSONIC = no; + HID_VIVALDI = no; + HID_WALTOP = no; + HID_WIIMOTE = no; + HID_XINMO = no; + HID_ZEROPLUS = no; + HID_ZYDACRON = no; + + # Disable unused SOC modules + SND_SOC_CHV3_I2S = no; + SND_SOC_ADI = no; + SND_SOC_APPLE_MCA = no; + SND_ATMEL_SOC = no; + SND_DESIGNWARE_I2S = no; + SND_SOC_FSL_ASRC = no; + SND_SOC_FSL_SAI = no; + SND_SOC_FSL_MQS = no; + SND_SOC_FSL_AUDMIX = no; + SND_SOC_FSL_SSI = no; + SND_SOC_FSL_SPDIF = no; + SND_SOC_FSL_ESAI = no; + SND_SOC_FSL_MICFIL = no; + SND_SOC_FSL_EASRC = no; + SND_SOC_FSL_XCVR = no; + SND_SOC_FSL_UTILS = no; + SND_SOC_FSL_RPMSG = no; + SND_I2S_HI6210_I2S = no; + SND_SOC_IMG = no; + SND_SOC_STI = no; + SND_SOC_XILINX_I2S = no; + SND_SOC_XILINX_AUDIO_FORMATTER = no; + SND_SOC_XILINX_SPDIF = no; + SND_XEN_FRONTEND = no; + }; + } + ]; +} diff --git a/nyx/hosts/enyo/kernel/default.nix b/nyx/hosts/enyo/kernel/default.nix new file mode 100644 index 0000000..0ecbf2d --- /dev/null +++ b/nyx/hosts/enyo/kernel/default.nix @@ -0,0 +1,13 @@ +{ + config, + pkgs, + ... +}: let + inherit (config.networking) hostname; + inherit (pkgs.callPackage ./package.nix {inherit hostname;}) xanmod_custom; +in { + imports = [./config]; + config = { + modules.system.boot.kernel = pkgs.linuxPackagesFor xanmod_custom; + }; +} diff --git a/nyx/hosts/enyo/kernel/package.nix b/nyx/hosts/enyo/kernel/package.nix new file mode 100644 index 0000000..7645f4f --- /dev/null +++ b/nyx/hosts/enyo/kernel/package.nix @@ -0,0 +1,48 @@ +{ + lib, + fetchFromGitHub, + linuxKernel, + hostname ? "", + ... +}: let + inherit (lib.kernel) yes no freeform; + inherit (lib.attrsets) mapAttrs; + inherit (lib.modules) mkForce; + + version = "6.8.4"; + suffix = "xanmod1"; + modDirVersion = "${version}-${suffix}"; + + xanmod_custom = linuxKernel.kernels.linux_xanmod_latest.override { + inherit version suffix modDirVersion; + + # https://github.com/xanmod/linux + src = fetchFromGitHub { + owner = "xanmod"; + repo = "linux"; + rev = "refs/tags/${version}-xanmod1"; + hash = "sha256-NQeUz50aBRvbHqhoOGv5CFQKKlKeCUEkCA8uf9W0f0k="; + }; + + extraMakeFlags = ["KCFLAGS=-DAMD_PRIVATE_COLOR"]; + ignoreConfigErrors = true; + + # after booting to the new kernel + # use zcat /proc/config.gz | grep -i "" + # to check if the kernel options are set correctly + extraStructuredConfig = mapAttrs (_: mkForce) { + EXPERT = yes; + DEBUG_KERNEL = no; + WERROR = no; + + GCC_PLUGINS = yes; + BUG_ON_DATA_CORRUPTION = yes; + + CONFIG_LOCALVERSION = freeform "-${suffix}"; + CONFIG_LOCALVERSION_AUTO = yes; + CONFIG_DEFAULT_HOSTNAME = freeform "${hostname}"; + }; + }; +in { + inherit xanmod_custom; +} diff --git a/nyx/hosts/enyo/modules/default.nix b/nyx/hosts/enyo/modules/default.nix new file mode 100644 index 0000000..2b95fe0 --- /dev/null +++ b/nyx/hosts/enyo/modules/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./device.nix + ./profiles.nix + ./system.nix + ./usrEnv.nix + ./style.nix + ]; +} diff --git a/nyx/hosts/enyo/modules/device.nix b/nyx/hosts/enyo/modules/device.nix new file mode 100644 index 0000000..0749596 --- /dev/null +++ b/nyx/hosts/enyo/modules/device.nix @@ -0,0 +1,11 @@ +{ + config.modules.device = { + type = "desktop"; + cpu.type = "amd"; + gpu.type = "amd"; + monitors = ["DP-1" "HDMI-A-1"]; + hasBluetooth = true; + hasSound = true; + hasTPM = true; + }; +} diff --git a/nyx/hosts/enyo/modules/profiles.nix b/nyx/hosts/enyo/modules/profiles.nix new file mode 100644 index 0000000..4aa92d1 --- /dev/null +++ b/nyx/hosts/enyo/modules/profiles.nix @@ -0,0 +1,6 @@ +{ + config.modules.profiles = { + workstation.enable = true; + gaming.enable = true; + }; +} diff --git a/nyx/hosts/enyo/modules/style.nix b/nyx/hosts/enyo/modules/style.nix new file mode 100644 index 0000000..62dc44e --- /dev/null +++ b/nyx/hosts/enyo/modules/style.nix @@ -0,0 +1,49 @@ +{ + config, + pkgs, + ... +}: { + config.modules.style = { + forceGtk = true; + useKvantum = true; + + gtk = { + usePortal = true; + theme = { + name = "Catppuccin-Mocha-Standard-Blue-Dark"; + package = pkgs.catppuccin-gtk.override { + size = "standard"; + accents = ["blue"]; + variant = "mocha"; + tweaks = ["normal"]; + }; + }; + + iconTheme = { + name = "Papirus-Dark"; + package = pkgs.catppuccin-papirus-folders.override { + accent = "blue"; + flavor = "mocha"; + }; + }; + + font = { + name = "Lexend"; + size = 14; + }; + }; + + qt = { + theme = { + name = "Catppuccin-Mocha-Dark"; + package = pkgs.catppuccin-kde.override { + flavour = ["mocha"]; + accents = ["blue"]; + winDecStyles = ["modern"]; + }; + }; + + kdeglobals.source = "${config.modules.style.qt.theme.package}" + "/share/color-schemes/CatppuccinMochaBlue.colors"; + }; + }; +} diff --git a/nyx/hosts/enyo/modules/system.nix b/nyx/hosts/enyo/modules/system.nix new file mode 100644 index 0000000..5bcf41b --- /dev/null +++ b/nyx/hosts/enyo/modules/system.nix @@ -0,0 +1,74 @@ +{pkgs, ...}: { + config.modules.system = { + mainUser = "notashelf"; + fs = ["btrfs" "vfat" "ntfs" "exfat"]; + autoLogin = true; + + boot = { + loader = "systemd-boot"; + secureBoot = false; + enableKernelTweaks = true; + initrd.enableTweaks = true; + loadRecommendedModules = true; + tmpOnTmpfs = false; + plymouth = { + enable = true; + withThemes = false; + }; + }; + + containers = { + enabledContainers = ["alpha"]; + }; + + yubikeySupport.enable = true; + + video.enable = true; + sound.enable = true; + bluetooth.enable = false; + printing.enable = false; + emulation.enable = true; + + virtualization = { + enable = true; + qemu.enable = true; + docker.enable = true; + }; + + networking = { + optimizeTcp = true; + nftables.enable = true; + tailscale = { + enable = true; + isClient = true; + isServer = false; + }; + }; + + security = { + tor.enable = true; + fixWebcam = false; + lockModules = true; + auditd.enable = true; + }; + + programs = { + cli.enable = true; + gui.enable = true; + + spotify.enable = true; + + git.signingKey = "0x02D1DD3FA08B6B29"; + + gaming = { + enable = true; + }; + + default = { + terminal = "foot"; + }; + + libreoffice.enable = true; + }; + }; +} diff --git a/nyx/hosts/enyo/modules/usrEnv.nix b/nyx/hosts/enyo/modules/usrEnv.nix new file mode 100644 index 0000000..45fcf8e --- /dev/null +++ b/nyx/hosts/enyo/modules/usrEnv.nix @@ -0,0 +1,18 @@ +{ + config.modules.usrEnv = { + desktop = "Hyprland"; + desktops."i3".enable = true; + useHomeManager = true; + + programs = { + media.mpv.enable = true; + + launchers = { + anyrun.enable = true; + tofi.enable = true; + }; + + screenlock.swaylock.enable = true; + }; + }; +} diff --git a/nyx/hosts/enyo/networking.nix b/nyx/hosts/enyo/networking.nix new file mode 100644 index 0000000..c702291 --- /dev/null +++ b/nyx/hosts/enyo/networking.nix @@ -0,0 +1,91 @@ +{ + # we don't want the kernel setting up interfaces magically for us + boot.extraModprobeConfig = "options bonding max_bonds=0"; + networking = { + useDHCP = false; + useNetworkd = false; + }; + + systemd.network = { + enable = true; + + wait-online = { + enable = false; + anyInterface = true; + extraArgs = ["--ipv4"]; + }; + + networks = { + # leave the kernel dummy devies unmanagaed + "10-dummy" = { + matchConfig.Name = "dummy*"; + networkConfig = {}; + # linkConfig.ActivationPolicy = "always-down"; + linkConfig.Unmanaged = "yes"; + }; + + # let me configure tailscale manually + "20-tailscale-ignore" = { + matchConfig.Name = "tailscale*"; + linkConfig = { + Unmanaged = "yes"; + RequiredForOnline = false; + }; + }; + + # wired interfaces e.g. ethernet + "30-network-defaults-wired" = { + # matchConfig.Name = "en* | eth* | usb*"; + matchConfig.Type = "ether"; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = true; + IPForward = "yes"; + IPMasquerade = "no"; + }; + + dhcpV4Config = { + ClientIdentifier = "duid"; # "mac" + Use6RD = "yes"; + RouteMetric = 512; + UseDNS = false; + DUIDType = "link-layer"; + }; + + dhcpV6Config = { + RouteMetric = 512; + PrefixDelegationHint = "::64"; + UseDNS = false; + DUIDType = "link-layer"; + }; + }; + + # wireless interfaces e.g. network cards + "30-network-defaults-wireless" = { + # matchConfig.Name = "wl*"; + matchConfig.Type = "wlan"; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = true; + IPForward = "yes"; + IPMasquerade = "no"; + }; + + dhcpV4Config = { + ClientIdentifier = "mac"; + RouteMetric = 1500; + UseDNS = true; + DUIDType = "link-layer"; + Use6RD = "yes"; + }; + + dhcpV6Config = { + RouteMetric = 1500; + UseDNS = true; + DUIDType = "link-layer"; + PrefixDelegationHint = "::64"; + }; + }; + }; + }; +} diff --git a/nyx/hosts/enyo/system.nix b/nyx/hosts/enyo/system.nix new file mode 100644 index 0000000..cb95290 --- /dev/null +++ b/nyx/hosts/enyo/system.nix @@ -0,0 +1,6 @@ +{self, ...}: { + system = { + stateVersion = "23.05"; + configurationRevision = self.rev or "dirty"; + }; +} diff --git a/nyx/hosts/enyo/wireguard.nix b/nyx/hosts/enyo/wireguard.nix new file mode 100644 index 0000000..984421e --- /dev/null +++ b/nyx/hosts/enyo/wireguard.nix @@ -0,0 +1,29 @@ +{config, ...}: { + networking.firewall = { + allowedUDPPorts = [51820]; + }; + + boot.kernelModules = ["wireguard"]; + + # Wireguard Client Peer Setup + networking.wireguard = { + enable = true; + interfaces = { + wg0 = { + # General Settings + privateKeyFile = config.age.secrets.wg-client.path; + allowedIPsAsRoutes = true; + listenPort = 51820; + ips = ["10.255.255.11/32" "2a01:4f9:c010:2cf9:f::11/128"]; + peers = [ + { + allowedIPs = ["10.255.255.0/24" "2a01:4f9:c010:2cf9:f::/80"]; + endpoint = "128.140.91.216:51820"; + publicKey = "v3ol3QsgLPudVEtbETByQ0ABAOrJE2WcFfQ/PQAD8FM="; + persistentKeepalive = 30; + } + ]; + }; + }; + }; +} diff --git a/nyx/hosts/epimetheus/default.nix b/nyx/hosts/epimetheus/default.nix new file mode 100644 index 0000000..73c8480 --- /dev/null +++ b/nyx/hosts/epimetheus/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./fs + ./modules + + ./system.nix + ./encryption.nix + ]; +} diff --git a/nyx/hosts/epimetheus/encryption.nix b/nyx/hosts/epimetheus/encryption.nix new file mode 100644 index 0000000..89f8fb1 --- /dev/null +++ b/nyx/hosts/epimetheus/encryption.nix @@ -0,0 +1,19 @@ +{ + # mildly improves performance for the disk encryption + boot.initrd.availableKernelModules = [ + "aesni_intel" + "cryptd" + "usb_storage" + ]; + + boot.initrd.luks.devices."enc" = { + # improve performance on ssds + bypassWorkqueues = true; + keyFileSize = 4096; + # the device with the maching id will be searched for the key file + keyFile = "/dev/disk/by-id/usb-Generic_Flash_Disk_B314B63E-0:0"; + preLVM = true; + # if keyfile is not there, fall back to cryptsetup password + # fallbackToPassword = true; # IMPLIED BY config.boot.initrd.systemd.enable + }; +} diff --git a/nyx/hosts/epimetheus/fs/default.nix b/nyx/hosts/epimetheus/fs/default.nix new file mode 100644 index 0000000..a0a0ba1 --- /dev/null +++ b/nyx/hosts/epimetheus/fs/default.nix @@ -0,0 +1,46 @@ +{ + boot.initrd.luks.devices."enc".device = "/dev/disk/by-uuid/82144284-cf1d-4d65-9999-2e7cdc3c75d4"; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=root"]; + }; + + "/home" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=home"]; + }; + + "/nix" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=nix"]; + }; + + "/persist" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=persist"]; + neededForBoot = true; + }; + + "/var/log" = { + device = "/dev/disk/by-uuid/b79d3c8b-d511-4d66-a5e0-641a75440ada"; + fsType = "btrfs"; + options = ["subvol=log"]; + neededForBoot = true; + }; + + "/boot" = { + device = "/dev/disk/by-uuid/FDED-3BCF"; + fsType = "vfat"; + }; + }; + + swapDevices = [ + {device = "/dev/disk/by-uuid/0d1fc824-623b-4bb8-bf7b-63a3e657889d";} + ]; +} diff --git a/nyx/hosts/epimetheus/modules/default.nix b/nyx/hosts/epimetheus/modules/default.nix new file mode 100644 index 0000000..43e67d0 --- /dev/null +++ b/nyx/hosts/epimetheus/modules/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./device.nix + ./system.nix + ./usrEnv.nix + ]; +} diff --git a/nyx/hosts/epimetheus/modules/device.nix b/nyx/hosts/epimetheus/modules/device.nix new file mode 100644 index 0000000..18b267d --- /dev/null +++ b/nyx/hosts/epimetheus/modules/device.nix @@ -0,0 +1,11 @@ +{ + config.modules.device = { + type = "laptop"; + cpu.type = "intel"; + gpu.type = "hybrid-nv"; # nvidia drivers :b:roke + monitors = ["eDP-1"]; + hasBluetooth = true; + hasSound = true; + hasTPM = true; + }; +} diff --git a/nyx/hosts/epimetheus/modules/system.nix b/nyx/hosts/epimetheus/modules/system.nix new file mode 100644 index 0000000..fe320ef --- /dev/null +++ b/nyx/hosts/epimetheus/modules/system.nix @@ -0,0 +1,57 @@ +{ + config.modules.system = { + mainUser = "notashelf"; + fs = ["btrfs" "ext4" "vfat"]; + autoLogin = true; + + boot = { + secureBoot = false; + loader = "systemd-boot"; + enableKernelTweaks = true; + initrd.enableTweaks = true; + loadRecommendedModules = true; + tmpOnTmpfs = true; + }; + + encryption = { + enable = true; + device = "enc"; + }; + + video.enable = true; + sound.enable = true; + bluetooth.enable = false; + printing.enable = false; + emulation.enable = true; + + networking = { + optimizeTcp = true; + }; + + security = { + fixWebcam = false; + }; + + virtualization = { + enable = true; + docker.enable = false; + qemu.enable = true; + podman.enable = false; + }; + + programs = { + git.signingKey = "0x05A3BD53FEB32B81"; + + cli.enable = true; + gui.enable = true; + + gaming = { + enable = false; + chess.enable = false; + }; + default = { + terminal = "foot"; + }; + }; + }; +} diff --git a/nyx/hosts/epimetheus/modules/usrEnv.nix b/nyx/hosts/epimetheus/modules/usrEnv.nix new file mode 100644 index 0000000..ab2a6db --- /dev/null +++ b/nyx/hosts/epimetheus/modules/usrEnv.nix @@ -0,0 +1,7 @@ +{ + config.modules.usrEnv = { + isWayland = true; + desktop = "Hyprland"; + useHomeManager = true; + }; +} diff --git a/nyx/hosts/epimetheus/system.nix b/nyx/hosts/epimetheus/system.nix new file mode 100644 index 0000000..e3cac54 --- /dev/null +++ b/nyx/hosts/epimetheus/system.nix @@ -0,0 +1,59 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf mkForce optionals; + + dev = config.modules.device; +in { + config = { + fileSystems = { + "/".options = ["compress=zstd" "noatime"]; + "/home".options = ["compress=zstd"]; + "/nix".options = ["compress=zstd" "noatime"]; + "/var/log".options = ["compress=zstd" "noatime"]; + "/persist".options = ["compress=zstd" "noatime"]; + }; + + hardware = { + nvidia = mkIf (builtins.elem dev.gpu ["nvidia" "hybrid-nv"]) { + nvidiaPersistenced = mkForce false; + + open = mkForce false; + + prime = { + offload.enable = mkForce true; + # Bus ID of the Intel GPU. You can find it using lspci, either under 3D or VGA + intelBusId = "PCI:0:2:0"; + + # Bus ID of the NVIDIA GPU. You can find it using lspci, either under 3D or VGA + nvidiaBusId = "PCI:1:0:0"; + }; + }; + }; + + boot = { + kernelParams = + [ + "nohibernate" + # The passive default severely degrades performance. + "intel_pstate=active" + ] + ++ optionals ((dev.cpu == "intel") && (dev.gpu != "hybrid-nv")) [ + "i915.enable_fbc=1" + "i915.enable_psr=2" + ]; + + kernelModules = [ + "sdhci" # fix microsd cards + ]; + }; + + services.btrfs.autoScrub = {fileSystems = ["/"];}; + + home-manager.users.notashelf.systemd.user.startServices = "legacy"; + + console.earlySetup = true; + }; +} diff --git a/nyx/hosts/erebus/default.nix b/nyx/hosts/erebus/default.nix new file mode 100644 index 0000000..ff8d74e --- /dev/null +++ b/nyx/hosts/erebus/default.nix @@ -0,0 +1,11 @@ +{ + imports = [ + ./system # system configuration + ./virtualization.nix # configure virtual machine + ./yubikey.nix # configure yubikey toolkit + ]; + + config = { + system.stateVersion = "23.11"; + }; +} diff --git a/nyx/hosts/erebus/system/default.nix b/nyx/hosts/erebus/system/default.nix new file mode 100644 index 0000000..63d3674 --- /dev/null +++ b/nyx/hosts/erebus/system/default.nix @@ -0,0 +1,56 @@ +# NixOS livesystem to generate yubikeys in an air-gapped manner +# $ nix build .#images.erebus +{ + config, + lib, + pkgs, + ... +}: { + # Secure defaults + nixpkgs.config = {allowBroken = false;}; # false breaks zfs kernel - but we don't care about zfs + + # Always copytoram so that, if the image is booted from, e.g., a + # USB stick, nothing is mistakenly written to persistent storage. + boot = { + kernelParams = ["copytoram"]; + tmp.cleanOnBoot = true; + kernel.sysctl = {"kernel.unprivileged_bpf_disabled" = 1;}; + }; + + # make sure we are air-gapped + networking = { + wireless.enable = false; + dhcpcd.enable = false; + }; + + services.getty.helpLine = "The 'root' account has an empty password."; + + isoImage.isoBaseName = lib.mkForce config.networking.hostName; + + # words cannot express how much I hate zfs + boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages; + + environment = { + # needed for i3blocks + pathsToLink = ["/libexec"]; + # fix an annoying warning + etc."mdadm.conf".text = '' + MAILADDR root + ''; + }; + + fonts = { + fontDir = { + enable = true; + decompressFonts = true; + }; + + fontconfig.enable = true; + + packages = with pkgs; [ + noto-fonts + noto-fonts-cjk + noto-fonts-color-emoji + ]; + }; +} diff --git a/nyx/hosts/erebus/system/desktop.nix b/nyx/hosts/erebus/system/desktop.nix new file mode 100644 index 0000000..ffda51a --- /dev/null +++ b/nyx/hosts/erebus/system/desktop.nix @@ -0,0 +1,46 @@ +{pkgs, ...}: { + security.sudo.wheelNeedsPassword = false; + + users.users.yubikey = { + isNormalUser = true; + extraGroups = ["wheel"]; + shell = pkgs.zsh; + }; + + programs.dconf.enable = true; + + services = { + gvfs.enable = true; + + autorandr.enable = true; + + xserver = { + enable = true; + layout = "tr"; + displayManager = { + autoLogin.enable = true; + autoLogin.user = "yubikey"; + defaultSession = "none+i3"; + }; + + desktopManager = { + xterm.enable = false; + }; + + # i3 for window management + windowManager.i3 = { + enable = true; + package = pkgs.i3-gaps; + + extraPackages = with pkgs; [ + st # suckless terminal that sucks, pretty minimal though + rofi # alternative to dmenu, usually better + dmenu # application launcher most people use + i3status # gives you the default i3 status bar + i3lock # default i3 screen locker + i3blocks # if you are planning on using i3blocks over i3status + ]; + }; + }; + }; +} diff --git a/nyx/hosts/erebus/virtualization.nix b/nyx/hosts/erebus/virtualization.nix new file mode 100644 index 0000000..8c203b1 --- /dev/null +++ b/nyx/hosts/erebus/virtualization.nix @@ -0,0 +1,9 @@ +{ + virtualisation.vmVariant = { + # let the built VM be more responsive + virtualisation = { + memorySize = 4096; + cores = 3; + }; + }; +} diff --git a/nyx/hosts/erebus/yubikey.nix b/nyx/hosts/erebus/yubikey.nix new file mode 100644 index 0000000..f02ba01 --- /dev/null +++ b/nyx/hosts/erebus/yubikey.nix @@ -0,0 +1,127 @@ +{ + config, + lib, + pkgs, + ... +}: let + drduhConfig = pkgs.fetchFromGitHub { + owner = "drduh"; + repo = "config"; + rev = "6bea1fdaa8732ec8625f4bac7022b25e14b15ffe"; + hash = "sha256-Fto8FCVYeKviMz0VmCiXHrgMT1pVopJGGDHF0s3K4ts="; + }; + + gpg-conf = "${drduhConfig}/gpg.conf"; + + yubico-guide = pkgs.stdenv.mkDerivation { + name = "yubikey-guide.html"; + src = pkgs.fetchFromGitHub { + owner = "drduh"; + repo = "YubiKey-Guide"; + rev = "fec6e92b8f05c899eccc7f2f2b273d609ed6094e"; + hash = "sha256-N76e/yhXUoWUK6EQZHGyTs0DcbZqAlI5xtQMf0squR8="; + }; + buildInputs = [pkgs.pandoc]; + installPhase = "pandoc --highlight-style pygments -s --toc README.md -o $out"; + }; + + guide = "${yubico-guide}/README.md"; + contrib = "${yubico-guide}/contrib"; + + # Instead of hard-coding the pinentry program, chose the appropriate one + # based on the environment of the image the user has chosen to build. + gpg-agent-conf = pkgs.runCommand "gpg-agent.conf" {} '' + sed '/pinentry-program/d' ${drduhConfig}/gpg-agent.conf > $out + echo "pinentry-program ${pkgs.pinentry.${pinentryFlavour}}/bin/pinentry" >> $out + ''; + + xserverCfg = config.services.xserver; + pinentryFlavour = + if xserverCfg.desktopManager.lxqt.enable || xserverCfg.desktopManager.plasma5.enable + then "qt" + else if xserverCfg.desktopManager.xfce.enable + then "gtk2" + else if xserverCfg.enable || config.programs.sway.enable + then "gnome3" + else "curses"; + + view-yubikey-guide = pkgs.writeShellScriptBin "view-yubikey-guide" '' + viewer="$(type -P xdg-open || true)" + if [ -z "$viewer" ]; then + viewer="${pkgs.glow}/bin/glow -p" + fi + exec $viewer "${guide}" + ''; + + shortcut = pkgs.makeDesktopItem { + name = "yubikey-guide"; + icon = "${pkgs.yubikey-manager-qt}/share/ykman-gui/icons/ykman.png"; + desktopName = "drduh's YubiKey Guide"; + genericName = "Guide to using YubiKey for GPG and SSH"; + comment = "Open the guide in a reader program"; + categories = ["Documentation"]; + exec = "${view-yubikey-guide}/bin/view-yubikey-guide"; + }; + + yubikey-guide = pkgs.symlinkJoin { + name = "yubikey-guide"; + paths = [view-yubikey-guide shortcut]; + }; +in { + environment.interactiveShellInit = '' + # unset HISTFILE + export GNUPGHOME="/run/user/$(id -u)/gnupg" + if [ ! -d "$GNUPGHOME" ]; then + echo "Creating \$GNUPGHOME…" + install --verbose -m=0700 --directory="$GNUPGHOME" + fi + [ ! -f "$GNUPGHOME/gpg.conf" ] && cp --verbose ${gpg-conf} "$GNUPGHOME/gpg.conf" + [ ! -f "$GNUPGHOME/gpg-agent.conf" ] && cp --verbose ${gpg-agent-conf} "$GNUPGHOME/gpg-agent.conf" + echo "\$GNUPGHOME is \"$GNUPGHOME\"" + ''; + + # Yubikey Tooling + environment.systemPackages = with pkgs; [ + yubikey-personalization + cryptsetup + pwgen + midori + paperkey + gnupg + ctmg + ]; + + services = { + udev.packages = with pkgs; [yubikey-personalization]; + pcscd.enable = true; + }; + + programs = { + ssh.startAgent = false; + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + }; + + services.xserver.displayManager.sessionCommands = '' + ${lib.getExe pkgs.zathura} ${guide} & + ${lib.getExe pkgs.kitty} & + ''; + + # Copy the contents of contrib to the home directory, add a shortcut to + # the guide on the desktop, and link to the whole repo in the documents + # folder. + system.activationScripts.yubikeyGuide = let + homeDir = "/home/nixos/"; + desktopDir = homeDir + "Desktop/"; + documentsDir = homeDir + "Documents/"; + in '' + mkdir -p ${desktopDir} ${documentsDir} + chown nixos ${homeDir} ${desktopDir} ${documentsDir} + + cp -R ${contrib}/* ${homeDir} + ln -sf ${yubikey-guide}/share/applications/yubikey-guide.desktop ${desktopDir} + ln -sfT ${yubikey-guide} ${documentsDir}/YubiKey-Guide + ''; +} diff --git a/nyx/hosts/gaea/default.nix b/nyx/hosts/gaea/default.nix new file mode 100644 index 0000000..f31d922 --- /dev/null +++ b/nyx/hosts/gaea/default.nix @@ -0,0 +1,30 @@ +{ + config, + lib, + ... +}: let + inherit (lib) optionalString; +in { + imports = [ + ./system + ]; + + services.getty.helpLine = + '' + The "nixos" and "root" accounts have empty passwords. + An ssh daemon is running. You then must set a password + for either "root" or "nixos" with `passwd` or add an ssh key + to /home/nixos/.ssh/authorized_keys be able to login. + If you need a wireless connection, you may use networkmanager + by invoking `nmcli` or `nmtui`, the ncurses interface. + '' + + optionalString config.services.xserver.enable '' + Type `sudo systemctl start display-manager' to + start the graphical user interface. + ''; + + # since we don't inherit the core module, this needs to be set here manually + # otherwise we'll see the stateVersion error - which doesn't actually matter inside the ISO + # but still annoying and slows down nix flake check + system.stateVersion = "23.11"; +} diff --git a/nyx/hosts/gaea/system/default.nix b/nyx/hosts/gaea/system/default.nix new file mode 100644 index 0000000..5d85a74 --- /dev/null +++ b/nyx/hosts/gaea/system/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./programs + ]; +} diff --git a/nyx/hosts/gaea/system/programs/default.nix b/nyx/hosts/gaea/system/programs/default.nix new file mode 100644 index 0000000..ae15d84 --- /dev/null +++ b/nyx/hosts/gaea/system/programs/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./neovim + + ./git.nix + ]; +} diff --git a/nyx/hosts/gaea/system/programs/git.nix b/nyx/hosts/gaea/system/programs/git.nix new file mode 100644 index 0000000..d8ac829 --- /dev/null +++ b/nyx/hosts/gaea/system/programs/git.nix @@ -0,0 +1,6 @@ +{ + programs.git = { + enable = true; + lfs.enable = true; + }; +} diff --git a/nyx/hosts/gaea/system/programs/neovim/config/init.vim b/nyx/hosts/gaea/system/programs/neovim/config/init.vim new file mode 100644 index 0000000..6640127 --- /dev/null +++ b/nyx/hosts/gaea/system/programs/neovim/config/init.vim @@ -0,0 +1,71 @@ +"vi:filetype=vim + +" add ~/.vim to the beginning of the runtimepath +set runtimepath^=~/.vim + +" set the packpath to the runtimepath +let &packpath = &runtimepath + +" for plugins to load correctly +filetype plugin indent on + +" don't try to be vi compatible +set nocompatible + +" use system clipboard +set clipboard+=unnamedplus + +" syntax highlighting +syntax enable + +" display line numbers +set number relativenumber + +" enable mouse support in all modes +set mouse=a + +" set indentation to spaces instead of tabs +set noexpandtab + +" number of spaces to use for each step of (auto)indent +set shiftwidth=2 + +" number of spaces that a in the file counts for +set tabstop=2 + +" C-style indenting +set cindent + +" 'smart' indenting +set smartindent + +" set the indent of new lines +set autoindent + +" set the folding method based on syntax +set foldmethod=syntax + + +" spaces instead of tabs for indentation +set expandtab + +" 'smart' tabs that respects 'shiftwidth' for indentation +set smarttab + +" number of spaces a in the file counts for +set tabstop=4 + +" number of spaces to use for each step of (auto)indent +set shiftwidth=0 + +" define backspace behavior in insert mode: +" - 'indent': allows backspace to delete auto-indentation at the start of a line +" - 'eol': enables backspace to delete the end-of-line character, acting as line deletion +" - 'start': allows backspace to delete past the start of insert or typeahead +set backspace=indent,eol,start + + +" spell Checking +set spelllang=en " spell check langs +set spellsuggest=best,9 " suggestions for spelling corrections + diff --git a/nyx/hosts/gaea/system/programs/neovim/config/maps.vim b/nyx/hosts/gaea/system/programs/neovim/config/maps.vim new file mode 100644 index 0000000..1fbc549 --- /dev/null +++ b/nyx/hosts/gaea/system/programs/neovim/config/maps.vim @@ -0,0 +1,9 @@ +" map key to toggle between hiding/showing current line +nmap zA + +" map key to toggle between reducing/enlarging fold level +nmap zR + +" map key to fold everything except the cursor line +nmap zM + diff --git a/nyx/hosts/gaea/system/programs/neovim/config/plugins.vim b/nyx/hosts/gaea/system/programs/neovim/config/plugins.vim new file mode 100644 index 0000000..cea4f4a --- /dev/null +++ b/nyx/hosts/gaea/system/programs/neovim/config/plugins.vim @@ -0,0 +1,16 @@ +" customize label for vim-sneak +let g:sneak#label = 1 + +" Toggle spell checking in normal mode +nnoremap :set spell! + +" Toggle spell checking in insert mode +inoremap :set spell! + +lua << EOF +require('nvim-treesitter.configs').setup { + highlight = { + enable = true + } +} +EOF diff --git a/nyx/hosts/gaea/system/programs/neovim/default.nix b/nyx/hosts/gaea/system/programs/neovim/default.nix new file mode 100644 index 0000000..9ee0db6 --- /dev/null +++ b/nyx/hosts/gaea/system/programs/neovim/default.nix @@ -0,0 +1,73 @@ +{pkgs, ...}: let + inherit (builtins) readFile; +in { + programs = { + neovim = { + enable = true; + + viAlias = true; + vimAlias = true; + defaultEditor = true; + + configure = { + customRC = '' + " -- init -- + ${readFile ./config/init.vim} + " -- mappings -- + ${readFile ./config/maps.vim} + " -- plugin configs -- + ${readFile ./config/plugins.vim} + ''; + + packages.myVimPackage = with pkgs.vimPlugins; { + start = [ + # general utils + direnv-vim # direnv for vim + dressing-nvim # better UI components + + leap-nvim # navigation + lualine-nvim # statusline + tabular # align text according to regexp + undotree # undo history + vim-css-color # highlight CSS colors + vim-signature # marks on signcolumn + which-key-nvim # mapping manager and cheatsheet + vim-sneak + + # completion + nvim-cmp + cmp-buffer + cmp-cmdline + cmp-nvim-lsp + cmp-path + cmp_luasnip + + comment-nvim + todo-comments-nvim + + luasnip + friendly-snippets + + nvim-lspconfig + nvim-lint + fidget-nvim + aerial-nvim + + telescope-nvim # list of files interface + telescope-file-browser-nvim + telescope-fzy-native-nvim + + vim-fugitive # git in vim + gitsigns-nvim + + targets-vim # text objects + vim-surround + vim-expand-region + + nvim-treesitter.withAllGrammars # better highlighting + ]; + }; + }; + }; + }; +} diff --git a/nyx/hosts/helios/default.nix b/nyx/hosts/helios/default.nix new file mode 100644 index 0000000..bba6ac2 --- /dev/null +++ b/nyx/hosts/helios/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./fs + ./modules + + ./system.nix + ./nftables.nix + ]; +} diff --git a/nyx/hosts/helios/fs/default.nix b/nyx/hosts/helios/fs/default.nix new file mode 100644 index 0000000..b492032 --- /dev/null +++ b/nyx/hosts/helios/fs/default.nix @@ -0,0 +1,13 @@ +{ + imports = [./external.nix]; + config = { + fileSystems."/" = { + device = "/dev/disk/by-uuid/783e926f-acd7-4684-a7b3-f5b1ecefa11b"; + fsType = "ext4"; + }; + + swapDevices = [ + {device = "/dev/disk/by-uuid/d1d77f8e-7c77-40c9-a5e8-59d962f4d397";} + ]; + }; +} diff --git a/nyx/hosts/helios/fs/external.nix b/nyx/hosts/helios/fs/external.nix new file mode 100644 index 0000000..e47f759 --- /dev/null +++ b/nyx/hosts/helios/fs/external.nix @@ -0,0 +1,6 @@ +{ + fileSystems."/srv/storage" = { + device = "/dev/disk/by-uuid/19ea8fad-b930-4a48-99e1-04633b2142f8"; + fsType = "ext4"; + }; +} diff --git a/nyx/hosts/helios/modules/default.nix b/nyx/hosts/helios/modules/default.nix new file mode 100644 index 0000000..3253a52 --- /dev/null +++ b/nyx/hosts/helios/modules/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./device.nix + ./system.nix + ./usrEnv.nix + ./services.nix + ]; +} diff --git a/nyx/hosts/helios/modules/device.nix b/nyx/hosts/helios/modules/device.nix new file mode 100644 index 0000000..4f950e8 --- /dev/null +++ b/nyx/hosts/helios/modules/device.nix @@ -0,0 +1,10 @@ +{ + config.modules.device = { + type = "server"; + cpu.type = "amd"; + gpu.type = null; + hasBluetooth = false; + hasSound = false; + hasTPM = false; + }; +} diff --git a/nyx/hosts/helios/modules/services.nix b/nyx/hosts/helios/modules/services.nix new file mode 100644 index 0000000..abd7efd --- /dev/null +++ b/nyx/hosts/helios/modules/services.nix @@ -0,0 +1,39 @@ +{ + config.modules.system.services = { + nextcloud.enable = true; + mailserver.enable = true; + vaultwarden.enable = true; + forgejo.enable = true; + searxng.enable = true; + reposilite.enable = true; + + social = { + mastodon.enable = true; + matrix.enable = true; + }; + + bincache = { + harmonia.enable = true; + }; + + networking = { + headscale.enable = true; + wireguard.enable = true; + }; + + monitoring = { + grafana.enable = true; + prometheus.enable = true; + loki.enable = true; + uptime-kuma.enable = true; + }; + + database = { + mysql.enable = false; + mongodb.enable = false; + redis.enable = true; + postgresql.enable = true; + garage.enable = true; + }; + }; +} diff --git a/nyx/hosts/helios/modules/system.nix b/nyx/hosts/helios/modules/system.nix new file mode 100644 index 0000000..a58e0e5 --- /dev/null +++ b/nyx/hosts/helios/modules/system.nix @@ -0,0 +1,44 @@ +{pkgs, ...}: { + config.modules.system = { + mainUser = "notashelf"; + fs = ["vfat" "exfat" "ext4"]; + video.enable = false; + sound.enable = false; + bluetooth.enable = false; + printing.enable = false; + + boot = { + secureBoot = false; + kernel = pkgs.linuxPackages_latest; + loader = "grub"; + enableKernelTweaks = true; + initrd.enableTweaks = true; + loadRecommendedModules = true; + tmpOnTmpfs = false; + }; + + virtualization = { + enable = true; + qemu.enable = true; + docker.enable = true; + }; + + networking = { + optimizeTcp = false; + tarpit.enable = true; + nftables.enable = true; + tailscale = { + enable = true; + isServer = true; + isClient = false; + }; + }; + + programs = { + git.signingKey = ""; + + cli.enable = true; + gui.enable = false; + }; + }; +} diff --git a/nyx/hosts/helios/modules/usrEnv.nix b/nyx/hosts/helios/modules/usrEnv.nix new file mode 100644 index 0000000..63e19db --- /dev/null +++ b/nyx/hosts/helios/modules/usrEnv.nix @@ -0,0 +1,5 @@ +{ + config.modules.usrEnv = { + useHomeManager = true; + }; +} diff --git a/nyx/hosts/helios/nftables.nix b/nyx/hosts/helios/nftables.nix new file mode 100644 index 0000000..581a48f --- /dev/null +++ b/nyx/hosts/helios/nftables.nix @@ -0,0 +1,47 @@ +{lib, ...}: let + inherit (lib) entryBetween; +in { + networking.nftables.rules = { + inet.filter.input = { + # endlessh + endlessh = entryBetween ["basic-icmp6" "basic-icmp" "ping6" "ping"] ["default"] { + protocol = "tcp"; + field = "dport"; + value = [22]; + policy = "accept"; + }; + + # this allows nginx to respond to the domain challenges without passing each service through the firewall + https = entryBetween ["basic-icmp6" "basic-icmp" "ping6" "ping"] ["default"] { + protocol = "tcp"; + field = "dport"; + value = [443]; + policy = "accept"; + }; + + headscale = entryBetween ["basic-icmp6" "basic-icmp" "ping6" "ping"] ["default"] { + protocol = "udp"; + field = "dport"; + value = [8344]; + policy = "accept"; + }; + + # NOTE: snm has an option to enable firewall ports by default, but my nftables abstractions + # do not allow for us to use that option, so we'll just open the ports manually + # I could probably add an entry that propagates the tcpPorts option to the firewall + # but that doesn not seem like a very good option since we'll not be able to control policies + simple-nixos-mailserver = entryBetween ["basic-icmp6" "basic-icmp" "ping6" "ping"] ["default"] { + protocol = "tcp"; + field = "dport"; + value = [ + 25 # smtp + 80 # used for acme-nginx domain challenges + 143 # imap + 993 # imapSsl + 465 # smtpSsl + ]; + policy = "accept"; + }; + }; + }; +} diff --git a/nyx/hosts/helios/system.nix b/nyx/hosts/helios/system.nix new file mode 100644 index 0000000..14ad983 --- /dev/null +++ b/nyx/hosts/helios/system.nix @@ -0,0 +1,25 @@ +{ + config, + lib, + ... +}: { + config = { + networking.domain = "notashelf.dev"; + services.smartd.enable = lib.mkForce false; + + boot = { + growPartition = !config.boot.initrd.systemd.enable; + loader.grub = { + enable = true; + useOSProber = lib.mkForce false; + efiSupport = lib.mkForce false; + enableCryptodisk = false; + theme = null; + backgroundColor = null; + splashImage = null; + device = lib.mkForce "/dev/disk/by-label/nixos"; + forceInstall = true; + }; + }; + }; +} diff --git a/nyx/hosts/hermes/default.nix b/nyx/hosts/hermes/default.nix new file mode 100644 index 0000000..479aac1 --- /dev/null +++ b/nyx/hosts/hermes/default.nix @@ -0,0 +1,10 @@ +{ + imports = [ + ./fs + ./modules + + ./encryption.nix + ./networking.nix + ./system.nix + ]; +} diff --git a/nyx/hosts/hermes/encryption.nix b/nyx/hosts/hermes/encryption.nix new file mode 100644 index 0000000..3137a16 --- /dev/null +++ b/nyx/hosts/hermes/encryption.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + ... +}: { + # mildly improves performance for the disk encryption + boot.initrd.availableKernelModules = [ + "aesni_intel" + "cryptd" + "usb_storage" + ]; + + services.lvm.enable = lib.mkForce true; + + boot.initrd.luks.devices."enc" = { + # improve performance on ssds + bypassWorkqueues = true; + preLVM = true; + + # the device with the maching id will be searched for the key file + # keyFile = "/dev/disk/by-id/usb-Generic_Flash_Disk_B314B63E-0:0"; + # keyFileSize = 4096; + + # if keyfile is not there, fall back to cryptsetup password + fallbackToPassword = !config.boot.initrd.systemd.enable; # IMPLIED BY config.boot.initrd.systemd.enable + }; +} diff --git a/nyx/hosts/hermes/fs/default.nix b/nyx/hosts/hermes/fs/default.nix new file mode 100644 index 0000000..beb8432 --- /dev/null +++ b/nyx/hosts/hermes/fs/default.nix @@ -0,0 +1,46 @@ +{ + boot.initrd.luks.devices."enc".device = "/dev/disk/by-uuid/0eb8b547-3644-4d49-a4e9-c28c395b8568"; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/c9527aaf-947d-4dc0-88ab-3af438e3f5b1"; + fsType = "btrfs"; + options = ["subvol=root" "compress=zstd" "noatime"]; + }; + + "/boot" = { + device = "/dev/disk/by-uuid/4F12-E737"; + fsType = "vfat"; + }; + + "/nix" = { + device = "/dev/disk/by-uuid/c9527aaf-947d-4dc0-88ab-3af438e3f5b1"; + fsType = "btrfs"; + options = ["subvol=nix" "compress=zstd" "noatime"]; + }; + + "/persist" = { + device = "/dev/disk/by-uuid/c9527aaf-947d-4dc0-88ab-3af438e3f5b1"; + fsType = "btrfs"; + neededForBoot = true; + options = ["subvol=persist" "compress=zstd" "noatime"]; + }; + + "/var/log" = { + device = "/dev/disk/by-uuid/c9527aaf-947d-4dc0-88ab-3af438e3f5b1"; + fsType = "btrfs"; + neededForBoot = true; + options = ["subvol=log" "compress=zstd" "noatime"]; + }; + + "/home" = { + device = "/dev/disk/by-uuid/c9527aaf-947d-4dc0-88ab-3af438e3f5b1"; + fsType = "btrfs"; + options = ["subvol=home" "compress=zstd"]; + }; + }; + + swapDevices = [ + {device = "/dev/disk/by-uuid/b55b09f2-b567-4fbf-9150-b05b91710ca2";} + ]; +} diff --git a/nyx/hosts/hermes/modules/default.nix b/nyx/hosts/hermes/modules/default.nix new file mode 100644 index 0000000..2b95fe0 --- /dev/null +++ b/nyx/hosts/hermes/modules/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./device.nix + ./profiles.nix + ./system.nix + ./usrEnv.nix + ./style.nix + ]; +} diff --git a/nyx/hosts/hermes/modules/device.nix b/nyx/hosts/hermes/modules/device.nix new file mode 100644 index 0000000..c86f1f1 --- /dev/null +++ b/nyx/hosts/hermes/modules/device.nix @@ -0,0 +1,15 @@ +{ + modules.device = { + type = "laptop"; + cpu = { + type = "amd"; + amd.pstate.enable = true; + amd.zenpower.enable = true; + }; + gpu.type = "amd"; + monitors = ["eDP-1"]; + hasBluetooth = true; + hasSound = true; + hasTPM = true; + }; +} diff --git a/nyx/hosts/hermes/modules/profiles.nix b/nyx/hosts/hermes/modules/profiles.nix new file mode 100644 index 0000000..4aa92d1 --- /dev/null +++ b/nyx/hosts/hermes/modules/profiles.nix @@ -0,0 +1,6 @@ +{ + config.modules.profiles = { + workstation.enable = true; + gaming.enable = true; + }; +} diff --git a/nyx/hosts/hermes/modules/style.nix b/nyx/hosts/hermes/modules/style.nix new file mode 100644 index 0000000..7514a35 --- /dev/null +++ b/nyx/hosts/hermes/modules/style.nix @@ -0,0 +1,48 @@ +{ + config, + pkgs, + ... +}: { + config.modules.style = { + forceGtk = true; + + gtk = { + usePortal = true; + theme = { + name = "Catppuccin-Mocha-Standard-Blue-Dark"; + package = pkgs.catppuccin-gtk.override { + size = "standard"; + accents = ["blue"]; + variant = "mocha"; + tweaks = ["normal"]; + }; + }; + + iconTheme = { + name = "Papirus-Dark"; + package = pkgs.catppuccin-papirus-folders.override { + accent = "blue"; + flavor = "mocha"; + }; + }; + + font = { + name = "Lexend"; + size = 14; + }; + }; + + qt = { + theme = { + name = "Catppuccin-Mocha-Dark"; + package = pkgs.catppuccin-kde.override { + flavour = ["mocha"]; + accents = ["blue"]; + winDecStyles = ["modern"]; + }; + }; + + kdeglobals.source = "${config.modules.style.qt.theme.package}" + "/share/color-schemes/CatppuccinMochaBlue.colors"; + }; + }; +} diff --git a/nyx/hosts/hermes/modules/system.nix b/nyx/hosts/hermes/modules/system.nix new file mode 100644 index 0000000..a3c1b73 --- /dev/null +++ b/nyx/hosts/hermes/modules/system.nix @@ -0,0 +1,71 @@ +{pkgs, ...}: { + modules.system = { + mainUser = "notashelf"; + fs = ["btrfs" "ext4" "vfat"]; + impermanence.root.enable = true; + + boot = { + secureBoot = false; + kernel = pkgs.linuxPackages_xanmod_latest; + plymouth.enable = true; + loader = "systemd-boot"; + enableKernelTweaks = true; + initrd.enableTweaks = true; + loadRecommendedModules = true; + tmpOnTmpfs = true; + }; + + encryption = { + enable = true; + device = "enc"; + }; + + yubikeySupport.enable = true; + autoLogin = true; + + video.enable = true; + sound.enable = true; + bluetooth.enable = true; + printing.enable = true; + emulation.enable = true; + + networking = { + optimizeTcp = true; + nftables.enable = true; + tailscale = { + enable = true; + isClient = true; + }; + }; + + security = { + fixWebcam = false; + lockModules = true; + usbguard.enable = true; + }; + + virtualization = { + enable = true; + docker.enable = false; + qemu.enable = true; + podman.enable = false; + }; + + programs = { + cli.enable = true; + gui.enable = true; + + spotify.enable = true; + + git.signingKey = "0x02D1DD3FA08B6B29"; + + gaming = { + enable = true; + }; + + default = { + terminal = "foot"; + }; + }; + }; +} diff --git a/nyx/hosts/hermes/modules/usrEnv.nix b/nyx/hosts/hermes/modules/usrEnv.nix new file mode 100644 index 0000000..43bd057 --- /dev/null +++ b/nyx/hosts/hermes/modules/usrEnv.nix @@ -0,0 +1,17 @@ +{ + modules.usrEnv = { + desktop = "Hyprland"; + useHomeManager = true; + + programs = { + media.mpv.enable = true; + + launchers = { + anyrun.enable = true; + tofi.enable = true; + }; + + screenlock.swaylock.enable = true; + }; + }; +} diff --git a/nyx/hosts/hermes/networking.nix b/nyx/hosts/hermes/networking.nix new file mode 100644 index 0000000..d2f559b --- /dev/null +++ b/nyx/hosts/hermes/networking.nix @@ -0,0 +1,93 @@ +{ + # we don't want the kernel setting up interfaces magically for us + boot.extraModprobeConfig = "options bonding max_bonds=0"; + networking = { + useDHCP = false; + useNetworkd = false; + }; + + systemd.network = { + enable = true; + + wait-online = { + enable = false; + anyInterface = true; + extraArgs = ["--ipv4"]; + }; + + networks = { + # leave the kernel dummy devies unmanagaed + "10-dummy" = { + matchConfig.Name = "dummy*"; + networkConfig = {}; + # linkConfig.ActivationPolicy = "always-down"; + linkConfig.Unmanaged = "yes"; + }; + + # let me configure tailscale manually + "20-tailscale-ignore" = { + matchConfig.Name = "tailscale*"; + linkConfig = { + Unmanaged = "yes"; + RequiredForOnline = false; + }; + }; + + "30-network-defaults-wired" = { + # matchConfig.Name = "en* | eth* | usb*"; + matchConfig.Type = "ether"; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = true; + IPForward = "yes"; + IPMasquerade = "no"; + }; + + dhcpV4Config = { + ClientIdentifier = "duid"; # "mac" + Use6RD = "yes"; + RouteMetric = 512; + UseDNS = false; + DUIDType = "link-layer"; + }; + + dhcpV6Config = { + RouteMetric = 512; + PrefixDelegationHint = "::64"; + UseDNS = false; + DUIDType = "link-layer"; + }; + }; + + "30-network-defaults-wireless" = { + # matchConfig.Name = "wl*"; + matchConfig.Type = "wlan"; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = true; + IPForward = "yes"; + IPMasquerade = "no"; + }; + + dhcpV4Config = { + ClientIdentifier = "mac"; + RouteMetric = 1500; + UseDNS = true; + DUIDType = "link-layer"; + Use6RD = "yes"; + }; + + dhcpV6Config = { + RouteMetric = 1500; + UseDNS = true; + DUIDType = "link-layer"; + # routes = [ + # { routeConfig = { Gateway = "_dhcp4"; Metric = 1500; }; } + # { routeConfig = { Gateway = "_ipv6ra"; Metric = 1500; }; } + # ]; + PrefixDelegationHint = "::64"; + }; + }; + }; + }; +} diff --git a/nyx/hosts/hermes/system.nix b/nyx/hosts/hermes/system.nix new file mode 100644 index 0000000..a6294eb --- /dev/null +++ b/nyx/hosts/hermes/system.nix @@ -0,0 +1,13 @@ +{self, ...}: { + config = { + boot.kernelParams = [ + "i8042.nomux" # Don't check presence of an active multiplexing controller + "i8042.nopnp" # Don't use ACPIPn

true + isx86Linux = pkgs: with pkgs.stdenv; hostPlatform.isLinux && hostPlatform.isx86; + + # assume the first monitor in the list of monitors is primary + # get its name from the list of monitors + # `primaryMonitor osConfig` -> "DP-1" + primaryMonitor = config: builtins.elemAt config.modules.device.monitors 0; +in { + inherit isx86Linux primaryMonitor; +} diff --git a/nyx/lib/helpers/default.nix b/nyx/lib/helpers/default.nix new file mode 100644 index 0000000..b0a911d --- /dev/null +++ b/nyx/lib/helpers/default.nix @@ -0,0 +1,15 @@ +{lib}: let + inherit (import ../core.nix {inherit lib;}) import'; + + systemd = import' ./systemd.nix; + fs = import' ./fs.nix; + types = import' ./types.nix; + themes = import' ./themes.nix; + modules = import' ./modules.nix; +in { + inherit (systemd) hardenService; + inherit (fs) mkBtrfs; + inherit (types) filterNixFiles importNixFiles boolToNum fetchKeys containsStrings indexOf intListToStringList; + inherit (themes) serializeTheme compileSCSS; + inherit (modules) mkModule; +} diff --git a/nyx/lib/helpers/fs.nix b/nyx/lib/helpers/fs.nix new file mode 100644 index 0000000..1cc9091 --- /dev/null +++ b/nyx/lib/helpers/fs.nix @@ -0,0 +1,5 @@ +_: let + mkBtrfs = list: list + ["compress=zstd" "noatime"]; +in { + inherit mkBtrfs; +} diff --git a/nyx/lib/helpers/modules.nix b/nyx/lib/helpers/modules.nix new file mode 100644 index 0000000..3264ab0 --- /dev/null +++ b/nyx/lib/helpers/modules.nix @@ -0,0 +1,34 @@ +{lib}: let + inherit (lib) mkEnableOption mkOption; + inherit (lib.types) str int; + + # mkModule takes a few arguments to generate a module for a service without + # repeating the same options over and over + # this is actually a horrendous abstractation + mkModule = { + name, + type ? "", # type being an empty string means it can be skipped, ommitted + host ? "127.0.0.1", # default to listening only on localhost + port ? 0, # don't set a port by default + extraOptions ? {}, # used to define additional modules + }: { + enable = mkEnableOption "${name} ${type} service"; + settings = + { + host = mkOption { + type = str; + default = host; + description = "The host ${name} will listen on"; + }; + + port = mkOption { + type = int; + default = port; + description = "The port ${name} will listen on"; + }; + } + // extraOptions; + }; +in { + inherit mkModule; +} diff --git a/nyx/lib/helpers/systemd.nix b/nyx/lib/helpers/systemd.nix new file mode 100644 index 0000000..488dd67 --- /dev/null +++ b/nyx/lib/helpers/systemd.nix @@ -0,0 +1,40 @@ +{lib, ...}: let + inherit (lib) mkOptionDefault mapAttrs; + + hardenService = attrs: + attrs + // (mapAttrs (_: mkOptionDefault) { + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallErrorNumber = "EPERM"; + SystemCallFilter = [ + "@system-service" + # Route-chain and OpenJ9 requires @resources calls + "~@clock @cpu-emulation @debug @module @mount @obsolete @privileged @raw-io @reboot @swap" + ]; + }); +in { + inherit hardenService; +} diff --git a/nyx/lib/helpers/themes.nix b/nyx/lib/helpers/themes.nix new file mode 100644 index 0000000..cbffd4a --- /dev/null +++ b/nyx/lib/helpers/themes.nix @@ -0,0 +1,21 @@ +{lib}: let + # function to generate theme slugs from theme names + # "A String With Whitespaces" -> "a-string-with-whitespaces" + serializeTheme = inputString: lib.strings.toLower (builtins.replaceStrings [" "] ["-"] inputString); + + # a function that takes a theme name and a source file and compiles it to CSS + # compileSCSS "theme-name" "path/to/theme.scss" -> "$out/theme-name.css" + # adapted from + compileSCSS = pkgs: { + name, + source, + args ? "-t expanded", + }: "${ + pkgs.runCommandLocal name {} '' + mkdir -p $out + ${lib.getExe pkgs.sassc} ${args} '${source}' > $out/${name}.css + '' + }/${name}.css"; +in { + inherit serializeTheme compileSCSS; +} diff --git a/nyx/lib/helpers/types.nix b/nyx/lib/helpers/types.nix new file mode 100644 index 0000000..32a9415 --- /dev/null +++ b/nyx/lib/helpers/types.nix @@ -0,0 +1,49 @@ +{lib, ...}: let + inherit (lib) lists mapAttrsToList filterAttrs hasSuffix; + + # filter files that have the .nix suffix + filterNixFiles = k: v: v == "regular" && hasSuffix ".nix" k; + + # import files that are selected by filterNixFiles + importNixFiles = path: + (lists.forEach (mapAttrsToList (name: _: path + ("/" + name)) + (filterAttrs filterNixFiles (builtins.readDir path)))) + import; + + # return an int (1/0) based on boolean value + # `boolToNum true` -> 1 + boolToNum = bool: + if bool + then 1 + else 0; + + # convert a list of integers to a list of string + # `intListToStringList [1 2 3]` -> ["1" "2" "3"] + intListToStringList = list: map (toString list); + + # a basic function to fetch a specified user's public keys from github .keys url + # `fetchKeys "username` -> "ssh-rsa AAAA...== username@hostname" + fetchKeys = username: (builtins.fetchurl "https://github.com/${username}.keys"); + + # a helper function that checks if a list contains a list of given strings + # `containsStrings { targetStrings = ["foo" "bar"]; list = ["foo" "bar" "baz"]; }` -> true + containsStrings = { + list, + targetStrings, + }: + builtins.all (s: builtins.any (x: x == s) list) targetStrings; + + # indexOf is a function that returns the index of an element in a list + # `indexOf ["foo" "bar" "baz"] "bar"` -> 1 + indexOf = list: elem: let + f = f: i: + if i == (builtins.length list) + then null + else if (builtins.elemAt list i) == elem + then i + else f f (i + 1); + in + f f 0; +in { + inherit filterNixFiles importNixFiles boolToNum fetchKeys containsStrings indexOf intListToStringList; +} diff --git a/nyx/lib/network/dag.nix b/nyx/lib/network/dag.nix new file mode 100644 index 0000000..8fe1ba3 --- /dev/null +++ b/nyx/lib/network/dag.nix @@ -0,0 +1,140 @@ +# Adjusted from https://gitlab.com/rycee/nur-expressions/blob/b34e2e548da574c7bd4da14d1779c95b62349a3a/lib/dag.nix (MIT) +# A generalization of Nixpkgs's `strings-with-deps.nix`. +# +# The main differences from the Nixpkgs version are +# +# - not specific to strings, i.e., any payload is OK, +# +# - the addition of the function `entryBefore` indicating a +# "wanted by" relationship. +{lib, ...}: let + inherit (lib) mkOption filterAttrs mapAttrsToList toposort mapAttrs any types; + + types' = + types + // { + dagOf = subType: + types.attrsOf (types.submodule { + options = { + data = mkOption { + type = subType; + description = "Entry value."; + }; + + before = mkOption { + type = types.listOf types.str; + default = []; + description = "Entries to guarantee before."; + }; + + after = mkOption { + type = types.listOf types.str; + default = []; + description = "Entries to guarantee after."; + }; + }; + }); + }; + + dag = { + # Takes an attribute set containing entries built by + # entryAnywhere, entryAfter, and entryBefore to a + # topologically sorted list of entries. + # + # Internally this function uses the `toposort` function in + # `` and its value is accordingly. + # + # Specifically, the result on success is + # + # { result = [{name = ?; data = ?;} …] } + # + # For example + # + # nix-repl> topoSort { + # a = entryAnywhere "1"; + # b = entryAfter ["a" "c"] "2"; + # c = entryBefore ["d"] "3"; + # d = entryBefore ["e"] "4"; + # e = entryAnywhere "5"; + # } == { + # result = [ + # { data = "1"; name = "a"; } + # { data = "3"; name = "c"; } + # { data = "2"; name = "b"; } + # { data = "4"; name = "d"; } + # { data = "5"; name = "e"; } + # ]; + # } + # true + # + # And the result on error is + # + # { + # cycle = [ {after = ?; name = ?; data = ?} … ]; + # loops = [ {after = ?; name = ?; data = ?} … ]; + # } + # + # For example + # + # nix-repl> topoSort { + # a = entryAnywhere "1"; + # b = entryAfter ["a" "c"] "2"; + # c = entryAfter ["d"] "3"; + # d = entryAfter ["b"] "4"; + # e = entryAnywhere "5"; + # } == { + # cycle = [ + # { after = ["a" "c"]; data = "2"; name = "b"; } + # { after = ["d"]; data = "3"; name = "c"; } + # { after = ["b"]; data = "4"; name = "d"; } + # ]; + # loops = [ + # { after = ["a" "c"]; data = "2"; name = "b"; } + # ]; + # } == {} + # true + topoSort = dag: let + dagBefore = dag: name: + mapAttrsToList (n: v: n) ( + filterAttrs (n: v: any (a: a == name) v.before) dag + ); + normalizedDag = + mapAttrs (n: v: { + name = n; + data = v.data; + after = v.after ++ dagBefore dag n; + }) + dag; + before = a: b: any (c: a.name == c) b.after; + sorted = toposort before (mapAttrsToList (n: v: v) normalizedDag); + in + if sorted ? result + then {result = map (v: {inherit (v) name data;}) sorted.result;} + else sorted; + + # Create a DAG entry with no particular dependency information. + entryAnywhere = data: { + inherit data; + before = []; + after = []; + }; + + # Ordering of after and before flipped from the original + entryBetween = after: before: data: { + inherit data before after; + }; + + entryAfter = after: data: { + inherit data after; + before = []; + }; + + entryBefore = before: data: { + inherit data before; + after = []; + }; + }; +in { + inherit (dag) entryBefore entryBetween entryAfter entryAnywhere topoSort; + inherit (types') dagOf; +} diff --git a/nyx/lib/network/firewall.nix b/nyx/lib/network/firewall.nix new file mode 100644 index 0000000..301ecdf --- /dev/null +++ b/nyx/lib/network/firewall.nix @@ -0,0 +1,177 @@ +{ + dag, + lib, + ... +}: let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.strings) optionalString concatMapStringsSep concatStringsSep; + inherit (lib.attrsets) filterAttrs mapAttrsToList; + inherit (lib.lists) concatLists; + inherit (lib) types; + inherit (dag) dagOf topoSort; + + mkTable = desc: body: + mkOption { + default = {}; + description = "Containers for chains, sets, and other stateful objects."; + type = types.submodule ({config, ...}: { + options = + { + enable = mkEnableOption desc; + objects = mkOption { + type = with types; listOf str; + description = "Objects associated with this table."; + default = []; + }; + } + // body; + + config = let + buildChainDag = chain: + concatMapStringsSep "\n" ({ + name, + data, + }: let + protocol = + if builtins.isNull data.protocol + then "" + else data.protocol; + field = + if builtins.isNull data.field + then "" + else data.field; + inherit (data) policy; + values = map toString data.value; + value = + if builtins.isNull data.value + then "" + else + ( + if builtins.length data.value == 1 + then builtins.head values + else "{ ${concatStringsSep ", " values} }" + ); + in '' + ${protocol} ${field} ${value} ${policy} comment ${name} + '') ((topoSort chain).result or (throw "Cycle in DAG")); + + buildChain = chainType: chain: + mapAttrsToList (chainName: chainDag: '' + chain ${chainName} { + type ${chainType} hook ${chainName} priority 0; + + ${buildChainDag chainDag} + } + '') (filterAttrs (_: g: builtins.length (builtins.attrNames g) > 0) chain); + in { + objects = let + chains = concatLists [ + ( + if config ? filter + then buildChain "filter" config.filter + else [] + ) + ( + if config ? nat + then buildChain "nat" config.nat + else [] + ) + ( + if config ? route + then buildChain "route" config.route + else [] + ) + ]; + in + chains; + }; + }); + }; + + mkChain = _: description: + mkOption { + inherit description; + default = {}; + type = dagOf (types.submodule { + options = { + protocol = mkOption { + default = null; + description = "Protocol to match."; + type = with types; + nullOr (either (enum [ + "ether" + "vlan" + "arp" + "ip" + "icmp" + "igmp" + "ip6" + "icmpv6" + "tcp" + "udp" + "udplite" + "sctp" + "dccp" + "ah" + "esp" + "comp" + ]) + str); + }; + + field = mkOption { + default = null; + description = "Field value to match."; + type = with types; + nullOr (enum [ + "dport" + "sport" + "daddr" + "saddr" + "type" + "state" + "iifname" + "pkttype" + ]); + }; + + value = mkOption { + default = null; + description = "Associated value."; + type = with types; let + valueType = oneOf [port str]; + in + nullOr (coercedTo valueType (value: [value]) (listOf valueType)); + }; + + policy = mkOption { + description = "What to do with matching packets."; + type = types.enum [ + "accept" + "reject" + "drop" + "log" + ]; + }; + }; + }); + }; + + mkRuleset = ruleset: + concatStringsSep "\n" (mapAttrsToList (name: table: + optionalString (builtins.length table.objects > 0) '' + table ${name} nixos { + ${concatStringsSep "\n" table.objects} + } + '') + ruleset); + + mkIngressChain = mkChain "Process all packets before they enter the system"; + mkPrerouteChain = mkChain "Process all packets entering the system"; + mkInputChain = mkChain "Process packets delivered to the local system"; + mkForwardChain = mkChain "Process packets forwarded to a different host"; + mkOutputChain = mkChain "Process packets sent by local processes"; + mkPostrouteChain = mkChain "Process all packets leaving the system"; +in { + inherit mkTable mkRuleset mkIngressChain mkPrerouteChain mkInputChain mkForwardChain mkOutputChain mkPostrouteChain; +} diff --git a/nyx/lib/network/namespacing.nix b/nyx/lib/network/namespacing.nix new file mode 100644 index 0000000..095c9b9 --- /dev/null +++ b/nyx/lib/network/namespacing.nix @@ -0,0 +1,13 @@ +_: let + makeServiceNsPhysical = name: { + systemd.services."${name}".serviceConfig.NetworkNamespacePath = "/var/run/netns/physical"; + }; + makeSocketNsPhysical = name: { + systemd.sockets."${name}".socketConfig.NetworkNamespacePath = "/var/run/netns/physical"; + }; + unRestrictNamespaces = name: { + systemd.sockets."${name}".socketConfig.RestrictNamespaces = "~net"; + }; +in { + inherit makeSocketNsPhysical makeServiceNsPhysical unRestrictNamespaces; +} diff --git a/nyx/lib/services.nix b/nyx/lib/services.nix new file mode 100644 index 0000000..ee5c57a --- /dev/null +++ b/nyx/lib/services.nix @@ -0,0 +1,17 @@ +{lib, ...}: let + # make a service that is a part of the graphical session target + mkGraphicalService = lib.recursiveUpdate { + Unit.PartOf = ["graphical-session.target"]; + Unit.After = ["graphical-session.target"]; + Install.WantedBy = ["graphical-session.target"]; + }; + + # make a service that is a part of the hyprland session target + mkHyprlandService = lib.recursiveUpdate { + Unit.PartOf = ["graphical-session.target"]; + Unit.After = ["graphical-session.target"]; + Install.WantedBy = ["hyprland-session.target"]; + }; +in { + inherit mkGraphicalService mkHyprlandService; +} diff --git a/nyx/lib/validators.nix b/nyx/lib/validators.nix new file mode 100644 index 0000000..ec54b78 --- /dev/null +++ b/nyx/lib/validators.nix @@ -0,0 +1,23 @@ +{lib, ...}: let + # a function that will append a list of groups if they exist in config.users.groups + ifTheyExist = config: groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups; + + # a function that returns a boolean based on whether or not the groups exist + ifGroupsExist = config: groups: lib.any (group: builtins.hasAttr group config.users.groups) groups; + + # convenience function check if the declared device type is of an accepted type + # takes config and a list of accepted device types + # `isAcceptedDevice osConfig ["foo" "bar"];` + isAcceptedDevice = conf: list: builtins.elem conf.modules.device.type list; + + # assert if the device is wayland-ready by checking sys.video and env.isWayland options + # `(lib.isWayland config)` where config is in scope + # `isWayland osConfig` -> true + isWayland = conf: conf.modules.system.video.enable && conf.modules.usrEnv.isWayland; + + # ifOneEnabled takes a parent option and 3 child options and checks if at least one of them is enabled + # `ifOneEnabled config.modules.services "service1" "service2" "service3"` + ifOneEnabled = cfg: a: b: c: (cfg.a || cfg.b || cfg.c); +in { + inherit ifTheyExist ifGroupsExist isAcceptedDevice isWayland ifOneEnabled; +} diff --git a/nyx/lib/xdg/default.nix b/nyx/lib/xdg/default.nix new file mode 100644 index 0000000..dad31fb --- /dev/null +++ b/nyx/lib/xdg/default.nix @@ -0,0 +1,5 @@ +_: let + xdgTemplate = ./. + /template.nix; +in { + inherit xdgTemplate; +} diff --git a/nyx/lib/xdg/template.nix b/nyx/lib/xdg/template.nix new file mode 100644 index 0000000..82907f8 --- /dev/null +++ b/nyx/lib/xdg/template.nix @@ -0,0 +1,98 @@ +system: let + # copy paste done right + XDG_CONFIG_HOME = "$HOME/.config"; + XDG_CACHE_HOME = "$HOME/.cache"; + XDG_DATA_HOME = "$HOME/.local/share"; + XDG_STATE_HOME = "$HOME/.local/state"; + XDG_BIN_HOME = "$HOME}/.local/bin"; + XDG_RUNTIME_DIR = "/run/user/$UID"; +in { + # global env + glEnv = { + inherit XDG_DATA_HOME XDG_CONFIG_HOME XDG_CACHE_HOME XDG_STATE_HOME XDG_RUNTIME_DIR XDG_BIN_HOME; + PATH = ["$XDG_BIN_HOME"]; + }; + + sysEnv = { + # general programs + CUDA_CACHE_PATH = "${XDG_CACHE_HOME}/nv"; + ERRFILE = "${XDG_CACHE_HOME}/X11/xsession-errors"; + GNUPGHOME = "${XDG_DATA_HOME}/gnupg"; + KDEHOME = "${XDG_CONFIG_HOME}/kde"; + LESSHISTFILE = "${XDG_DATA_HOME}/less/history"; + STEPPATH = "${XDG_DATA_HOME}/step"; + WAKATIME_HOME = "${XDG_DATA_HOME}/wakatime"; + XCOMPOSECACHE = "${XDG_CACHE_HOME}/X11/xcompose"; + INPUTRC = "${XDG_CONFIG_HOME}/readline/inputrc"; + PLATFORMIO_CORE_DIR = "${XDG_DATA_HOME}/platformio"; + WINEPREFIX = "${XDG_DATA_HOME}/wine"; + DOTNET_CLI_HOME = "${XDG_DATA_HOME}/dotnet"; + MPLAYER_HOME = "${XDG_CONFIG_HOME}/mplayer"; + SQLITE_HISTORY = "${XDG_CACHE_HOME}/sqlite_history"; + NBRC_PATH = "${XDG_CONFIG_HOME}/nbrc"; + NB_DIR = "${XDG_DATA_HOME}/nb"; + + # programming languages/package managers/tools + ANDROID_HOME = "${XDG_DATA_HOME}/android"; + DOCKER_CONFIG = "${XDG_CONFIG_HOME}/docker"; + GRADLE_USER_HOME = "${XDG_DATA_HOME}/gradle"; + IPYTHONDIR = "${XDG_CONFIG_HOME}/ipython"; + JUPYTER_CONFIG_DIR = "${XDG_CONFIG_HOME}/jupyter"; + GOPATH = "${XDG_DATA_HOME}/go"; + M2_HOME = "${XDG_DATA_HOME}/m2"; + _JAVA_OPTIONS = "-Djava.util.prefs.userRoot=${XDG_CONFIG_HOME}/java"; + CARGO_HOME = "${XDG_DATA_HOME}/cargo"; + NODE_REPL_HISTORY = "${XDG_DATA_HOME}/node_repl_history"; + NPM_CONFIG_CACE = "${XDG_CACHE_HOME}/npm"; + NPM_CONFIG_TMP = "${XDG_RUNTIME_DIR}/npm"; + NPM_CONFIG_USERCONFIG = "${XDG_CONFIG_HOME}/npm/config"; + PYTHONSTARTUP = + if system == "nixos" + then "/etc/pythonrc" + else "${XDG_CONFIG_HOME}/python/pythonrc"; + }; + + npmrc.text = '' + prefix=''${XDG_DATA_HOME}/npm + cache=''${XDG_CACHE_HOME}/npm + init-module=''${XDG_CONFIG_HOME}/npm/config/npm-init.js + ''; + + pythonrc.text = + /* + python + */ + '' + import os + import atexit + import readline + from pathlib import Path + + if readline.get_current_history_length() == 0: + + state_home = os.environ.get("XDG_STATE_HOME") + if state_home is None: + state_home = Path.home() / ".local" / "state" + else: + state_home = Path(state_home) + + history_path = state_home / "python_history" + if history_path.is_dir(): + raise OSError(f"'{history_path}' cannot be a directory") + + history = str(history_path) + + try: + readline.read_history_file(history) + except OSError: # Non existent + pass + + def write_history(): + try: + readline.write_history_file(history) + except OSError: + pass + + atexit.register(write_history) + ''; +} diff --git a/nyx/modules/core/common/default.nix b/nyx/modules/core/common/default.nix new file mode 100644 index 0000000..c8acebd --- /dev/null +++ b/nyx/modules/core/common/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./docs # generated system documentation of my nested module system + ./system # system configurations, from bootloader to desktop environment + ./secrets # secrets management + ]; +} diff --git a/nyx/modules/core/common/docs/default.nix b/nyx/modules/core/common/docs/default.nix new file mode 100644 index 0000000..ae64971 --- /dev/null +++ b/nyx/modules/core/common/docs/default.nix @@ -0,0 +1,16 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf; + + cfg = config.modules.documentation; +in { + config = mkIf cfg.enable { + environment.etc = { + "nyxos/options.md".source = cfg.markdownPackage; + "nyxos/options.html".source = cfg.htmlPackage; + }; + }; +} diff --git a/nyx/modules/core/common/secrets/default.nix b/nyx/modules/core/common/secrets/default.nix new file mode 100644 index 0000000..3162973 --- /dev/null +++ b/nyx/modules/core/common/secrets/default.nix @@ -0,0 +1,180 @@ +{ + self, + lib, + config, + ... +}: let + inherit (lib) mkIf optionalString; + + sys = config.modules.system; + cfg = sys.services; + + # mkSecret is an abstraction over agenix secrets + # it allows for secrets to be written conditionally and with + # relatively secure defaults without having to set each one of them + # manually. + mkSecret = enableCondition: { + file, + owner ? "root", + group ? "root", + mode ? "400", + }: + mkIf enableCondition { + file = "${self}/secrets/${file}"; + inherit group owner mode; + }; +in { + age.identityPaths = [ + "${optionalString sys.impermanence.root.enable "/persist"}/etc/ssh/ssh_host_ed25519_key" + "${optionalString sys.impermanence.home.enable "/persist"}/home/notashelf/.ssh/id_ed25519" + ]; + + age.secrets = { + # TODO: system option for declaring host as a potential builder + nix-builderKey = mkSecret true { + file = "common-nix-builder.age"; + }; + + tailscale-client = mkSecret true { + file = "client-tailscale.age"; + owner = "notashelf"; + group = "users"; + mode = "400"; + }; + + # secrets needed for peers + spotify-secret = mkSecret config.modules.system.programs.spotify.enable { + file = "client-spotify.age"; + owner = "notashelf"; + group = "users"; + mode = "400"; + }; + + wg-client = mkSecret true { + file = "client-wg.age"; + owner = "notashelf"; + group = "users"; + mode = "700"; + }; + + client-email = mkSecret true { + file = "client-email.age"; + owner = "notashelf"; + group = "users"; + mode = "400"; + }; + + # database secrets + mongodb-secret = mkSecret cfg.database.mongodb.enable { + file = "db-mongodb.age"; + }; + + garage-env = mkSecret cfg.database.garage.enable { + file = "db-garage.age"; + mode = "400"; + owner = "garage"; + group = "garage"; + }; + + # service secrets + wg-server = mkSecret cfg.networking.wireguard.enable { + file = "service-wg.age"; + }; + + mkm-web = mkSecret cfg.mkm.enable { + file = "service-mkm-web.age"; + mode = "400"; + }; + + matrix-secret = mkSecret cfg.social.matrix.enable { + file = "service-matrix.age"; + owner = "matrix-synapse"; + mode = "400"; + }; + + vaultwarden-env = mkSecret cfg.vaultwarden.enable { + file = "service-vaultwarden.age"; + owner = "vaultwarden"; + mode = "400"; + }; + + searx-secretkey = mkSecret cfg.searxng.enable { + file = "service-searx.age"; + mode = "400"; + owner = "searx"; + group = "searx"; + }; + + nextcloud-secret = mkSecret cfg.nextcloud.enable { + file = "service-nextcloud.age"; + mode = "400"; + owner = "nextcloud"; + group = "nextcloud"; + }; + + attic-env = mkSecret cfg.bincache.atticd.enable { + file = "service-attic.age"; + mode = "400"; + owner = "atticd"; + group = "atticd"; + }; + + harmonia-privateKey = mkSecret cfg.bincache.harmonia.enable { + file = "service-harmonia.age"; + mode = "770"; + owner = "harmonia"; + group = "harmonia"; + }; + + forgejo-runner-token = mkSecret cfg.forgejo.enable { + file = "service-forgejo-runner-token.age"; + mode = "400"; + owner = "gitea-runner"; + group = "gitea-runner"; + }; + + forgejo-runner-config = mkSecret cfg.forgejo.enable { + file = "service-forgejo-runner-config.age"; + mode = "400"; + owner = "gitea-runner"; + group = "gitea-runner"; + }; + + # mailserver secrets + mailserver-secret = mkSecret cfg.mailserver.enable { + file = "mailserver-postmaster.age"; + mode = "400"; + }; + + mailserver-forgejo-secret = mkSecret cfg.forgejo.enable { + file = "mailserver-forgejo.age"; + owner = "forgejo"; + group = "forgejo"; + mode = "400"; + }; + + mailserver-vaultwarden-secret = mkSecret cfg.vaultwarden.enable { + file = "mailserver-vaultwarden.age"; + owner = "vaultwarden"; + mode = "400"; + }; + + mailserver-cloud-secret = mkSecret cfg.nextcloud.enable { + file = "mailserver-cloud.age"; + owner = "nextcloud"; + mode = "400"; + }; + + mailserver-matrix-secret = mkSecret cfg.social.matrix.enable { + file = "mailserver-matrix.age"; + owner = "matrix-synapse"; + mode = "400"; + }; + + mailserver-noreply-secret = mkSecret cfg.social.mastodon.enable { + file = "mailserver-noreply.age"; + owner = "mastodon"; + mode = "400"; + }; + }; +} diff --git a/nyx/modules/core/common/system/containers/alpha/default.nix b/nyx/modules/core/common/system/containers/alpha/default.nix new file mode 100644 index 0000000..ac05e2f --- /dev/null +++ b/nyx/modules/core/common/system/containers/alpha/default.nix @@ -0,0 +1,86 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + hostConfig = config; +in { + config = mkIf (builtins.elem "alpha" config.modules.system.containers.enabledContainers) { + systemd = { + services."container@alpha".after = ["container@firewall.service"]; + tmpfiles.rules = [ + "D /srv/containers/home 755 root root" + ]; + }; + + containers."alpha" = { + autoStart = false; + enableTun = true; + ephemeral = true; + privateNetwork = true; + localAddress = "10.1.0.1"; + hostAddress = "10.1.0.2"; + config = _: { + _module.args = {inherit lib;}; + nixpkgs.pkgs = pkgs; + + system.stateVersion = "23.05"; + + users = { + groups.alpha = {}; + users.alpha = { + isNormalUser = true; + extraGroups = ["alpha"]; + home = "/home/alpha"; + createHome = true; + initialPassword = "alpha"; + }; + }; + + environment.systemPackages = with pkgs; [ + gcc + openjdk17_headless + gitMinimal + ]; + + networking.interfaces.ve-alpha = { + useDHCP = true; + ipv4 = { + addresses = [ + { + address = "10.1.0.1"; + prefixLength = 32; + } + ]; + routes = [ + { + address = "10.1.0.2"; + prefixLength = 32; + options = {src = "10.1.0.1";}; + } + ]; + }; + }; + }; + + bindMounts = { + "/home" = { + hostPath = "/srv/containers/home"; + isReadOnly = false; + }; + + "/run/systemd/ask-password" = { + hostPath = "/run/systemd/ask-password"; + isReadOnly = false; + }; + "/run/systemd/ask-password-block" = { + hostPath = "/run/systemd/ask-password-block"; + isReadOnly = false; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/containers/beta/default.nix b/nyx/modules/core/common/system/containers/beta/default.nix new file mode 100644 index 0000000..3deeaa8 --- /dev/null +++ b/nyx/modules/core/common/system/containers/beta/default.nix @@ -0,0 +1,99 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; +in { + config = mkIf (builtins.elem "beta" config.modules.system.containers.enabledContainers) { + containers."beta" = { + autoStart = false; + enableTun = true; + ephemeral = true; + privateNetwork = true; + localAddress = "10.2.0.1"; + hostAddress = "10.2.0.2"; + config = _: let + backup_path = "/var/backup/postgresql"; + in { + system.stateVersion = "23.05"; + + services.openssh.enable = true; + + users = { + groups.beta = {}; + users = { + root.hashedPassword = "!"; # disable root login + beta = { + isNormalUser = true; + createHome = true; + group = "beta"; + }; + }; + }; + + time.timeZone = "Europe/Berlin"; + + networking.interfaces = { + eth0 = { + useDHCP = false; + ipv4.addresses = [ + { + address = "192.168.6.1"; + prefixLength = 23; + } + ]; + ipv6.addresses = []; + }; + }; + + networking.firewall = { + enable = true; + allowPing = true; + allowedTCPPorts = [5432]; + }; + + services.postgresql = { + enable = true; + enableTCPIP = true; + package = pkgs.postgresql; + dataDir = "/var/db/postgresql"; + authentication = '' + host selfoss selfoss 192.168.6.2/32 trust + ''; + initialScript = builtins.toFile "pg_initial_script" '' + CREATE ROLE selfoss LOGIN CREATEDB; + CREATE DATABASE selfoss OWNER selfoss; + ''; + }; + + systemd.services.postgresql.preStart = '' + if [ ! -d ${backup_path} ]; then + mkdir -p ${backup_path} + chown postgres ${backup_path} + fi + ''; + + systemd.services.postgresql-dump = { + path = with pkgs; [postgresql gzip]; + serviceConfig = { + User = "root"; + }; + script = let + db_list_command = "psql -l -t -A |cut -d'|' -f 1 |grep -v -e template0 -e template1 -e 'root=CT'"; + in '' + ${db_list_command} + for db in `${db_list_command}`; do + echo "Dumping $db" + pg_dump --format directory --file ${backup_path}/$db $db + done + echo "Dumping all in one gzip" + pg_dumpall |gzip > ${backup_path}/complete_dump.sql.gz + ''; + startAt = "daily"; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/containers/default.nix b/nyx/modules/core/common/system/containers/default.nix new file mode 100644 index 0000000..52cf297 --- /dev/null +++ b/nyx/modules/core/common/system/containers/default.nix @@ -0,0 +1,11 @@ +_: { + # this imports all container directories unconditionally, regardless of whether or not + # they are included in containers.enabledContainers option definition + # however, as a safeguard, we are required to check if a container is actually meant to be enabled + # so each container does it's own "builtins.elem ..." bullshit before evaluating the container + # configuration - hacky? yes. working? also yes. + imports = [ + ./alpha # sandbox + ./beta # postgresql + ]; +} diff --git a/nyx/modules/core/common/system/default.nix b/nyx/modules/core/common/system/default.nix new file mode 100644 index 0000000..f8cdf67 --- /dev/null +++ b/nyx/modules/core/common/system/default.nix @@ -0,0 +1,14 @@ +{ + imports = [ + ./containers # hotpluggable systemd-nspawn containers + ./emulation # emulation via binfmt for cross-building + ./encryption # LUKS encryption + ./gaming # available games and gaming utilities such as steam and mangohud + ./hardware # hardware capabilities - i.e bluetooth, sound, tpm etc. + ./impermanence # impermanence configuration + ./nix # configuration for the nix package manager and build tool + ./os # configurations for how the system should operate + ./security # anything from kernel hardening to audit daemeons + ./virtualization # hypervisor and virtualisation related options - docker, QEMU, waydroid etc. + ]; +} diff --git a/nyx/modules/core/common/system/emulation/default.nix b/nyx/modules/core/common/system/emulation/default.nix new file mode 100644 index 0000000..fb7d7fd --- /dev/null +++ b/nyx/modules/core/common/system/emulation/default.nix @@ -0,0 +1,25 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; +in { + config = mkIf sys.emulation.enable { + nix.settings.extra-sandbox-paths = ["/run/binfmt" "${pkgs.qemu}"]; + + boot.binfmt = { + emulatedSystems = sys.emulation.systems; + registrations = { + # aarch64 interpreter + aarch64-linux.interpreter = "${pkgs.qemu}/bin/qemu-aarch64"; + + # i686 interpreter + i686-linux.interpreter = "${pkgs.qemu}/bin/qemu-i686"; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/encryption/default.nix b/nyx/modules/core/common/system/encryption/default.nix new file mode 100644 index 0000000..83b6c0e --- /dev/null +++ b/nyx/modules/core/common/system/encryption/default.nix @@ -0,0 +1,47 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + cfg = config.modules.system.encryption; +in { + config = mkIf cfg.enable { + boot = { + # mildly improves performance for the disk encryption + initrd.availableKernelModules = [ + "aesni_intel" + "cryptd" + "usb_storage" + ]; + + kernelParams = [ + # Disable password timeout + "luks.options=timeout=0" + "rd.luks.options=timeout=0" + "rootflags=x-systemd.device-timeout=0" + ]; + }; + + services.lvm.enable = true; + + # TODO: account for multiple encrypted devices + boot.initrd.luks.devices."${cfg.device}" = { + # improve performance on ssds + bypassWorkqueues = true; + + # handle LUKS decryption before LVM + preLVM = true; + + # the device with the maching id will be searched for the key file + keyFile = mkIf (cfg.keyFile != null) "${cfg.keyFile}"; + + # the size of the key file in bytes + keyFileSize = cfg.keySize; + + # if keyfile is not there, fall back to cryptsetup password + fallbackToPassword = cfg.fallbackToPassword; # IMPLIED BY config.boot.initrd.systemd.enable + }; + }; +} diff --git a/nyx/modules/core/common/system/gaming/default.nix b/nyx/modules/core/common/system/gaming/default.nix new file mode 100644 index 0000000..d91ecc6 --- /dev/null +++ b/nyx/modules/core/common/system/gaming/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./gamescope.nix + ./gamemode.nix + ./steam.nix + ]; +} diff --git a/nyx/modules/core/common/system/gaming/gamemode.nix b/nyx/modules/core/common/system/gaming/gamemode.nix new file mode 100644 index 0000000..83a3a98 --- /dev/null +++ b/nyx/modules/core/common/system/gaming/gamemode.nix @@ -0,0 +1,75 @@ +{ + inputs, + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf makeBinPath optionalString; + inherit (config) modules; + + env = modules.usrEnv; + sys = modules.system; + prg = sys.programs; + + programs = makeBinPath (with pkgs; [ + inputs.hyprland.packages.${stdenv.system}.default + coreutils + power-profiles-daemon + systemd + libnotify + ]); + + startscript = pkgs.writeShellScript "gamemode-start" '' + ${optionalString (env.desktop == "Hyprland") '' + export PATH=$PATH:${programs} + export HYPRLAND_INSTANCE_SIGNATURE=$(ls -w1 /tmp/hypr | tail -1) + hyprctl --batch 'keyword decoration:blur 0 ; keyword animations:enabled 0 ; keyword misc:vfr 0' + ''} + + powerprofilesctl set performance + notify-send -a 'Gamemode' 'Optimizations activated' -u 'low' + ''; + + endscript = pkgs.writeShellScript "gamemode-end" '' + ${optionalString (env.desktop == "Hyprland") '' + export PATH=$PATH:${programs} + export HYPRLAND_INSTANCE_SIGNATURE=$(ls -w1 /tmp/hypr | tail -1) + hyprctl --batch 'keyword decoration:blur 1 ; keyword animations:enabled 1 ; keyword misc:vfr 1' + ''} + + powerprofilesctl set balanced + notify-send -a 'Gamemode' 'Optimizations deactivated' -u 'low' + ''; +in { + config = mkIf prg.gaming.gamemode.enable { + programs.gamemode = { + enable = true; + enableRenice = true; + settings = { + general = { + softrealtime = "auto"; + renice = 15; + }; + + custom = { + start = startscript.outPath; + end = endscript.outPath; + }; + }; + }; + + security.wrappers.gamemode = { + owner = "root"; + group = "root"; + source = "${pkgs.gamemode}/bin/gamemoderun"; + capabilities = "cap_sys_ptrace,cap_sys_nice+pie"; + }; + + boot.kernel.sysctl = { + # default on some gaming (SteamOS) and desktop (Fedora) distributions + # might help with gaming performance + "vm.max_map_count" = 2147483642; + }; + }; +} diff --git a/nyx/modules/core/common/system/gaming/gamescope.nix b/nyx/modules/core/common/system/gaming/gamescope.nix new file mode 100644 index 0000000..f4f028c --- /dev/null +++ b/nyx/modules/core/common/system/gaming/gamescope.nix @@ -0,0 +1,28 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (config) modules; + + sys = modules.system; + prg = sys.programs; +in { + config = mkIf prg.gaming.gamescope.enable { + programs.gamescope = { + enable = true; + package = pkgs.gamescope; # the default, here in case I want to override it + }; + + # workaround attempt for letting gamescope bypass YAMA LSM + # doesn't work, but doesn't hurt to keep this here + security.wrappers.gamescope = { + owner = "root"; + group = "root"; + source = "${config.programs.gamescope.package}/bin/gamescope"; + capabilities = "cap_sys_ptrace,cap_sys_nice+pie"; + }; + }; +} diff --git a/nyx/modules/core/common/system/gaming/steam.nix b/nyx/modules/core/common/system/gaming/steam.nix new file mode 100644 index 0000000..057f37d --- /dev/null +++ b/nyx/modules/core/common/system/gaming/steam.nix @@ -0,0 +1,83 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + + prg = config.modules.system.programs; +in { + config = mkIf prg.gaming.steam.enable { + nixpkgs = { + config = { + allowUnfreePredicate = pkg: + builtins.elem (lib.getName pkg) [ + "steam" + "steam-original" + "steam-runtime" + ]; + }; + + overlays = [ + (_: prev: { + steam = prev.steam.override ({extraPkgs ? _: [], ...}: { + extraPkgs = pkgs': + (extraPkgs pkgs') + # Add missing dependencies + ++ (with pkgs'; [ + # Generic dependencies + libgdiplus + keyutils + libkrb5 + libpng + libpulseaudio + libvorbis + stdenv.cc.cc.lib + xorg.libXcursor + xorg.libXi + xorg.libXinerama + xorg.libXScrnSaver + at-spi2-atk + fmodex + gtk3 + gtk3-x11 + harfbuzz + icu + glxinfo + inetutils + libthai + mono5 + pango + stdenv.cc.cc.lib + strace + zlib + + # for Titanfall 2 Northstar launcher + libunwind + ]); + }); + }) + ]; + }; + + programs.steam = { + # Enable steam + enable = true; + + # Whether to open ports in the firewall for Steam Remote Play + remotePlay.openFirewall = false; + + # Whether to open ports in the firewall for Source Dedicated Server + dedicatedServer.openFirewall = false; + + # Compatibility tools to install + # For the accepted format (and the reason behind) + # the "compattool" attribute, see: + # + extraCompatPackages = [ + pkgs.proton-ge-bin.steamcompattool + ]; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/bluetooth.nix b/nyx/modules/core/common/system/hardware/bluetooth.nix new file mode 100644 index 0000000..8703092 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/bluetooth.nix @@ -0,0 +1,32 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system.bluetooth; +in { + config = mkIf sys.enable { + modules.system.boot.extraKernelParams = ["btusb"]; + + hardware.bluetooth = { + enable = true; + package = pkgs.bluez5-experimental; + #hsphfpd.enable = true; + powerOnBoot = true; + disabledPlugins = ["sap"]; + settings = { + General = { + JustWorksRepairing = "always"; + MultiProfile = "multiple"; + Experimental = true; + }; + }; + }; + + # https://nixos.wiki/wiki/Bluetooth + services.blueman.enable = true; + }; +} diff --git a/nyx/modules/core/common/system/hardware/cpu/amd/default.nix b/nyx/modules/core/common/system/hardware/cpu/amd/default.nix new file mode 100644 index 0000000..128e424 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/cpu/amd/default.nix @@ -0,0 +1,60 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf mkMerge versionOlder versionAtLeast; + dev = config.modules.device; + + kver = config.boot.kernelPackages.kernel.version; + inherit (dev.cpu.amd) pstate zenpower; +in { + config = mkIf (builtins.elem dev.cpu.type ["amd" "vm-amd"]) { + environment.systemPackages = [pkgs.amdctl]; + + hardware.cpu.amd.updateMicrocode = true; + boot = mkMerge [ + { + kernelModules = [ + "kvm-amd" # amd virtualization + "amd-pstate" # load pstate module in case the device has a newer gpu + "zenpower" # zenpower is for reading cpu info, i.e voltage + "msr" # x86 CPU MSR access device + ]; + extraModulePackages = [config.boot.kernelPackages.zenpower]; + } + + (mkIf (pstate.enable && (versionAtLeast kver "5.17") && (versionOlder kver "6.1")) { + kernelParams = ["initcall_blacklist=acpi_cpufreq_init"]; + kernelModules = ["amd-pstate"]; + }) + + (mkIf (pstate.enable && (versionAtLeast kver "6.1") && (versionOlder kver "6.3")) { + kernelParams = ["amd_pstate=passive"]; + }) + + # for older kernels + # see + (mkIf (pstate.enable && (versionAtLeast kver "6.3")) { + kernelParams = ["amd_pstate=active"]; + }) + ]; + + # Ryzen cpu control + systemd.services.zenstates = mkIf zenpower.enable { + enable = true; + description = "Undervolt via Zenstates"; + after = ["syslog.target" "systemd-modules-load.service"]; + + unitConfig = {ConditionPathExists = "${pkgs.zenstates}/bin/zenstates";}; + + serviceConfig = { + User = "root"; + ExecStart = "${pkgs.zenstates}/bin/zenstates ${zenpower.args}"; + }; + + wantedBy = ["multi-user.target"]; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/cpu/default.nix b/nyx/modules/core/common/system/hardware/cpu/default.nix new file mode 100644 index 0000000..b31716f --- /dev/null +++ b/nyx/modules/core/common/system/hardware/cpu/default.nix @@ -0,0 +1,6 @@ +_: { + imports = [ + ./amd + ./intel + ]; +} diff --git a/nyx/modules/core/common/system/hardware/cpu/intel/default.nix b/nyx/modules/core/common/system/hardware/cpu/intel/default.nix new file mode 100644 index 0000000..e20f59d --- /dev/null +++ b/nyx/modules/core/common/system/hardware/cpu/intel/default.nix @@ -0,0 +1,20 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + dev = config.modules.device; +in { + config = mkIf (builtins.elem dev.cpu.type ["intel" "vm-intel"]) { + hardware.cpu.intel.updateMicrocode = true; + boot = { + kernelModules = ["kvm-intel"]; + kernelParams = ["i915.fastboot=1" "enable_gvt=1"]; + }; + + environment.systemPackages = with pkgs; [intel-gpu-tools]; + }; +} diff --git a/nyx/modules/core/common/system/hardware/default.nix b/nyx/modules/core/common/system/hardware/default.nix new file mode 100644 index 0000000..15ff593 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/default.nix @@ -0,0 +1,12 @@ +{ + imports = [ + ./cpu # cpu specific options + ./gpu # gpu specific options + ./multimedia # enable multimedia: e.g. sound and video + + ./bluetooth.nix # bluetooth and device management + ./generic.nix # host-agnostic options and settings + ./tpm.nix # trusted platform module + ./yubikey.nix # yubikey device support and management tools + ]; +} diff --git a/nyx/modules/core/common/system/hardware/generic.nix b/nyx/modules/core/common/system/hardware/generic.nix new file mode 100644 index 0000000..fb60fa1 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/generic.nix @@ -0,0 +1,8 @@ +{lib, ...}: { + # This enables non-free firmware on devices not recognized by `nixos-generate-config`. + # Disabling this option will make the system unbootable if such devices are critical + # in your boot chain - therefore this should remain true until you are running a device + # with mostly libre firmware. Which there is not many of. + # on 2021-06-14: disabled this by accident and nuked my GPU drivers + hardware.enableRedistributableFirmware = lib.mkDefault true; +} diff --git a/nyx/modules/core/common/system/hardware/gpu/amd/default.nix b/nyx/modules/core/common/system/hardware/gpu/amd/default.nix new file mode 100644 index 0000000..0502039 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/gpu/amd/default.nix @@ -0,0 +1,49 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + dev = config.modules.device; +in { + config = mkIf (builtins.elem dev.gpu.type ["amd" "hybrid-amd"]) { + # enable amdgpu xorg drivers in case Hyprland breaks again + services.xserver.videoDrivers = lib.mkDefault ["modesetting" "amdgpu"]; + + # enable amdgpu kernel module + boot = { + initrd.kernelModules = ["amdgpu"]; # load amdgpu kernel module as early as initrd + kernelModules = ["amdgpu"]; # if loading somehow fails during initrd but the boot continues, try again later + }; + + environment.systemPackages = [pkgs.nvtopPackages.amd]; + + # enables AMDVLK & OpenCL support + hardware.opengl = { + extraPackages = with pkgs; + [ + amdvlk + + # mesa + mesa + + # vulkan + vulkan-tools + vulkan-loader + vulkan-validation-layers + vulkan-extension-layer + ] + ++ ( + # this is a backwards-compatible way of loading appropriate opencl packages + # in case the host runs an older revision of nixpkgs + if pkgs ? rocmPackages.clr + then with pkgs.rocmPackages; [clr clr.icd] + else with pkgs; [rocm-opencl-icd rocm-opencl-runtime] + ); + + extraPackages32 = [pkgs.driversi686Linux.amdvlk]; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/gpu/default.nix b/nyx/modules/core/common/system/hardware/gpu/default.nix new file mode 100644 index 0000000..38140c5 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/gpu/default.nix @@ -0,0 +1,7 @@ +_: { + imports = [ + ./intel + ./nvidia + ./amd + ]; +} diff --git a/nyx/modules/core/common/system/hardware/gpu/intel/default.nix b/nyx/modules/core/common/system/hardware/gpu/intel/default.nix new file mode 100644 index 0000000..a4a36bb --- /dev/null +++ b/nyx/modules/core/common/system/hardware/gpu/intel/default.nix @@ -0,0 +1,43 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + dev = config.modules.device; + + # let me play youtube videos without h.264, please and thank you + vaapiIntel = pkgs.vaapiIntel.override {enableHybridCodec = true;}; +in { + config = mkIf (builtins.elem dev.gpu.type ["intel" "hybrid-intel"]) { + # enable the i915 kernel module + boot.initrd.kernelModules = ["i915"]; + # better performance than the actual Intel driver + services.xserver.videoDrivers = ["modesetting"]; + + # OpenCL support and VAAPI + hardware.opengl = { + extraPackages = with pkgs; [ + intel-compute-runtime + intel-media-driver + vaapiIntel + vaapiVdpau + libvdpau-va-gl + ]; + + extraPackages32 = with pkgs.pkgsi686Linux; [ + # intel-compute-runtime # FIXME does not build due to unsupported system + intel-media-driver + vaapiIntel + vaapiVdpau + libvdpau-va-gl + ]; + }; + + environment.variables = mkIf (config.hardware.opengl.enable && dev.gpu != "hybrid-nv") { + VDPAU_DRIVER = "va_gl"; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/gpu/nvidia/default.nix b/nyx/modules/core/common/system/hardware/gpu/nvidia/default.nix new file mode 100644 index 0000000..2a109f8 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/gpu/nvidia/default.nix @@ -0,0 +1,117 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf mkDefault mkMerge versionOlder; + + # use the latest possible nvidia package + nvStable = config.boot.kernelPackages.nvidiaPackages.stable.version; + nvBeta = config.boot.kernelPackages.nvidiaPackages.beta.version; + + nvidiaPackage = + if (versionOlder nvBeta nvStable) + then config.boot.kernelPackages.nvidiaPackages.stable + else config.boot.kernelPackages.nvidiaPackages.beta; + + dev = config.modules.device; + env = config.modules.usrEnv; +in { + config = mkIf (builtins.elem dev.gpu.type ["nvidia" "hybrid-nv"]) { + # nvidia drivers are unfree software + nixpkgs.config.allowUnfree = true; + + services.xserver = mkMerge [ + { + videoDrivers = ["nvidia"]; + } + + # xorg settings + (mkIf (!env.isWayland) { + # disable DPMS + monitorSection = '' + Option "DPMS" "false" + ''; + + # disable screen blanking in general + serverFlagsSection = '' + Option "StandbyTime" "0" + Option "SuspendTime" "0" + Option "OffTime" "0" + Option "BlankTime" "0" + ''; + }) + ]; + + # blacklist nouveau module so that it does not conflict with nvidia drm stuff + # also the nouveau performance is godawful, I'd rather run linux on a piece of paper than use nouveau + # no offense to nouveau devs, I'm sure they're doing their best and they have my respect for that + # but their best does not constitute a usable driver for me + boot.blacklistedKernelModules = ["nouveau"]; + + environment = { + sessionVariables = mkMerge [ + {LIBVA_DRIVER_NAME = "nvidia";} + + (mkIf env.isWayland { + WLR_NO_HARDWARE_CURSORS = "1"; + #__GLX_VENDOR_LIBRARY_NAME = "nvidia"; + #GBM_BACKEND = "nvidia-drm"; # breaks firefox apparently + }) + + (mkIf (env.isWayland && (dev.gpu == "hybrid-nv")) { + #__NV_PRIME_RENDER_OFFLOAD = "1"; + #WLR_DRM_DEVICES = mkDefault "/dev/dri/card1:/dev/dri/card0"; + }) + ]; + systemPackages = with pkgs; [ + nvtopPackages.nvidia + + # mesa + mesa + + # vulkan + vulkan-tools + vulkan-loader + vulkan-validation-layers + vulkan-extension-layer + + # libva + libva + libva-utils + ]; + }; + + hardware = { + nvidia = { + package = mkDefault nvidiaPackage; + modesetting.enable = mkDefault true; + + prime.offload = let + isHybrid = dev.gpu == "hybrid-nv"; + in { + enable = isHybrid; + enableOffloadCmd = isHybrid; + }; + + powerManagement = { + enable = mkDefault true; + finegrained = mkDefault false; + }; + + # use open source drivers by default, hosts may override this option if their gpu is + # not supported by the open source drivers + open = mkDefault true; + nvidiaSettings = false; # add nvidia-settings to pkgs, useless on nixos + nvidiaPersistenced = true; + forceFullCompositionPipeline = true; + }; + + opengl = { + extraPackages = with pkgs; [nvidia-vaapi-driver]; + extraPackages32 = with pkgs.pkgsi686Linux; [nvidia-vaapi-driver]; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/multimedia/default.nix b/nyx/modules/core/common/system/hardware/multimedia/default.nix new file mode 100644 index 0000000..e031047 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/multimedia/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./video + ./sound + ]; +} diff --git a/nyx/modules/core/common/system/hardware/multimedia/sound/default.nix b/nyx/modules/core/common/system/hardware/multimedia/sound/default.nix new file mode 100644 index 0000000..b9a27c1 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/multimedia/sound/default.nix @@ -0,0 +1,17 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf mkDefault; + cfg = config.modules.system.sound; + dev = config.modules.device; +in { + imports = [./pipewire.nix]; + config = mkIf (cfg.enable && dev.hasSound) { + sound = { + enable = mkDefault false; # this just enables ALSA, which we don't really care abouyt + mediaKeys.enable = true; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/multimedia/sound/pipewire.nix b/nyx/modules/core/common/system/hardware/multimedia/sound/pipewire.nix new file mode 100644 index 0000000..9ac3a25 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/multimedia/sound/pipewire.nix @@ -0,0 +1,130 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) isx86Linux; + inherit (lib.modules) mkIf; + inherit (lib.lists) optionals; + inherit (lib.generators) toLua; + + cfg = config.modules.system.sound; + dev = config.modules.device; +in { + config = mkIf (cfg.enable && dev.hasSound) { + # if the device advertises sound enabled, and pipewire is disabled + # for whatever reason, we may fall back to PulseAudio to ensure + # that we still have audio. I do not like PA, but bad audio + # is better than no audio. Though we should always use + # PipeWire where available + hardware.pulseaudio.enable = !config.services.pipewire.enable; + + # able to change scheduling policies, e.g. to SCHED_RR + # sounds server use RealtimeKit (rtkti) to acquire + # realtime priority + security.rtkit.enable = config.services.pipewire.enable; + + # enable pipewire and configure it for low latency + # the below configuration may not fit every use case + # and you are recommended to experiment with the values + # in order to find the perfect configuration + services = { + pipewire = let + quantum = 64; + rate = 48000; + qr = "${toString quantum}/${toString rate}"; + in { + enable = true; + + # emulation layers + audio.enable = true; + pulse.enable = true; # PA server emulation + jack.enable = true; # JACK audio emulation + alsa = { + enable = true; + support32Bit = isx86Linux pkgs; # if we're on x86 linux, we can support 32 bit + }; + + extraConfig.pipewire."99-lowlatency" = { + context = { + properties.default.clock.min-quantum = quantum; + modules = [ + { + name = "libpipewire-module-rtkit"; + flags = ["ifexists" "nofail"]; + args = { + nice.level = -15; + rt = { + prio = 88; + time.soft = 200000; + time.hard = 200000; + }; + }; + } + { + name = "libpipewire-module-protocol-pulse"; + args = { + server.address = ["unix:native"]; + pulse.min = { + req = qr; + quantum = qr; + frag = qr; + }; + }; + } + ]; + + stream.properties = { + node.latency = qr; + resample.quality = 1; + }; + }; + }; + + wireplumber = { + enable = true; + configPackages = let + # generate "matches" section of the rules + matches = toLua { + multiline = false; # looks better while inline + indent = false; + } [[["node.name" "matches" "alsa_output.*"]]]; # nested lists are to produce `{{{ }}}` in the output + + # generate "apply_properties" section of the rules + apply_properties = toLua {} { + "audio.format" = "S32LE"; + "audio.rate" = rate * 2; + "api.alsa.period-size" = 2; + }; + in + [ + (pkgs.writeTextDir "share/lowlatency.lua.d/99-alsa-lowlatency.lua" '' + alsa_monitor.rules = { + { + matches = ${matches}; + apply_properties = ${apply_properties}; + } + } + '') + ] + ++ optionals dev.hasBluetooth [ + (pkgs.writeTextDir "share/bluetooth.lua.d/51-bluez-config.lua" '' + bluez_monitor.properties = { + ["bluez5.enable-sbc-xq"] = true, + ["bluez5.enable-msbc"] = true, + ["bluez5.enable-hw-volume"] = true, + ["bluez5.headset-roles"] = "[ hsp_hs hsp_ag hfp_hf hfp_ag ]" + } + '') + ]; + }; + }; + }; + + systemd.user.services = { + pipewire.wantedBy = ["default.target"]; + pipewire-pulse.wantedBy = ["default.target"]; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/multimedia/video/default.nix b/nyx/modules/core/common/system/hardware/multimedia/video/default.nix new file mode 100644 index 0000000..fbf021b --- /dev/null +++ b/nyx/modules/core/common/system/hardware/multimedia/video/default.nix @@ -0,0 +1,26 @@ +{ + pkgs, + lib, + config, + ... +}: let + inherit (lib) mkIf isx86Linux; + + sys = config.modules.system; +in { + config = mkIf sys.video.enable { + hardware = { + opengl = { + enable = true; + driSupport = true; + driSupport32Bit = isx86Linux pkgs; + }; + }; + + # benchmarking tools + environment.systemPackages = with pkgs; [ + glxinfo + glmark2 + ]; + }; +} diff --git a/nyx/modules/core/common/system/hardware/tpm.nix b/nyx/modules/core/common/system/hardware/tpm.nix new file mode 100644 index 0000000..1b24592 --- /dev/null +++ b/nyx/modules/core/common/system/hardware/tpm.nix @@ -0,0 +1,28 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf mkDefault; + + dev = config.modules.device; +in { + config = mkIf dev.hasTPM { + security.tpm2 = { + # enable Trusted Platform Module 2 support + enable = true; + + # enable Trusted Platform 2 userspace resource manager daemon + abrmd.enable = mkDefault false; + + # The TCTI is the "Transmission Interface" that is used to communicate with a + # TPM. this option sets TCTI environment variables to the specified values if enabled + # - TPM2TOOLS_TCTI + # - TPM2_PKCS11_TCTI + tctiEnvironment.enable = mkDefault true; + + # enable TPM2 PKCS#11 tool and shared library in system path + pkcs11.enable = mkDefault false; + }; + }; +} diff --git a/nyx/modules/core/common/system/hardware/yubikey.nix b/nyx/modules/core/common/system/hardware/yubikey.nix new file mode 100644 index 0000000..129150d --- /dev/null +++ b/nyx/modules/core/common/system/hardware/yubikey.nix @@ -0,0 +1,33 @@ +{ + config, + lib, + pkgs, + ... +}: { + config = lib.mkIf config.modules.system.yubikeySupport.enable { + hardware.gpgSmartcards.enable = true; + + services = { + pcscd.enable = true; + udev.packages = [pkgs.yubikey-personalization]; + }; + + programs = { + ssh.startAgent = false; + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + }; + + environment.systemPackages = with pkgs; [ + # Yubico's official tools + yubikey-manager # cli + yubikey-manager-qt # gui + yubikey-personalization # cli + yubikey-personalization-gui # gui + yubico-piv-tool # cli + #yubioath-flutter # gui + ]; + }; +} diff --git a/nyx/modules/core/common/system/impermanence/default.nix b/nyx/modules/core/common/system/impermanence/default.nix new file mode 100644 index 0000000..a11ab19 --- /dev/null +++ b/nyx/modules/core/common/system/impermanence/default.nix @@ -0,0 +1,169 @@ +{ + config, + lib, + inputs, + ... +}: let + inherit (lib) optionalString mkIf mkForce; + + cfg = config.modules.system.impermanence; +in { + imports = [ + inputs.impermanence.nixosModules.impermanence + ]; + + config = mkIf cfg.enable { + users = { + # this option makes it that users are not mutable outside our configurations + # if you are on nixos, you are probably smart enough to not try and edit users + # manually outside your configuration.nix or whatever + # P.S: This option requires you to define a password file for your users + # inside your configuration.nix - you can generate this password with + # mkpasswd -m sha-512 > /persist/passwords/notashelf after you confirm /persist/passwords exists + mutableUsers = false; + + # each existing user needs to have a passwordFile defined here + # otherwise, they will not be available for a login + users = { + root = { + # passwordFile needs to be in a volume marked with `neededForBoot = true` + hashedPasswordFile = "/persist/passwords/root"; + }; + notashelf = { + hashedPasswordFile = "/persist/passwords/notashelf"; + }; + }; + }; + + # home.persistence."/persist/home/notashelf" = {}; + environment.persistence."/persist" = { + directories = + [ + "/etc/nixos" + "/etc/nix" + "/etc/NetworkManager/system-connections" + "/etc/secureboot" + "/var/db/sudo" + "/var/lib/flatpak" + "/var/lib/libvirt" + "/var/lib/bluetooth" + "/var/lib/nixos" + "/var/lib/pipewire" + "/var/lib/systemd/coredump" + "/var/cache/tailscale" + "/var/lib/tailscale" + ] + ++ [config.programs.ccache.cacheDir]; + + files = [ + # important state + "/etc/machine-id" + # ssh stuff + /* + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + */ + # other + # TODO: optionalstring for /var/lib/${lxd, docker} + ]; + + # builtins.concatMap (key: [key.path (key.path + ".pub")]) config.services.openssh.hostKeys + }; + + # for some reason *this* is what makes networkmanager not get screwed completely instead of the impermanence module + systemd.tmpfiles.rules = [ + "L /var/lib/NetworkManager/secret_key - - - - /persist/var/lib/NetworkManager/secret_key" + "L /var/lib/NetworkManager/seen-bssids - - - - /persist/var/lib/NetworkManager/seen-bssids" + "L /var/lib/NetworkManager/timestamps - - - - /persist/var/lib/NetworkManager/timestamps" + ]; + + services.openssh.hostKeys = mkForce [ + { + bits = 4096; + path = "/persist/etc/ssh/ssh_host_rsa_key"; + type = "rsa"; + } + { + bits = 4096; + path = "/persist/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; + + boot.initrd.systemd.services.rollback = { + description = "Rollback BTRFS root subvolume to a pristine state"; + wantedBy = ["initrd.target"]; + # make sure it's done after encryption + # i.e. LUKS/TPM process + after = ["systemd-cryptsetup@enc.service"]; + # mount the root fs before clearing + before = ["sysroot.mount"]; + unitConfig.DefaultDependencies = "no"; + serviceConfig.Type = "oneshot"; + script = '' + mkdir -p /mnt + + # We first mount the btrfs root to /mnt + # so we can manipulate btrfs subvolumes. + mount -o subvol=/ /dev/mapper/enc /mnt + + # If home is meant to be impermanent, also mount the home subvolume to be deleted later + ${optionalString cfg.home.enable "mount -o subvol=/home /dev/mapper/enc /mnt/home"} + + # While we're tempted to just delete /root and create + # a new snapshot from /root-blank, /root is already + # populated at this point with a number of subvolumes, + # which makes `btrfs subvolume delete` fail. + # So, we remove them first. + # + # /root contains subvolumes: + # - /root/var/lib/portables + # - /root/var/lib/machines + + btrfs subvolume list -o /mnt/root | + cut -f9 -d' ' | + while read subvolume; do + echo "deleting /$subvolume subvolume..." + btrfs subvolume delete "/mnt/$subvolume" + done && + echo "deleting /root subvolume..." && + btrfs subvolume delete /mnt/root + + echo "restoring blank /root subvolume..." + btrfs subvolume snapshot /mnt/root-blank /mnt/root + + ${optionalString cfg.home.enable '' + echo "restoring blank /home subvolume..." + mount -o subvol=/home /dev/mapper/enc /mnt/home + ''} + + # Once we're done rolling back to a blank snapshot, + # we can unmount /mnt and continue on the boot process. + umount /mnt + ''; + }; + + assertions = [ + { + assertion = cfg.home.enable -> !cfg.root.enable; + message = '' + You have enabled home impermanence without root impermanence. This + is not supported due to the fact that we handle all all impermanence + related deletions and creations in a single service. Please enable + `modules.system.impermanence.root.enable` if you wish to proceed. + ''; + } + ]; + + # home impermanence is not very safe, and chances are I don't want it. Warn any potential + # users (which may or may not be me) when it is enabled just to be safe. + # p.s. I really don't like nix's warnings syntax. why can't it be the same + # as the assertions format? /rant + warnings = + if cfg.home.enable + then ["Home impermanence is enabled. This is experimental, beware."] + else []; + }; +} diff --git a/nyx/modules/core/common/system/nix/builders.nix b/nyx/modules/core/common/system/nix/builders.nix new file mode 100644 index 0000000..1208269 --- /dev/null +++ b/nyx/modules/core/common/system/nix/builders.nix @@ -0,0 +1,52 @@ +{ + config, + lib, + ... +}: let + inherit (lib.attrsets) recursiveUpdate; + inherit (lib.lists) filter; + # a generic builder configuration + builder = { + systems = ["x86_64-linux"]; + speedFactor = 4; + maxJobs = 4; + supportedFeatures = ["benchmark" "nixos-test"]; + sshKey = "/home/notashelf/.ssh/builder"; + protocol = "ssh-ng"; + }; + + # override generic config builder with the assumption that more + # resources and features are available to us + bigBuilder = recursiveUpdate builder { + maxJobs = 16; + speedFactor = 16; + supportedFeatures = builder.supportedFeatures ++ ["kvm" "big-parallel"]; + systems = builder.systems ++ ["aarch64-linux" "i686-linux"]; + }; + + mkBuilder = { + builderBase ? builder, + sshProtocol ? "ssh-ng", + user ? "root", + host, + ... + }: + recursiveUpdate builderBase { + hostName = host; + sshUser = user; + protocol = sshProtocol; + }; +in { + nix = { + distributedBuilds = true; + buildMachines = filter (builder: builder.hostName != config.networking.hostName) [ + # large build machine + (mkBuilder { + builderBase = bigBuilder; + user = "builder"; + host = "build.neushore.dev"; + sshProtocol = "ssh"; # ssh-ng is not supported by this device + }) + ]; + }; +} diff --git a/nyx/modules/core/common/system/nix/default.nix b/nyx/modules/core/common/system/nix/default.nix new file mode 100644 index 0000000..df5be2e --- /dev/null +++ b/nyx/modules/core/common/system/nix/default.nix @@ -0,0 +1,222 @@ +{ + inputs, + self, + config, + pkgs, + lib, + ... +}: let + inherit (lib.trivial) pipe; + inherit (lib.types) isType; + inherit (lib.attrsets) mapAttrsToList optionalAttrs filterAttrs mapAttrs; + inherit (lib.modules) mkDefault; +in { + imports = [ + ./transcend # module that merges trees outside central nixpkgs with our system's + ./builders.nix # import builders config + ./overlays.nix + ]; + + system = { + autoUpgrade.enable = false; + stateVersion = mkDefault "23.05"; + }; + + environment = { + etc = with inputs; { + # set channels (backwards compatibility) + "nix/flake-channels/system".source = self; + "nix/flake-channels/nixpkgs".source = nixpkgs; + "nix/flake-channels/home-manager".source = home-manager; + + # preserve current flake in /etc + "nixos/flake".source = self; + }; + + # we need git for flakes, don't we + systemPackages = [pkgs.git]; + }; + + nixpkgs = { + # https://github.com/NixOS/nixpkgs/commit/eb8ce7930d14dafcc7eff56c2f9efca6a3b2f622 + # pkgs = self.legacyPackages.${config.nixpkgs.system}; + + config = { + allowUnfree = true; # really a pain in the ass to deal with when disabled + allowBroken = false; + allowUnsupportedSystem = true; + + # default to none, add more as necessary + permittedInsecurePackages = [ + "electron-24.8.6" + "electron-25.9.0" + "freeimage-unstable-2021-11-01" + ]; + }; + }; + + # faster rebuilding + documentation = { + doc.enable = false; + nixos.enable = true; + info.enable = false; + man = { + enable = mkDefault true; + generateCaches = mkDefault true; + }; + }; + + nix = let + # mappedRegistry = mapAttrs (_: v: {flake = v;}) inputs; + mappedRegistry = pipe inputs [ + (filterAttrs (_: isType "flake")) + (mapAttrs (_: flake: {inherit flake;})) + (x: x // {nixpkgs.flake = inputs.nixpkgs;}) + ]; + in { + package = pkgs.nixSuper; # pkgs.nixVersions.unstable; + + # pin the registry to avoid downloading and evaluating a new nixpkgs version every time + # this will add each flake input as a registry to make nix3 commands consistent with your flake + # additionally we also set `registry.default`, which was added by nix-super + registry = mappedRegistry // optionalAttrs (config.nix.package == pkgs.nixSuper) {default = mappedRegistry.nixpkgs;}; + + # This will additionally add your inputs to the system's legacy channels + # Making legacy nix commands consistent as well + nixPath = mapAttrsToList (key: _: "${key}=flake:${key}") config.nix.registry; + + # make builds run with low priority so my system stays responsive + # this is especially helpful if you have auto-upgrade on + daemonCPUSchedPolicy = "batch"; + daemonIOSchedClass = "idle"; + daemonIOSchedPriority = 7; + + # set up garbage collection to run weekly, + # removing unused packages that are older than 7 days + gc = { + automatic = true; + dates = "Mon *-*-* 03:00"; + options = "--delete-older-than 7d"; + }; + + # automatically optimize nix store my removing hard links + # do it after the gc + optimise = { + automatic = true; + dates = ["04:00"]; + }; + + settings = { + # tell nix to use the xdg spec for base directories + # while transitioning, any state must be carried over + # manually, as Nix won't do it for us + use-xdg-base-directories = true; + + # specify the path to the nix registry + flake-registry = "/etc/nix/registry.json"; + + # Free up to 10GiB whenever there is less than 5GB left. + # this setting is in bytes, so we multiply with 1024 thrice + min-free = "${toString (5 * 1024 * 1024 * 1024)}"; + max-free = "${toString (10 * 1024 * 1024 * 1024)}"; + + # automatically optimise symlinks + auto-optimise-store = true; + + # allow sudo users to mark the following values as trusted + allowed-users = ["root" "@wheel" "nix-builder"]; + + # only allow sudo users to manage the nix store + trusted-users = ["root" "@wheel" "nix-builder"]; + + # let the system decide the number of max jobs + max-jobs = "auto"; + + # build inside sandboxed environments + sandbox = true; + sandbox-fallback = false; + + # supported system features + system-features = ["nixos-test" "kvm" "recursive-nix" "big-parallel"]; + + # extra architectures supported by my builders + extra-platforms = config.boot.binfmt.emulatedSystems; + + # continue building derivations if one fails + keep-going = true; + + # show more log lines for failed builds + log-lines = 30; + + # enable new nix command and flakes + # and also "unintended" recursion as well as content addresssed nix + extra-experimental-features = [ + "flakes" # flakes + "nix-command" # experimental nix commands + "recursive-nix" # let nix invoke itself + "ca-derivations" # content addressed nix + "auto-allocate-uids" # allow nix to automatically pick UIDs, rather than creating nixbld* user accounts + "configurable-impure-env" # allow impure environments + "cgroups" # allow nix to execute builds inside cgroups + "git-hashing" # allow store objects which are hashed via Git's hashing algorithm + "verified-fetches" # enable verification of git commit signatures for fetchGit + ]; + + # don't warn me that my git tree is dirty, I know + warn-dirty = false; + + # maximum number of parallel TCP connections used to fetch imports and binary caches, 0 means no limit + http-connections = 50; + + # whether to accept nix configuration from a flake without prompting + accept-flake-config = false; + + # execute builds inside cgroups + use-cgroups = true; + + # for direnv GC roots + keep-derivations = true; + keep-outputs = true; + + # use binary cache, this is not gentoo + # external builders can also pick up those substituters + builders-use-substitutes = true; + + # substituters to use + substituters = [ + "https://cache.ngi0.nixos.org" # content addressed nix cache (TODO) + "https://cache.nixos.org" # funny binary cache + "https://cache.privatevoid.net" # for nix-super + "https://nixpkgs-wayland.cachix.org" # automated builds of *some* wayland packages + "https://nix-community.cachix.org" # nix-community cache + "https://hyprland.cachix.org" # hyprland + "https://nixpkgs-unfree.cachix.org" # unfree-package cache + "https://numtide.cachix.org" # another unfree package cache + "https://anyrun.cachix.org" # anyrun program launcher + "https://nyx.cachix.org" # cached stuff from my flake outputs + "https://neovim-flake.cachix.org" # a cache for my neovim flake + "https://cache.garnix.io" # garnix binary cache, hosts prismlauncher + "https://cache.notashelf.dev" # my own binary cache, served over https + "https://ags.cachix.org" # ags + ]; + + trusted-public-keys = [ + "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" + "cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=" + "cache.privatevoid.net:SErQ8bvNWANeAvtsOESUwVYr2VJynfuc9JRwlzTTkVg=" + "nixpkgs-wayland.cachix.org-1:3lwxaILxMRkVhehr5StQprHdEo4IrE8sRho9R9HOLYA=" + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" + "nixpkgs-unfree.cachix.org-1:hqvoInulhbV4nJ9yJOEr+4wxhDV4xq2d1DK7S6Nj6rs=" + "numtide.cachix.org-1:2ps1kLBUWjxIneOy1Ik6cQjb41X0iXVXeHigGmycPPE=" + "anyrun.cachix.org-1:pqBobmOjI7nKlsUMV25u9QHa9btJK65/C8vnO3p346s=" + "notashelf.cachix.org-1:VTTBFNQWbfyLuRzgm2I7AWSDJdqAa11ytLXHBhrprZk=" + "neovim-flake.cachix.org-1:iyQ6lHFhnB5UkVpxhQqLJbneWBTzM8LBYOFPLNH4qZw=" + "nyx.cachix.org-1:xH6G0MO9PrpeGe7mHBtj1WbNzmnXr7jId2mCiq6hipE=" + "cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g=" + "cache.notashelf.dev-1:DhlmJBtURj+XS3j4F8SFFukT8dYgSjtFcd3egH8rE6U=" + "ags.cachix.org-1:naAvMrz0CuYqeyGNyLgE010iUiuf/qx6kYrUv3NwAJ8=" + ]; + }; + }; +} diff --git a/nyx/modules/core/common/system/nix/overlays.nix b/nyx/modules/core/common/system/nix/overlays.nix new file mode 100644 index 0000000..ab33604 --- /dev/null +++ b/nyx/modules/core/common/system/nix/overlays.nix @@ -0,0 +1,52 @@ +{ + inputs', + lib, + ... +}: let + inherit (builtins) concatStringsSep length; + inherit (lib.lists) zipListsWith; + inherit (lib.strings) escapeShellArg; +in { + nixpkgs.overlays = [ + (_: prev: let + oldIcons = [ + "↑" + "↓" + "⏱" + "⏵" + "✔" + "⏸" + "⚠" + "∅" + "∑" + ]; + newIcons = [ + "f062" #  + "f063" #  + "f520" #  + "f04b" #  + "f00c" #  + "f04c" #  + "f071" #  + "f1da" #  + "f04a0" # 󰒠 + ]; + in { + nixSuper = inputs'.nix-super.packages.default; + nixSchemas = inputs'.nixSchemas.packages.default; + + nix-output-monitor = assert length oldIcons == length newIcons; + prev.nix-output-monitor.overrideAttrs (o: { + postPatch = + (o.postPatch or "") + + '' + sed -i ${escapeShellArg ( + concatStringsSep "\n" (zipListsWith (a: b: "s/${a}/\\\\x${b}/") oldIcons newIcons) + )} lib/NOM/Print.hs + + sed -i 's/┌/╭/' lib/NOM/Print/Tree.hs + ''; + }); + }) + ]; +} diff --git a/nyx/modules/core/common/system/nix/transcend/default.nix b/nyx/modules/core/common/system/nix/transcend/default.nix new file mode 100644 index 0000000..e3fe37b --- /dev/null +++ b/nyx/modules/core/common/system/nix/transcend/default.nix @@ -0,0 +1,37 @@ +# credits go to @eclairevoyant on this one +# lets us import modules from PRs that are not yet merged +# and handles disabling of the relevant module locally +# I've extracted the modules section to make this system more robust and explicit +{ + lib, + modulesPath, + ... +}: let + inherit (builtins) fetchTree getAttr map; + inherit (lib.attrsets) attrValues; + + modules = import ./modules.nix; + + transcendModules = + map ({ + # repo details + owner, + repo, + rev, + narHash, + # module path + module, + }: { + disabledModules = modulesPath + module; + importedModules = + (fetchTree { + type = "github"; + inherit owner repo rev narHash; + }) + + "/nixos/modules/${module}"; + }) + (attrValues modules); +in { + disabledModules = map (getAttr "disabledModules") transcendModules; + imports = map (getAttr "importedModules") transcendModules; +} diff --git a/nyx/modules/core/common/system/nix/transcend/modules.nix b/nyx/modules/core/common/system/nix/transcend/modules.nix new file mode 100644 index 0000000..fcfceff --- /dev/null +++ b/nyx/modules/core/common/system/nix/transcend/modules.nix @@ -0,0 +1,12 @@ +{ + # the name here is arbitrary, and is used as an identifier + # what matters is the presence of owner, module and rev + "nix-gc" = { + # https://github.com/NixOS/nixpkgs/pull/260620 + owner = "nobbz"; + repo = "nixpkgs"; + module = "/services/misc/nix-gc.nix"; + rev = "10ec045f1dc82c72630c85906e1ae1d54340a7e0"; + narHash = "sha256-AV3TXXWp0AxM98wCbEa3iThUQ5AbTMC/3fZAa50lfKI="; + }; +} diff --git a/nyx/modules/core/common/system/os/activation/default.nix b/nyx/modules/core/common/system/os/activation/default.nix new file mode 100644 index 0000000..969ebd5 --- /dev/null +++ b/nyx/modules/core/common/system/os/activation/default.nix @@ -0,0 +1,39 @@ +{ + config, + pkgs, + lib, + ... +}: { + system.activationScripts = { + # if system declares that it wants closure diffs, then run the diff script on activation + # this is useless if you are using nh, which does this for you in a different way + diff = lib.mkIf config.modules.system.activation.diffGenerations { + supportsDryActivation = true; + text = '' + if [[ -e /run/current-system ]]; then + echo "=== diff to current-system ===" + ${pkgs.nvd}/bin/nvd --nix-bin-dir='${config.nix.package}/bin' diff /run/current-system "$systemConfig" + echo "=== end of the system diff ===" + fi + ''; + }; + + # + # symlink root's ssh config to ours + # to fix nix-daemon's ability to remote build since it sshs from the root account + root_ssh_config = let + sshDir = "/home/notashelf/.ssh"; + in { + text = '' + ( + # symlink root ssh config to ours so daemon can use our agent/keys/etc... + mkdir -p /root/.ssh + ln -sf ${sshDir}/config /root/.ssh/config + ln -sf ${sshDir}/known_hosts /root/.ssh/known_hosts + ln -sf ${sshDir}/known_hosts /root/.ssh/known_hosts + ) + ''; + deps = []; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/boot/default.nix b/nyx/modules/core/common/system/os/boot/default.nix new file mode 100644 index 0000000..e0b8a0b --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./loaders # per-bootloader configurations + ./secure-boot.nix # secure boot module + ./generic.nix # generic configuration, such as kernel and tmpfs setup + ./plymouth.nix # plymouth boot splash + ]; +} diff --git a/nyx/modules/core/common/system/os/boot/generic.nix b/nyx/modules/core/common/system/os/boot/generic.nix new file mode 100644 index 0000000..6429af7 --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/generic.nix @@ -0,0 +1,180 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkDefault mkForce mkOverride mkMerge mkIf optionals; + + sys = config.modules.system; +in { + config.boot = { + # kernel console loglevel + consoleLogLevel = 3; + + # always use the latest kernel instead of the old-ass lts one + kernelPackages = mkOverride 500 sys.boot.kernel; + + # additional packages supplying kernel modules + extraModulePackages = mkDefault sys.boot.extraModulePackages; + + # configuration to be appended to the generated modprobe.conf + extraModprobeConfig = mkDefault sys.boot.extraModprobeConfig; + + # whether to enable support for Linux MD RAID arrays + # I don't know why this defaults to true, how many people use RAID anyway? + # also on > 23.11, this will throw a warning if neither MAILADDR nor PROGRAM are set + swraid.enable = mkDefault false; + + # settings shared between bootloaders + # they are set unless system.boot.loader != none + loader = { + # if set to 0, space needs to be held to get the boot menu to appear + timeout = mkForce 2; + + # whether to copy the necessary boot files into /boot + # so that /nix/store is not needed by the boot loader. + generationsDir.copyKernels = true; + + # allow installation to modify EFI variables + efi.canTouchEfiVariables = true; + }; + + # instructions on how /tmp should be handled + # if your system is low on ram, you should avoid tmpfs to prevent hangups while compiling + tmp = { + # /tmp on tmpfs, lets it live on your ram + # it defaults to FALSE, which means you will use disk space instead of ram + # enable tmpfs tmp on anything except servers and builders + useTmpfs = sys.boot.tmpOnTmpfs; + + # If not using tmpfs, which is naturally purged on reboot, we must clean + # /tmp ourselves. /tmp should be volatile storage! + cleanOnBoot = mkDefault (!config.boot.tmp.useTmpfs); + + # The size of the tmpfs, in percentage form + # this defaults to 50% of your ram, which is a good default + # but should be tweaked based on your systems capabilities + tmpfsSize = mkDefault "75%"; + }; + + # initrd and kernel tweaks + # if you intend to copy paste this section, read what each parameter or module does before doing so + # or perish, I am not responsible for your broken system. if you copy paste this section without reading + # and later realise your mistake, you are a moron. + initrd = mkMerge [ + (mkIf sys.boot.initrd.enableTweaks { + # Verbosity of the initrd + # disabling verbosity removes only the mandatory messages generated by the NixOS + verbose = false; + + systemd = { + # enable systemd in initrd + # extremely experimental, just the way I like it on a production machine + enable = true; + + # strip copied binaries and libraries from inframs + # saves 30~ mb space according to the nix derivation + strip = true; + + # packages that will be added to the PATH in initrd + # this is useful for debugging if the host provides + # emergency access + storePaths = with pkgs; [util-linux pciutils]; + extraBin = { + fdisk = "${pkgs.util-linux}/bin/fdisk"; + lsblk = "${pkgs.util-linux}/bin/lsblk"; + lspci = "${pkgs.pciutils}/bin/lspci"; + }; + }; + + # List of modules that are always loaded by the initrd + kernelModules = [ + "ahci" + "nvme" + "xhci_pci" + "btrfs" + "sd_mod" + "dm_mod" + "tpm" + ]; + + # the set of kernel modules in the initial ramdisk used during the boot process + availableKernelModules = [ + "usbhid" + "sd_mod" + "sr_mod" + "dm_mod" + "uas" + "usb_storage" + "rtsx_usb_sdmmc" + "rtsx_pci_sdmmc" # Realtek PCI-Express SD/MMC Card Interface driver + "ata_piix" + "virtio_pci" + "virtio_scsi" + "ehci_pci" + ]; + }) + + (mkIf sys.boot.initrd.optimizeCompressor + { + compressor = "zstd"; + compressorArgs = ["-19" "-T0"]; + }) + ]; + + # https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html + kernelParams = + (optionals sys.boot.enableKernelTweaks [ + # https://en.wikipedia.org/wiki/Kernel_page-table_isolation + # auto means kernel will automatically decide the pti state + "pti=auto" # on | off + + # CPU idle behaviour + # poll: slightly improve performance at cost of a hotter system (not recommended) + # halt: halt is forced to be used for CPU idle + # nomwait: Disable mwait for CPU C-states + "idle=nomwait" # poll | halt | nomwait + + # enable IOMMU for devices used in passthrough + # and provide better host performance in virtualization + "iommu=pt" + + # disable usb autosuspend + "usbcore.autosuspend=-1" + + # disables resume and restores original swap space + "noresume" + + # allows systemd to set and save the backlight state + "acpi_backlight=native" # none | vendor | video | native + + # prevent the kernel from blanking plymouth out of the fb + "fbcon=nodefer" + + # disable the cursor in vt to get a black screen during intermissions + "vt.global_cursor_default=0" + + # disable displaying of the built-in Linux logo + "logo.nologo" + ]) + ++ (optionals sys.boot.silentBoot [ + # tell the kernel to not be verbose + "quiet" + + # kernel log message level + "loglevel=3" # 1: sustem is unusable | 3: error condition | 7: very verbose + + # udev log message level + "udev.log_level=3" + + # lower the udev log level to show only errors or worse + "rd.udev.log_level=3" + + # disable systemd status messages + # rd prefix means systemd-udev will be used instead of initrd + "systemd.show_status=auto" + "rd.systemd.show_status=auto" + ]); + }; +} diff --git a/nyx/modules/core/common/system/os/boot/loaders/default.nix b/nyx/modules/core/common/system/os/boot/loaders/default.nix new file mode 100644 index 0000000..699cef0 --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/loaders/default.nix @@ -0,0 +1,6 @@ +_: { + imports = [ + ./grub + ./systemd-boot + ]; +} diff --git a/nyx/modules/core/common/system/os/boot/loaders/grub/default.nix b/nyx/modules/core/common/system/os/boot/loaders/grub/default.nix new file mode 100644 index 0000000..463e3c3 --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/loaders/grub/default.nix @@ -0,0 +1,24 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkDefault mkIf; + + cfg = config.modules.system; +in { + config = mkIf (cfg.boot.loader == "grub") { + boot.loader = { + grub = { + enable = mkDefault true; + useOSProber = true; + efiSupport = true; + enableCryptodisk = mkDefault false; + device = cfg.boot.grub.device; + theme = null; + backgroundColor = null; + splashImage = null; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/boot/loaders/none/default.nix b/nyx/modules/core/common/system/os/boot/loaders/none/default.nix new file mode 100644 index 0000000..f27a13e --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/loaders/none/default.nix @@ -0,0 +1,16 @@ +{ + lib, + config, + ... +}: let + inherit (lib) mkIf mkForce; + + cfg = config.modules.system; +in { + config = mkIf (cfg.boot.loader == "none") { + boot.loader = { + grub.enable = mkForce false; + systemd-boot.enable = mkForce false; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/boot/loaders/systemd-boot/default.nix b/nyx/modules/core/common/system/os/boot/loaders/systemd-boot/default.nix new file mode 100644 index 0000000..202b2f6 --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/loaders/systemd-boot/default.nix @@ -0,0 +1,32 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkDefault mkIf optionalAttrs; + + cfg = config.modules.system; +in { + config = mkIf (cfg.boot.loader == "systemd-boot") { + boot.loader = { + systemd-boot = + { + enable = mkDefault true; + configurationLimit = null; # unlimited + consoleMode = mkDefault "max"; # the default is "keep", can be overriden per host if need be + + # Fix a security hole in place for backwards compatibility. See desc in + # nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix + editor = false; + } + // optionalAttrs cfg.boot.memtest.enable { + # https://matrix.to/#/!sgkZKRutwatDMkYBHU:nixos.org/$iKnJUt1L_7E5bq7hStDPwv6_2HTBvNjwfcWxlKlF-k8?via=nixos.org&via=matrix.org&via=nixos.dev + extraFiles."efi/memtest86plus/memtest.efi" = "${cfg.boot.memtest.package}/memtest.efi"; + extraEntries."memtest86plus.conf" = '' + title MemTest86+ + efi /efi/memtest86plus/memtest.efi + ''; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/boot/plymouth.nix b/nyx/modules/core/common/system/os/boot/plymouth.nix new file mode 100644 index 0000000..9097453 --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/plymouth.nix @@ -0,0 +1,39 @@ +{ + config, + lib, + pkgs, + self', + ... +}: let + inherit (pkgs) plymouth; + inherit (lib) mkIf; + + cfg = config.modules.system.boot.plymouth; +in { + config = mkIf cfg.enable { + # configure plymouth theme + # + boot.plymouth = let + pack = cfg.pack; + theme = cfg.theme; + in + { + enable = true; + } + // lib.optionalAttrs cfg.withThemes { + themePackages = [(self'.packages.plymouth-themes.override {inherit pack theme;})]; + + inherit theme; + }; + + # make plymouth work with sleep + powerManagement = { + powerDownCommands = '' + ${plymouth} --show-splash + ''; + resumeCommands = '' + ${plymouth} --quit + ''; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/boot/secure-boot.nix b/nyx/modules/core/common/system/os/boot/secure-boot.nix new file mode 100644 index 0000000..7b04e47 --- /dev/null +++ b/nyx/modules/core/common/system/os/boot/secure-boot.nix @@ -0,0 +1,36 @@ +{ + config, + pkgs, + lib, + inputs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system.boot; +in { + imports = [ + inputs.lanzaboote.nixosModules.lanzaboote + ]; + + config = mkIf sys.secureBoot { + environment.systemPackages = [ + # For debugging and troubleshooting Secure Boot. + pkgs.sbctl + ]; + + # Lanzaboote currently replaces the systemd-boot module. + # This setting is usually set to true in configuration.nix + # generated at installation time. So we force it to false + # for now. + boot.loader.systemd-boot.enable = lib.mkForce false; + + boot = { + bootspec.enable = true; + lanzaboote = { + enable = true; + pkiBundle = "/etc/secureboot"; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/default.nix b/nyx/modules/core/common/system/os/default.nix new file mode 100644 index 0000000..3a180d0 --- /dev/null +++ b/nyx/modules/core/common/system/os/default.nix @@ -0,0 +1,15 @@ +{ + imports = [ + ./activation # activation system for nixos-rebuild + ./boot # boot and bootloader configurations + ./display # display protocol (wayland/xorg) + ./environment # system environment e.g. locale, timezone, packages + ./fs # filesystem support options + ./misc # things that don't fit anywhere else + ./networking # network configuration & tcp optimizations + ./programs # general programs + ./services # gemeral services + ./theme # theming for desktop toolkits e.g. gtk, qt + ./users # per user configurations + ]; +} diff --git a/nyx/modules/core/common/system/os/display/default.nix b/nyx/modules/core/common/system/os/display/default.nix new file mode 100644 index 0000000..a383d42 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./wayland + ./xorg + ]; +} diff --git a/nyx/modules/core/common/system/os/display/wayland/default.nix b/nyx/modules/core/common/system/os/display/wayland/default.nix new file mode 100644 index 0000000..2b4d346 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/wayland/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./wms + + ./environment.nix + ./xdg-portals.nix + ./services.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/display/wayland/environment.nix b/nyx/modules/core/common/system/os/display/wayland/environment.nix new file mode 100644 index 0000000..6b34d97 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/wayland/environment.nix @@ -0,0 +1,34 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system.video; + env = config.modules.usrEnv; +in { + config = mkIf (sys.enable && env.isWayland) { + environment.etc."greetd/environments".text = '' + ${lib.optionalString (env.desktop == "Hyprland") "Hyprland"} + zsh + ''; + + environment = { + variables = { + NIXOS_OZONE_WL = "1"; + _JAVA_AWT_WM_NONEREPARENTING = "1"; + GDK_BACKEND = "wayland,x11"; + ANKI_WAYLAND = "1"; + MOZ_ENABLE_WAYLAND = "1"; + XDG_SESSION_TYPE = "wayland"; + SDL_VIDEODRIVER = "wayland"; + CLUTTER_BACKEND = "wayland"; + #WLR_DRM_NO_ATOMIC = "1"; + #WLR_BACKEND = "vulkan"; + #__GL_GSYNC_ALLOWED = "0"; + #__GL_VRR_ALLOWED = "0"; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/display/wayland/services.nix b/nyx/modules/core/common/system/os/display/wayland/services.nix new file mode 100644 index 0000000..5f991d3 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/wayland/services.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf getExe; + + cfg = config.modules.system.video; + env = config.modules.usrEnv; +in { + config = mkIf (cfg.enable && env.isWayland) { + systemd.services = { + seatd = { + enable = true; + description = "Seat management daemon"; + script = "${getExe pkgs.seatd} -g wheel"; + serviceConfig = { + Type = "simple"; + Restart = "always"; + RestartSec = "1"; + }; + wantedBy = ["multi-user.target"]; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/display/wayland/wms/default.nix b/nyx/modules/core/common/system/os/display/wayland/wms/default.nix new file mode 100644 index 0000000..3fbd598 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/wayland/wms/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./hyprland + ]; +} diff --git a/nyx/modules/core/common/system/os/display/wayland/wms/hyprland/default.nix b/nyx/modules/core/common/system/os/display/wayland/wms/hyprland/default.nix new file mode 100644 index 0000000..9f693ed --- /dev/null +++ b/nyx/modules/core/common/system/os/display/wayland/wms/hyprland/default.nix @@ -0,0 +1,24 @@ +{ + config, + lib, + inputs', + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + env = config.modules.usrEnv; +in { + # disables Nixpkgs Hyprland module to avoid conflicts + disabledModules = ["programs/hyprland.nix"]; + + config = mkIf (sys.video.enable && (env.desktop == "Hyprland" && env.isWayland)) { + services.xserver.displayManager.sessionPackages = [inputs'.hyprland.packages.default]; + + xdg.portal = { + extraPortals = [ + inputs'.xdg-portal-hyprland.packages.xdg-desktop-portal-hyprland + ]; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/display/wayland/xdg-portals.nix b/nyx/modules/core/common/system/os/display/wayland/xdg-portals.nix new file mode 100644 index 0000000..fd286a3 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/wayland/xdg-portals.nix @@ -0,0 +1,53 @@ +{ + config, + lib, + pkgs, + ... +}: let + sys = config.modules.system; + env = config.modules.usrEnv; + inherit (lib) mkForce mkIf; +in { + config = mkIf sys.video.enable { + xdg.portal = { + enable = true; + + extraPortals = [pkgs.xdg-desktop-portal-gtk]; + + config = { + common = let + portal = + if env.desktop == "Hyprland" + then "hyprland" + else if env.desktop == "sway" + then "wlr" + else "gtk"; # FIXME: does this actually implement what we need? + in { + default = [ + "hyprland" + "gtk" + ]; + + # for flameshot to work + # https://github.com/flameshot-org/flameshot/issues/3363#issuecomment-1753771427 + "org.freedesktop.impl.portal.Screencast" = "${portal}"; + "org.freedesktop.impl.portal.Screenshot" = "${portal}"; + }; + }; + + # xdg-desktop-wlr (this section) is no longer needed, xdg-desktop-portal-hyprland + # will (and should) override this one + # however in case I run a different compositor on a Wayland host, it can be enabled + wlr = { + enable = mkForce (env.isWayland && env.desktop != "Hyprland"); + settings = { + screencast = { + max_fps = 60; + chooser_type = "simple"; + chooser_cmd = "${pkgs.slurp}/bin/slurp -f %o -or"; + }; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/display/xorg/default.nix b/nyx/modules/core/common/system/os/display/xorg/default.nix new file mode 100644 index 0000000..fd2a93f --- /dev/null +++ b/nyx/modules/core/common/system/os/display/xorg/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./environment.nix + ./xserver.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/display/xorg/environment.nix b/nyx/modules/core/common/system/os/display/xorg/environment.nix new file mode 100644 index 0000000..1c5dcb5 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/xorg/environment.nix @@ -0,0 +1,18 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system.video; + env = config.modules.usrEnv; +in { + config = mkIf (sys.enable && !env.isWayland) { + environment.etc."greetd/environments".text = '' + ${lib.optionalString (env.desktop == "i3") "i3"} + ${lib.optionalString (env.desktop == "awesome") "awesome"} + zsh + ''; + }; +} diff --git a/nyx/modules/core/common/system/os/display/xorg/xserver.nix b/nyx/modules/core/common/system/os/display/xorg/xserver.nix new file mode 100644 index 0000000..3e18b73 --- /dev/null +++ b/nyx/modules/core/common/system/os/display/xorg/xserver.nix @@ -0,0 +1,5 @@ +{pkgs, ...}: { + services.xserver.excludePackages = [ + pkgs.xterm + ]; +} diff --git a/nyx/modules/core/common/system/os/environment/aliases.nix b/nyx/modules/core/common/system/os/environment/aliases.nix new file mode 100644 index 0000000..2b38c4f --- /dev/null +++ b/nyx/modules/core/common/system/os/environment/aliases.nix @@ -0,0 +1,19 @@ +{ + pkgs, + lib, + ... +}: { + environment.shellAliases = let + nr = "${pkgs.nixos-rebuild}/bin/nixos-rebuild"; + in { + # nix aliases + rebuild = "nix-store --verify; pushd ~dotfiles ; ${nr} switch --flake .#$1 --use-remote-sudo && notify-send \"Done\" ; popd"; + deploy = "${nr} switch --flake .#$1 --target-host $1 --use-remote-sudo -Lv"; + + # things I do to keep my home directory clean + wget = "wget --hsts-file='\${XDG_DATA_HOME}/wget-hsts'"; + + # init a LICENSE file with my go-to gpl3 license + "gpl" = "${lib.getExe pkgs.curl} https://www.gnu.org/licenses/gpl-3.0.txt -o LICENSE"; + }; +} diff --git a/nyx/modules/core/common/system/os/environment/default.nix b/nyx/modules/core/common/system/os/environment/default.nix new file mode 100644 index 0000000..8c1b160 --- /dev/null +++ b/nyx/modules/core/common/system/os/environment/default.nix @@ -0,0 +1,10 @@ +{ + imports = [ + ./aliases.nix + ./etc.nix + ./locale.nix + ./packages.nix + ./paths.nix + ./variables.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/environment/etc.nix b/nyx/modules/core/common/system/os/environment/etc.nix new file mode 100644 index 0000000..3ff4d37 --- /dev/null +++ b/nyx/modules/core/common/system/os/environment/etc.nix @@ -0,0 +1,8 @@ +{ + # https://github.com/NixOS/nixpkgs/issues/72394#issuecomment-549110501 + # the service is enabled by default, but this is not set. so by default, you will seee the error + # why? + environment.etc."mdadm.conf".text = '' + MAILADDR root + ''; +} diff --git a/nyx/modules/core/common/system/os/environment/locale.nix b/nyx/modules/core/common/system/os/environment/locale.nix new file mode 100644 index 0000000..5bc06b1 --- /dev/null +++ b/nyx/modules/core/common/system/os/environment/locale.nix @@ -0,0 +1,59 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib) mkDefault; +in { + time = { + timeZone = "Europe/Istanbul"; + hardwareClockInLocalTime = true; + }; + + services.xserver.xkb = { + layout = "tr"; + variant = ""; + }; + + i18n = let + defaultLocale = "en_US.UTF-8"; + tr = "tr_TR.UTF-8"; + in { + inherit defaultLocale; + + extraLocaleSettings = { + LANG = defaultLocale; + LC_COLLATE = defaultLocale; + LC_CTYPE = defaultLocale; + LC_MESSAGES = defaultLocale; + + LC_ADDRESS = tr; + LC_IDENTIFICATION = tr; + LC_MEASUREMENT = tr; + LC_MONETARY = tr; + LC_NAME = tr; + LC_NUMERIC = tr; + LC_PAPER = tr; + LC_TELEPHONE = tr; + LC_TIME = tr; + }; + + supportedLocales = mkDefault [ + "en_US.UTF-8/UTF-8" + "tr_TR.UTF-8/UTF-8" + ]; + + # ime configuration + inputMethod = { + enabled = "fcitx5"; # Needed for fcitx5 to work in qt6 + fcitx5.addons = with pkgs; [ + fcitx5-gtk + fcitx5-lua + libsForQt5.fcitx5-qt + + # themes + fcitx5-material-color + ]; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/environment/packages.nix b/nyx/modules/core/common/system/os/environment/packages.nix new file mode 100644 index 0000000..85335bf --- /dev/null +++ b/nyx/modules/core/common/system/os/environment/packages.nix @@ -0,0 +1,27 @@ +{ + pkgs, + lib, + ... +}: { + environment = { + # nixos ships a bunch of packages by default under environment.defaultPackages + # those do not add much to the system closure, but for a little added extra security + # and in an attempt to reduce my system closure size, I would like those to be + # removed from my packages + defaultPackages = lib.mkForce []; + + # packages that will be shared across all users and and all systems + # this should generally include tools used for debugging + # or system administration + systemPackages = with pkgs; [ + git + curl + wget + pciutils + lshw + man-pages + rsync + bind.dnsutils + ]; + }; +} diff --git a/nyx/modules/core/common/system/os/environment/paths.nix b/nyx/modules/core/common/system/os/environment/paths.nix new file mode 100644 index 0000000..1413d94 --- /dev/null +++ b/nyx/modules/core/common/system/os/environment/paths.nix @@ -0,0 +1,9 @@ +{ + # enable completions for system packages + # and other stuff + environment.pathsToLink = [ + "/share/zsh" # zsh completions + "/share/bash-completion" # bash completions + "/share/nix-direnv" # direnv completions + ]; +} diff --git a/nyx/modules/core/common/system/os/environment/variables.nix b/nyx/modules/core/common/system/os/environment/variables.nix new file mode 100644 index 0000000..512feb6 --- /dev/null +++ b/nyx/modules/core/common/system/os/environment/variables.nix @@ -0,0 +1,18 @@ +_: { + # variables that I want to set globally on all systems + + environment.variables = { + FLAKE = "/home/notashelf/.config/nyx"; + SSH_AUTH_SOCK = "/run/user/\${UID}/keyring/ssh"; + + # editors + EDITOR = "nvim"; + VISUAL = "nvim"; + SUDO_EDITOR = "nvim"; + + # pager stuff + SYSTEMD_PAGERSECURE = "true"; + PAGER = "less -FR"; + MANPAGER = "nvim +Man!"; + }; +} diff --git a/nyx/modules/core/common/system/os/fs/default.nix b/nyx/modules/core/common/system/os/fs/default.nix new file mode 100644 index 0000000..2285613 --- /dev/null +++ b/nyx/modules/core/common/system/os/fs/default.nix @@ -0,0 +1,52 @@ +{ + lib, + config, + ... +}: let + inherit (lib) mkIf mkMerge; + + sys = config.modules.system; +in { + config = mkMerge [ + (mkIf (builtins.elem "btrfs" sys.fs) { + # scrub btrfs devices + services.btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; + + # this fixes initrd.systemd.enable for whatever reason + boot = { + supportedFilesystems = ["btrfs"]; + initrd = { + supportedFilesystems = ["btrfs"]; + }; + }; + }) + + (mkIf (builtins.elem "ext4" sys.fs) { + boot = { + supportedFilesystems = ["ext4"]; + initrd = { + supportedFilesystems = ["ext4"]; + }; + }; + }) + + (mkIf (builtins.elem "exfat" sys.fs) { + boot = { + supportedFilesystems = ["exfat"]; + initrd = { + supportedFilesystems = ["exfat"]; + }; + }; + }) + + # accept both ntfs and ntfs3 as valid values + (mkIf ((builtins.elem "ntfs" sys.fs) || (builtins.elem "ntfs3" sys.fs)) { + boot = { + supportedFilesystems = ["ntfs"]; + }; + }) + ]; +} diff --git a/nyx/modules/core/common/system/os/misc/console.nix b/nyx/modules/core/common/system/os/misc/console.nix new file mode 100644 index 0000000..0ecc8aa --- /dev/null +++ b/nyx/modules/core/common/system/os/misc/console.nix @@ -0,0 +1,41 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) attrValues mkDefault; +in { + console = let + variant = "v18n"; + in { + enable = mkDefault true; + earlySetup = true; + keyMap = "trq"; + + font = "ter-powerline-${variant}"; + packages = attrValues {inherit (pkgs) terminus_font powerline-fonts;}; + }; + + # FIXME: kmscon, in my testing, is working as advertised and a performance difference + # is observable. However, enabling kmscon seems to *completely* ignore silent boot + # parameters. Not sure if this is a potential conflict with earlySetup (probably not) + # or kmscon not respecting the kernel parameters (more likely). Either way, I will + # revisit this in the future. + services.kmscon = { + enable = false; + hwRender = true; + fonts = [ + { + name = "Source Code Pro"; + package = pkgs.source-code-pro; + } + ]; + + extraOptions = "--term xterm-256color"; + extraConfig = '' + font-size=14 + xkb-layout=${config.console.layout} + ''; + }; +} diff --git a/nyx/modules/core/common/system/os/misc/crash.nix b/nyx/modules/core/common/system/os/misc/crash.nix new file mode 100644 index 0000000..0405ab3 --- /dev/null +++ b/nyx/modules/core/common/system/os/misc/crash.nix @@ -0,0 +1,12 @@ +{ + systemd = { + # TODO: those tend to include sensitie information, maybe we want to disable this? + # it could be an override in the security module + tmpfiles.rules = [ + # Enables storing of the kernel log (including stack trace) into pstore upon a panic or crash. + "w /sys/module/kernel/parameters/crash_kexec_post_notifiers - - - - Y" + # Enables storing of the kernel log upon a normal shutdown (shutdown, reboot, halt). + "w /sys/module/printk/parameters/always_kmsg_dump - - - - N" + ]; + }; +} diff --git a/nyx/modules/core/common/system/os/misc/default.nix b/nyx/modules/core/common/system/os/misc/default.nix new file mode 100644 index 0000000..74367d5 --- /dev/null +++ b/nyx/modules/core/common/system/os/misc/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./realtime.nix + ./crash.nix + ./journald.nix + ./console.nix + ./xdg-portals.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/misc/journald.nix b/nyx/modules/core/common/system/os/misc/journald.nix new file mode 100644 index 0000000..7a1debc --- /dev/null +++ b/nyx/modules/core/common/system/os/misc/journald.nix @@ -0,0 +1,20 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + dev = config.modules.device; +in { + # https://wiki.archlinux.org/title/Systemd/Journal#Persistent_journals + # limit systemd journal size + # journals get big really fasti and on desktops they are not audited often + # on servers, however, they are important for both security and stability + # thus, persisting them as is remains a good idea + services.journald.extraConfig = mkIf (dev.type != "server") '' + SystemMaxUse=100M + RuntimeMaxUse=50M + SystemMaxFileSize=50M + ''; +} diff --git a/nyx/modules/core/common/system/os/misc/realtime.nix b/nyx/modules/core/common/system/os/misc/realtime.nix new file mode 100644 index 0000000..d9818f3 --- /dev/null +++ b/nyx/modules/core/common/system/os/misc/realtime.nix @@ -0,0 +1,35 @@ +{config, ...}: { + # port of https://gitlab.archlinux.org/archlinux/packaging/packages/realtime-privileges + # see https://wiki.archlinux.org/title/Realtime_process_management + # tldr: realtime processes have higher priority than normal processes + # and that's a good thing + users = { + users."${config.modules.system.mainUser}".extraGroups = ["realtime"]; + groups.realtime = {}; + }; + + services.udev.extraRules = '' + KERNEL=="cpu_dma_latency", GROUP="realtime" + ''; + + security.pam.loginLimits = [ + { + domain = "@realtime"; + type = "-"; + item = "rtprio"; + value = 98; + } + { + domain = "@realtime"; + type = "-"; + item = "memlock"; + value = "unlimited"; + } + { + domain = "@realtime"; + type = "-"; + item = "nice"; + value = -11; + } + ]; +} diff --git a/nyx/modules/core/common/system/os/misc/xdg-portals.nix b/nyx/modules/core/common/system/os/misc/xdg-portals.nix new file mode 100644 index 0000000..bc80412 --- /dev/null +++ b/nyx/modules/core/common/system/os/misc/xdg-portals.nix @@ -0,0 +1,18 @@ +{ + config, + lib, + ... +}: let + sys = config.modules.system; + inherit (lib) mkIf; +in { + config = mkIf sys.video.enable { + xdg.portal.config = { + common = { + "org.freedesktop.impl.portal.Secret" = [ + "gnome-keyring" + ]; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/blocker.nix b/nyx/modules/core/common/system/os/networking/blocker.nix new file mode 100644 index 0000000..c568b50 --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/blocker.nix @@ -0,0 +1,16 @@ +{config, ...}: let + dev = config.modules.device; +in { + # this should block *most* junk sites + networking = { + stevenblack = { + enable = dev.type != "server"; # don't touch hosts file on a server + block = [ + "fakenews" + "gambling" + "porn" + #"social" # blocks stuff like reddit, which I occasionally visit + ]; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/default.nix b/nyx/modules/core/common/system/os/networking/default.nix new file mode 100644 index 0000000..4db2e62 --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/default.nix @@ -0,0 +1,108 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkForce mkDefault; +in { + imports = [ + ./firewall + + ./blocker.nix + ./network-manager.nix + ./optimize.nix + ./resolved.nix + ./ssh.nix + ./tailscale.nix + ./tcpcrypt.nix + ./wireless.nix + ]; + + # network tools that are helpful and nice to have + boot.kernelModules = ["af_packet"]; + environment.systemPackages = with pkgs; [ + mtr + tcpdump + traceroute + ]; + + networking = { + # generate a unique hostname by hashing the hostname + # with md5 and taking the first 8 characters of the hash + # this is especially helpful while using zfs but still + # ensures that there will be a unique hostId even when + # we are not using zfs + hostId = builtins.substring 0 8 (builtins.hashString "md5" config.networking.hostName); + + # global dhcp has been deprecated upstream + # use the new networkd service instead of the legacy + # "script-based" network setups. Host may contain individual + # dhcp interfaces or systemd-networkd configurations in host + # specific directories + useDHCP = mkForce false; + useNetworkd = mkForce true; + + # interfaces are assigned names that contain topology information (e.g. wlp3s0) + # and thus should be consistent across reboots + # this already defaults to true, we set it in case it changes upstream + usePredictableInterfaceNames = mkDefault true; + + # dns + nameservers = [ + # cloudflare, yuck + # shares data + "1.1.1.1" + "1.0.0.1" + "2606:4700:4700::1111" + "2606:4700:4700::1001" + + # quad9, said to be the best + # shares *less* data + "9.9.9.9" + "149.112.112.112" + "2620:fe::fe" + "2620:fe::9" + ]; + + # search paths used when resolving domain names + # this can allow us to find hosts on private networks + # e.g. wireguard, tailscale and headscale + search = [ + "notashelf.dev" # referss to the server itself + "notashelf.notashelf.dev" # headscale network + ]; + }; + + # enable wireless database, it helps with finding the right channels + hardware.wirelessRegulatoryDatabase = true; + + # allow for the system to boot without waiting for the network interfaces are online + # speeds up boot times + systemd = let + # TODO: allow for the hosts to define those interfaces + ethernetDevices = [ + "wlp1s0f0u8" # wifi dongle + ]; + in { + # according to 23.11 release notes, wait-online target has long been fixed + # spoiler: no it's not. + network.wait-online.enable = false; + services = + { + NetworkManager-wait-online.enable = false; + + # disable networkd and resolved from being restarted on configuration changes + # lets me avoid a short network outage when I change the configuration + # also means that I **must** reboot to make sure my network changes are + # are properly propagated + systemd-networkd.stopIfChanged = false; + systemd-resolved.stopIfChanged = false; + } + // lib.concatMapAttrs (_: v: v) (lib.genAttrs ethernetDevices (device: { + # Assign an IP address when the device is plugged in rather than on startup. Needed to prevent + # blocking the boot sequence when the device is unavailable, as it is hotpluggable. + "network-addresses-${device}".wantedBy = lib.mkForce ["sys-subsystem-net-devices-${device}.device"]; + })); + }; +} diff --git a/nyx/modules/core/common/system/os/networking/firewall/default.nix b/nyx/modules/core/common/system/os/networking/firewall/default.nix new file mode 100644 index 0000000..ddc7fda --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/firewall/default.nix @@ -0,0 +1,42 @@ +{ + pkgs, + lib, + config, + ... +}: let + inherit (lib) mkForce; + dev = config.modules.device; + cfg = config.networking.nftables; +in { + imports = [ + ./nftables + + ./fail2ban.nix + ./tarpit.nix + ]; + + config = { + # enable opensnitch firewall + # inactive until opensnitch UI is opened + # since the UI cannot be opened on servers, we + # disable it if dev.type is server + services.opensnitch.enable = dev.type != "server"; + + networking.firewall = { + enable = !cfg.enable; + package = + if cfg.enable + then pkgs.iptables-nftables-compat + else pkgs.iptables; + allowedTCPPorts = [443 8080]; + allowedUDPPorts = []; + allowPing = dev.type == "server"; + logReversePathDrops = true; + logRefusedConnections = false; # avoid log spam + # Leaks IPv6 route table entries due to kernel bug. This leads to degraded + # IPv6 performance in some situations. + # checkReversePath = config.boot.kernelPackages.kernelAtLeast "5.16"; + checkReversePath = mkForce false; # Don't filter DHCP packets, according to nixops-libvirtd + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/firewall/fail2ban.nix b/nyx/modules/core/common/system/os/networking/firewall/fail2ban.nix new file mode 100644 index 0000000..f43ff27 --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/firewall/fail2ban.nix @@ -0,0 +1,77 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf mkMerge mkForce; + inherit (lib.strings) concatStringsSep; + + sys = config.modules.system; +in { + # fail2ban firewall jail + services.fail2ban = { + enable = true; + extraPackages = [pkgs.nftables]; # make nftables accessible to fail2ban service + + ignoreIP = [ + "127.0.0.0/8" # localhost + "10.0.0.0/8" # wireguard + "100.64.0.0/16" # tailscale + "192.168.0.0/16" # local network + ]; + + maxretry = 7; + bantime-increment = { + enable = true; + rndtime = "12m"; + overalljails = true; + multipliers = "4 8 16 32 64 128 256 512 1024 2048"; + maxtime = "5000h"; # get banned for 5000 hours idiot + }; + + jails = mkMerge [ + { + # sshd jail + sshd = mkForce '' + enabled = true + port = ${concatStringsSep "," (map toString config.services.openssh.ports)} + mode = aggressive + ''; + } + { + # nftables jail + nftables-common = mkForce '' + enabled = true + banaction = nftables-multiport + chain = input + ''; + } + + (mkIf sys.services.vaultwarden.enable { + # vaultwarden and vaultwarden admin interface jails + vaultwarden = '' + enabled = true + port = 80,443,8822 + filter = vaultwarden + banaction = %(banaction_allports)s + logpath = /var/log/vaultwarden.log + maxretry = 3 + bantime = 14400 + findtime = 14400 + ''; + + vaultwarden-admin = '' + enabled = true + port = 80,443 + filter = vaultwarden-admin + banaction = %(banaction_allports)s + logpath = /var/log/vaultwarden.log + maxretry = 3 + bantime = 14400 + findtime = 14400 + ''; + }) + ]; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/firewall/nftables/default.nix b/nyx/modules/core/common/system/os/networking/firewall/nftables/default.nix new file mode 100644 index 0000000..0af530b --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/firewall/nftables/default.nix @@ -0,0 +1,70 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf mkRuleset; + + sys = config.modules.system; + cfg = config.networking.nftables; + + check-results = + pkgs.runCommand "check-nft-ruleset" { + ruleset = pkgs.writeText "nft-ruleset" cfg.ruleset; + } '' + mkdir -p $out + ${pkgs.nftables}/bin/nft -c -f $ruleset 2>&1 > $out/message \ + && echo false > $out/assertion \ + || echo true > $out/assertion + ''; +in { + imports = [./rules.nix]; + config = mkIf sys.networking.nftables.enable { + networking.nftables = { + enable = true; + + # flush ruleset on each reload + flushRuleset = true; + + # nftables.tables is semi-verbatim configuration + # that is inserted **before** nftables.ruleset + # as per the nftables module. + tables = { + "fail2ban" = { + name = "fail2ban-nftables"; + family = "ip"; + content = '' + # + chain input { + type filter hook input priority 100; + } + ''; + }; + }; + + # our ruleset, built with our local ruleset builder from lib/network/firewall.nix + # I prefer using this to the nftables.tables.* and verbatim nftables.ruleset = "" + # kinds of configs, as it allows me to programmatically approach to my ruleset + # instead of structuring it inside a multiline string. nftables.rules, which is + # located in ./rules.nix, is easily parsable and modifiable with the help of Nix. + ruleset = mkRuleset cfg.rules; + }; + + assertions = [ + { + assertion = import "${check-results}/assertion"; + message = '' + Bad config: + ${builtins.readFile "${check-results}/message"} + ''; + } + ]; + + # pin IFD as a system dependency + # this makes sure the IFD result is realised in time + # without making the IFD a part of the system + # unlike system.extraDependencies + system.checks = [check-results]; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/firewall/nftables/rules.nix b/nyx/modules/core/common/system/os/networking/firewall/nftables/rules.nix new file mode 100644 index 0000000..6aaa1ce --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/firewall/nftables/rules.nix @@ -0,0 +1,97 @@ +{ + config, + lib, + ... +}: let + inherit (lib) entryBefore entryBetween entryAfter entryAnywhere; +in { + networking.nftables.rules = { + inet = { + filter = { + input = { + loopback = entryAnywhere { + field = "iifname"; + value = "lo"; + policy = "accept"; + }; + + established-locally = entryAfter ["loopback"] { + protocol = "ct"; + field = "state"; + value = ["established" "related"]; + policy = "accept"; + }; + + basic-icmp6 = entryAfter ["loopback" "established-locally"] { + protocol = "ip6 nexthdr icmpv6 icmpv6"; + field = "type"; + value = [ + "destination-unreachable" + "packet-too-big" + "time-exceeded" + "parameter-problem" + "nd-router-advert" + "nd-neighbor-solicit" + "nd-neighbor-advert" + #"mld-listener-query" "nd-router-solicit" # for routers + ]; + policy = "accept"; + }; + + basic-icmp = entryAfter ["loopback" "established-locally"] { + protocol = "ip protocol icmp icmp"; + field = "type"; + value = [ + "destination-unreachable" + "router-advertisement" + "time-exceeded" + "parameter-problem" + ]; + policy = "accept"; + }; + + ping6 = entryBefore ["basic-icmp6"] { + protocol = "ip6 nexthdr icmpv6 icmpv6"; + field = "type"; + value = "echo-request"; + policy = "accept"; + }; + + ping = entryBefore ["basic-icmp"] { + protocol = "ip protocol icmp icmp"; + field = "type"; + value = "echo-request"; + policy = "accept"; + }; + + ssh = entryBetween ["basic-icmp6" "basic-icmp" "ping6" "ping"] ["default"] { + protocol = "tcp"; + field = "dport"; + value = config.services.openssh.ports; + policy = "accept"; + }; + + default = entryAfter ["loopback" "established-locally" "basic-icmp6" "basic-icmp" "ping6" "ping"] { + policy = lib.mkDefault "drop"; + }; + }; + + # accept all outgoing traffic + output = { + default = entryAnywhere { + policy = "accept"; + }; + }; + + # let nftables forward traffic + # we decide whether the host can forward traffic + # via sysctl settings elsewhere + forward = { + default = entryAnywhere { + policy = "accept"; + }; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/firewall/tarpit.nix b/nyx/modules/core/common/system/os/networking/firewall/tarpit.nix new file mode 100644 index 0000000..f2538d7 --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/firewall/tarpit.nix @@ -0,0 +1,32 @@ +# jebait agressive port scanners by wasting their time with connection that'll never make it in +# this *does* have performance implications, however, so be careful which hosts you enable it for +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.networking.tarpit; +in { + config = mkIf cfg.enable { + services.endlessh-go = { + enable = true; + port = 22; + openFirewall = true; + + extraOptions = [ + "-alsologtostderr" + "-geoip_supplier max-mind-db" + "-max_mind_db ${pkgs.clash-geoip}/etc/clash/Country.mmdb" + ]; + + prometheus = { + enable = true; + port = 9105; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/network-manager.nix b/nyx/modules/core/common/system/os/networking/network-manager.nix new file mode 100644 index 0000000..68fcdf3 --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/network-manager.nix @@ -0,0 +1,36 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf mkForce; + + dev = config.modules.device; + sys = config.modules.system; + + inherit (sys.networking) wireless; +in { + # we use networkmanager manage network devices locally + networking.networkmanager = { + enable = true; + plugins = mkForce []; # disable all plugins, we don't need them + dns = "systemd-resolved"; # use systemd-resolved as dns backend + unmanaged = [ + "interface-name:tailscale*" + "interface-name:br-*" + "interface-name:rndis*" + "interface-name:docker*" + "interface-name:virbr*" + ]; + + wifi = { + inherit (wireless) backend; # this can be iwd or wpa_supplicant, use wpa_supp. until iwd support is stable + macAddress = "random"; # use a random mac address on every boot + powersave = true; # enable wifi powersaving + scanRandMacAddress = true; # MAC address randomization of a Wi-Fi device during scanning + }; + + ethernet.macAddress = mkIf (dev.type != "server") "random"; # causes server to be unreachable over SSH + }; +} diff --git a/nyx/modules/core/common/system/os/networking/optimize.nix b/nyx/modules/core/common/system/os/networking/optimize.nix new file mode 100644 index 0000000..bc01c4c --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/optimize.nix @@ -0,0 +1,78 @@ +{ + config, + lib, + ... +}: let + sys = config.modules.system.networking; + inherit (lib) mkIf; +in { + config = mkIf sys.optimizeTcp { + boot = { + kernelModules = ["tls" "tcp_bbr"]; + kernel.sysctl = { + # TCP hardening + # Prevent bogus ICMP errors from filling up logs. + "net.ipv4.icmp_ignore_bogus_error_responses" = 1; + # Reverse path filtering causes the kernel to do source validation of + # packets received from all interfaces. This can mitigate IP spoofing. + "net.ipv4.conf.default.rp_filter" = 1; + "net.ipv4.conf.all.rp_filter" = 1; + # Do not accept IP source route packets (we're not a router) + "net.ipv4.conf.all.accept_source_route" = 0; + "net.ipv6.conf.all.accept_source_route" = 0; + # Don't send ICMP redirects (again, we're on a router) + "net.ipv4.conf.all.send_redirects" = 0; + "net.ipv4.conf.default.send_redirects" = 0; + # Refuse ICMP redirects (MITM mitigations) + "net.ipv4.conf.all.accept_redirects" = 0; + "net.ipv4.conf.default.accept_redirects" = 0; + "net.ipv4.conf.all.secure_redirects" = 0; + "net.ipv4.conf.default.secure_redirects" = 0; + "net.ipv6.conf.all.accept_redirects" = 0; + "net.ipv6.conf.default.accept_redirects" = 0; + # Protects against SYN flood attacks + "net.ipv4.tcp_syncookies" = 1; + # Incomplete protection again TIME-WAIT assassination + "net.ipv4.tcp_rfc1337" = 1; + # And other stuff + "net.ipv4.conf.all.log_martians" = true; + "net.ipv4.conf.default.log_martians" = true; + "net.ipv4.icmp_echo_ignore_broadcasts" = true; + "net.ipv6.conf.default.accept_ra" = 0; + "net.ipv6.conf.all.accept_ra" = 0; + "net.ipv4.tcp_timestamps" = 0; + + # TCP optimization + # TCP Fast Open is a TCP extension that reduces network latency by packing + # data in the sender’s initial TCP SYN. Setting 3 = enable TCP Fast Open for + # both incoming and outgoing connections: + "net.ipv4.tcp_fastopen" = 3; + # Bufferbloat mitigations + slight improvement in throughput & latency + "net.ipv4.tcp_congestion_control" = "bbr"; + "net.core.default_qdisc" = "cake"; + + # Other stuff that I am too lazy to document + "net.core.optmem_max" = 65536; + "net.core.rmem_default" = 1048576; + "net.core.rmem_max" = 16777216; + "net.core.somaxconn" = 8192; + "net.core.wmem_default" = 1048576; + "net.core.wmem_max" = 16777216; + "net.ipv4.ip_local_port_range" = "16384 65535"; + "net.ipv4.tcp_max_syn_backlog" = 8192; + "net.ipv4.tcp_max_tw_buckets" = 2000000; + "net.ipv4.tcp_mtu_probing" = 1; + "net.ipv4.tcp_rmem" = "4096 1048576 2097152"; + "net.ipv4.tcp_slow_start_after_idle" = 0; + "net.ipv4.tcp_tw_reuse" = 1; + "net.ipv4.tcp_wmem" = "4096 65536 16777216"; + "net.ipv4.udp_rmem_min" = 8192; + "net.ipv4.udp_wmem_min" = 8192; + "net.netfilter.nf_conntrack_generic_timeout" = 60; + "net.netfilter.nf_conntrack_max" = 1048576; + "net.netfilter.nf_conntrack_tcp_timeout_established" = 600; + "net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 1; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/resolved.nix b/nyx/modules/core/common/system/os/networking/resolved.nix new file mode 100644 index 0000000..bff84dd --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/resolved.nix @@ -0,0 +1,34 @@ +{ + services = { + resolved = { + # enable systemd DNS resolver daemon + enable = true; + + # this is necessary to get tailscale picking up your headscale instance + # and allows you to ping connected hosts by hostname + domains = ["~."]; + + # DNSSEC provides to DNS clients (resolvers) origin authentication of DNS data, authenticated denial of existence + # and data integrity but not availability or confidentiality. + # this is considered EXPERIMENTAL and UNSTABLE according to upstream + # PLEASE SEE + # before you decide to set this. I have it set to false as the issue + # does not inspire confidence in systemd's ability to manage this + dnssec = "false"; + + # additional configuration to be appeneded to systemd-resolved configuration + extraConfig = '' + # + # apparently upstream (systemd) recommends this to be false + # `allow-downgrade` is vulnerable to downgrade attacks + DNSOverTLS=yes # or allow-downgrade + ''; + + # ideally our fallbackDns should be something more widely available + # but I do not want my last resort to sell my data to every company available + # NOTE: DNS fallback is not a recovery DNS + # See + fallbackDns = ["9.9.9.9"]; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/ssh.nix b/nyx/modules/core/common/system/os/networking/ssh.nix new file mode 100644 index 0000000..c0581ca --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/ssh.nix @@ -0,0 +1,131 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkForce mkDefault; + inherit (lib.strings) concatStringsSep; + inherit (lib.attrsets) mapAttrs; + inherit (lib.lists) elemAt; +in { + services.openssh = { + # enable openssh + enable = true; + openFirewall = true; # the ssh port(s) should be automatically passed to the firewall's allowedTCPports + ports = [30]; # the port(s) openssh daemon should listen on + startWhenNeeded = true; # automatically start the ssh daemon when it's required + settings = { + # no root login + PermitRootLogin = mkForce "no"; + + # no password auth + # force publickey authentication only + PasswordAuthentication = false; + AuthenticationMethods = "publickey"; + PubkeyAuthentication = "yes"; + ChallengeResponseAuthentication = "no"; + UsePAM = "no"; + + # remove sockets as they get stale + # this will unbind gnupg sockets if they exists + StreamLocalBindUnlink = "yes"; + + KbdInteractiveAuthentication = mkDefault false; + UseDns = false; # no + X11Forwarding = false; # ew xorg + + # key exchange algorithms recommended by `nixpkgs#ssh-audit` + KexAlgorithms = [ + "curve25519-sha256" + "curve25519-sha256@libssh.org" + "diffie-hellman-group16-sha512" + "diffie-hellman-group18-sha512" + "diffie-hellman-group-exchange-sha256" + "sntrup761x25519-sha512@openssh.com" + ]; + + # message authentication code algorithms recommended by `nixpkgs#ssh-audit` + Macs = [ + "hmac-sha2-512-etm@openssh.com" + "hmac-sha2-256-etm@openssh.com" + "umac-128-etm@openssh.com" + ]; + + # kick out inactive sessions + ClientAliveCountMax = 5; + ClientAliveInterval = 60; + + # max auth attempts + MaxAuthTries = 3; + }; + + hostKeys = mkDefault [ + { + bits = 4096; + path = "/etc/ssh/ssh_host_rsa_key"; + type = "rsa"; + } + { + bits = 4096; + path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; + }; + + programs.ssh = let + # a list of hosts that are connected over Tailscale + # it would be better to construct this list dynamically + # but we hardcode it because we cannot check if a host is + # authenticated - that needs manual intervention + hosts = ["helios" "enyo" "hermes"]; + + # generate the ssh config for the hosts + mkHostConfig = hostname: '' + # Configuration for ${hostname} + Host ${hostname} + HostName ${hostname} + Port ${toString (elemAt config.services.openssh.ports 0)} + StrictHostKeyChecking=accept-new + ''; + + hostConfig = concatStringsSep "\n" (map mkHostConfig hosts); + in { + startAgent = !config.modules.system.yubikeySupport.enable; + extraConfig = '' + ${hostConfig} + ''; + + # ship github/gitlab/sourcehut host keys to avoid MiM (man in the middle) attacks + knownHosts = mapAttrs (_: mkForce) { + github-rsa = { + hostNames = ["github.com"]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=="; + }; + + github-ed25519 = { + hostNames = ["github.com"]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl"; + }; + + gitlab-rsa = { + hostNames = ["gitlab.com"]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9"; + }; + gitlab-ed25519 = { + hostNames = ["gitlab.com"]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf"; + }; + + sourcehut-rsa = { + hostNames = ["git.sr.ht"]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZ+l/lvYmaeOAPeijHL8d4794Am0MOvmXPyvHTtrqvgmvCJB8pen/qkQX2S1fgl9VkMGSNxbp7NF7HmKgs5ajTGV9mB5A5zq+161lcp5+f1qmn3Dp1MWKp/AzejWXKW+dwPBd3kkudDBA1fa3uK6g1gK5nLw3qcuv/V4emX9zv3P2ZNlq9XRvBxGY2KzaCyCXVkL48RVTTJJnYbVdRuq8/jQkDRA8lHvGvKI+jqnljmZi2aIrK9OGT2gkCtfyTw2GvNDV6aZ0bEza7nDLU/I+xmByAOO79R1Uk4EYCvSc1WXDZqhiuO2sZRmVxa0pQSBDn1DB3rpvqPYW+UvKB3SOz"; + }; + + sourcehut-ed25519 = { + hostNames = ["git.sr.ht"]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMZvRd4EtM7R+IHVMWmDkVU3VLQTSwQDSAvW0t2Tkj60"; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/tailscale.nix b/nyx/modules/core/common/system/os/networking/tailscale.nix new file mode 100644 index 0000000..29f489e --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/tailscale.nix @@ -0,0 +1,96 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf mkDefault optionals mkBefore; + inherit (config.services) tailscale; + + sys = config.modules.system.networking; + cfg = sys.tailscale; + + upFlags = + cfg.flags.default + ++ ["--authkey file:${config.age.secrets.tailscale-client.path}"] + ++ optionals cfg.isServer ["--advertise-exit-node"] + ++ optionals (cfg.endpoint != null) ["--login-server ${cfg.endpoint}"] + # TODO: test if specifying an operator messes with the autologin service + # which, as you expect, does not run as the operator user + ++ optionals (cfg.operator != null) ["--operator" cfg.operator]; +in { + config = mkIf cfg.enable { + # make the tailscale command usable to users + environment.systemPackages = [pkgs.tailscale]; + + networking.firewall = { + # always allow traffic from the designated tailscale interface + trustedInterfaces = ["${tailscale.interfaceName}"]; + checkReversePath = "loose"; + + # allow + allowedUDPPorts = [tailscale.port]; + }; + + boot.kernel = { + sysctl = { + # # Enable IP forwarding + # required for Wireguard & Tailscale/Headscale subnet feature + # See + "net.ipv4.ip_forward" = true; + "net.ipv6.conf.all.forwarding" = true; + }; + }; + + # enable tailscale, inter-machine VPN service + services.tailscale = { + enable = true; + permitCertUid = "root"; + useRoutingFeatures = mkDefault "both"; + # TODO: these flags still need to be specified with `tailscale up` + # for some reason + extraUpFlags = upFlags; + }; + + systemd = { + services = { + # lets not send our logs to log.tailscale.io + # unless I get to know what they do with the logs + tailscaled.serviceConfig.Environment = mkBefore ["TS_NO_LOGS_NO_SUPPORT=true"]; + + # oneshot tailscale authentication servcie + # TODO: this implies tailscale has been authenticated before with our own login server + # ideally we should have a way to authenticate tailscale with our own login server in + # this service, likely through an option in the system module + tailscale-autoconnect = { + description = "Automatic connection to Tailscale"; + + # make sure tailscale is running before trying to connect to tailscale + after = ["network-pre.target" "tailscale.service"]; + wants = ["network-pre.target" "tailscale.service"]; + wantedBy = ["multi-user.target"]; + + # set this service as a oneshot job + serviceConfig.Type = "oneshot"; + + # have the job run this shell script + script = '' + # wait for tailscaled to settle + sleep 2 + + # check if we are already authenticated to tailscale + status="$(${pkgs.tailscale}/bin/tailscale status -json | ${pkgs.jq}/bin/jq -r .BackendState)" + if [ $status = "Running" ]; then # if so, then do nothing + exit 0 + fi + + # otherwise authenticate with tailscale + ${pkgs.tailscale}/bin/tailscale up ${toString upFlags} + ''; + }; + }; + + network.wait-online.ignoredInterfaces = ["${tailscale.interfaceName}"]; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/tcpcrypt.nix b/nyx/modules/core/common/system/os/networking/tcpcrypt.nix new file mode 100644 index 0000000..f09b5cf --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/tcpcrypt.nix @@ -0,0 +1,101 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + dev = config.modules.device; +in { + # get rid of the tcpcrypt module provided by nixpkgs + # it is unmaintained and I cannot be arsed to PR a fix + disabledModules = ["services/networking/tcpcrypt.nix"]; + config = mkIf (dev.type != "server") { + # FIXME: the upstream tcpcrypd service is unmaintained and poorly designed + # networking.tcpcrypt.enable = true; + + # create a system user for the tcpcrypt service + # this is the user we will use the systemd service as + users = { + groups.tcpcryptd = {}; + users.tcpcryptd = { + description = "tcpcrypt daemon user"; + group = "tcpcryptd"; + uid = config.ids.uids.tcpcryptd; # nixpkgs already defines a hardcoded uid, use it + }; + }; + + # enable opportunistic TCP encryption + # this is NOT a pancea, however, if the receiver supports encryption and the attacker is passive + # privacy will be more plausible (but not guaranteed, unlike what the option docs suggest) + # NOTE: the systemd service below is rewritten to be an alternative to networking.tcpcrypt.enable + # it lacks hardening and SHOULD NOT BE USED until further notice. + systemd.services.tcpcrypt = let + # borrowed from fedora's tcpcrypt rpm spec + # + tcpcryptd-firewall = pkgs.writeShellApplication { + name = "tcpcryptd-firewall"; + runtimeInputs = [pkgs.iptables]; + text = '' + + # use iptables manually + if [ "$1" = "start" ]; then + iptables -t raw -N nixos-tcpcrypt + iptables -t raw -A nixos-tcpcrypt -p tcp -m mark --mark 0x0/0x10 -j NFQUEUE --queue-num 666 + iptables -t raw -I PREROUTING -j nixos-tcpcrypt + + iptables -t mangle -N nixos-tcpcrypt + iptables -t mangle -A nixos-tcpcrypt -p tcp -m mark --mark 0x0/0x10 -j NFQUEUE --queue-num 666 + iptables -t mangle -I POSTROUTING -j nixos-tcpcrypt + fi + + if [ "$1" = "stop" ]; then + iptables -t mangle -D POSTROUTING -j nixos-tcpcrypt || true + iptables -t raw -D PREROUTING -j nixos-tcpcrypt || true + + iptables -t raw -F nixos-tcpcrypt || true + iptables -t raw -X nixos-tcpcrypt || true + + iptables -t mangle -F nixos-tcpcrypt || true + iptables -t mangle -X nixos-tcpcrypt || true + fi + ''; + }; + in { + description = "tcpcrypt, opportunistic tcp encryption"; + wantedBy = ["multi-user.target"]; + after = ["network.target" "syslog.target"]; + + serviceConfig = { + Restart = "on-failure"; + RestartSec = 10; + + RuntimeDirectory = "tcpcryptd"; + RuntimeDirectoryMode = "0750"; + }; + + preStart = '' + echo -en "Starting tcpcryptd\n" + ${pkgs.procps}/bin/sysctl -n net.ipv4.tcp_ecn > /run/tcpcryptd/pre-tcpcrypt-ecn-state + ${pkgs.procps}/bin/sysctl -w net.ipv4.tcp_ecn=0 + + # start the firewall + ${tcpcryptd-firewall}/bin/tcpcryptd-firewall start + ''; + + # -f disables network test + script = "${pkgs.tcpcrypt}/bin/tcpcryptd -v -f -x 0x10 "; + + postStop = '' + echo -en "Stopped tcpcrypd, restoring tcp_enc state\n" + if [ -f /run/tcpcryptd/pre-tcpcrypt-ecn-state ]; then + ${pkgs.procps}/bin/sysctl -w net.ipv4.tcp_ecn=$(cat /run/tcpcryptd/pre-tcpcrypt-ecn-state) + fi + + # stop the firewall + ${tcpcryptd-firewall}/bin/tcpcryptd-firewall stop + ''; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/networking/wireless.nix b/nyx/modules/core/common/system/os/networking/wireless.nix new file mode 100644 index 0000000..2e5e66c --- /dev/null +++ b/nyx/modules/core/common/system/os/networking/wireless.nix @@ -0,0 +1,71 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (lib.lists) optionals; + inherit (lib.attrsets) optionalAttrs; + inherit (lib.meta) getExe; + + sys = config.modules.system; + + inherit (sys.networking) wireless; +in { + config = { + environment.systemPackages = optionals (wireless.backend == "iwd") pkgs.iwgtk; + networking.wireless = + { + enable = wireless.backend == "wpa_supplicant"; + + # configure iwd + iwd = { + enable = wireless.backend == "iwd"; + settings = { + #Rank.BandModifier5Ghz = 2.0; + #Scan.DisablePeriodicScan = true; + Settings.AutoConnect = true; + + General = { + AddressRandomization = "network"; + AddressRandomizationRange = "full"; + EnableNetworkConfiguration = true; + RoamRetryInterval = 15; + }; + + Network = { + EnableIPv6 = true; + RoutePriorityOffset = 300; + # NameResolvingService = "resolvconf"; + }; + }; + }; + } + // optionalAttrs wireless.allowImperative { + # Imperative Configuration + userControlled.enable = true; + allowAuxiliaryImperativeNetworks = true; # patches wpa_supplicant + + extraConfig = '' + update_config=1 + ''; + }; + + # launch indicator as a daemon on login if wireless backend + # is defined as iwd + systemd = { + # make sure we ensure the existence of wpa_supplicant config + # before we run the wpa_supplicant service + services.wpa_supplicant.preStart = '' + touch /etc/wpa_supplicant.conf + ''; + + user.services.iwgtk = mkIf (wireless.backend == "iwd") { + serviceConfig.ExecStart = "${getExe pkgs.iwgtk} -i"; + wantedBy = ["graphical-session.target"]; + partOf = ["graphical-session.target"]; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/programs/default.nix b/nyx/modules/core/common/system/os/programs/default.nix new file mode 100644 index 0000000..eafa36c --- /dev/null +++ b/nyx/modules/core/common/system/os/programs/default.nix @@ -0,0 +1,39 @@ +{ + pkgs, + lib, + ... +}: { + imports = [ + ./direnv.nix + ./nano.nix + ]; + + programs = { + bash = { + # when entering the interactive shell, set the history file to + # the config directory to avoid cluttering the $HOME directory + interactiveShellInit = '' + export HISTFILE="$XDG_STATE_HOME"/bash_history + ''; + + # initialize starship in impromptu bash sessions + # (e.g. when running a command without entering a shell) + promptInit = '' + eval "$(${lib.getExe pkgs.starship} init bash)" + ''; + }; + + # less pager + less.enable = true; + + # home-manager is quirky as ever, and wants this to be set in system config + # instead of just home-manager + zsh.enable = true; + + # run commands without installing the programs + comma.enable = true; + + # type "fuck" to fix the last command that made you go "fuck" + thefuck.enable = true; + }; +} diff --git a/nyx/modules/core/common/system/os/programs/direnv.nix b/nyx/modules/core/common/system/os/programs/direnv.nix new file mode 100644 index 0000000..93e2e26 --- /dev/null +++ b/nyx/modules/core/common/system/os/programs/direnv.nix @@ -0,0 +1,103 @@ +{ + config, + pkgs, + ... +}: { + programs.direnv = { + enable = true; + + # shut up. SHUT UP + silent = true; + + # faster, persistent implementation of use_nix and use_flake + nix-direnv = { + enable = true; + package = pkgs.nix-direnv.override { + nix = config.nix.package; + }; + }; + + # enable loading direnv in nix-shell nix shell or nix develop + loadInNixShell = true; + + direnvrcExtra = '' + : ''${XDG_CACHE_HOME:=$HOME/.cache} + declare -A direnv_layout_dirs + + # https://github.com/direnv/direnv/wiki/Customizing-cache-location#hashed-directories + direnv_layout_dir() { + echo "''${direnv_layout_dirs[$PWD]:=$( + echo -n "$XDG_CACHE_HOME"/direnv/layouts/ + echo -n "$PWD" | ${pkgs.perl}/bin/shasum | cut -d ' ' -f 1 + )}" + } + + # Usage: daemonize [ [...]] + # + # Starts the command in the background with an exclusive lock on $name. + # + # If no command is passed, it uses the name as the command. + # + # Logs are in .direnv/$name.log + # + # To kill the process, run `kill $(< .direnv/$name.pid)`. + daemonize() { + local name=$1 + shift + local pid_file=$(direnv_layout_dir)/$name.pid + local log_file=$(direnv_layout_dir)/$name.log + + if [[ $# -lt 1 ]]; then + cmd=$name + else + cmd=$1 + shift + fi + + if ! has "$cmd"; then + echo "ERROR: $cmd not found" + return 1 + fi + + mkdir -p "$(direnv_layout_dir)" + + # Open pid_file on file descriptor 200 + exec 200>"$pid_file" + + # Check that we have exclusive access + if ! flock --nonblock 200; then + echo "daemonize[$name] is already running as pid $(< "$pid_file")" + return + fi + + # Start the process in the background. This requires two forks to escape the + # control of bash. + + # First fork + ( + # Second fork + ( + echo "daemonize[$name:$BASHPID]: starting $cmd $*" >&2 + + # Record the PID for good measure + echo "$BASHPID" >&200 + + # Redirect standard file descriptors + exec 0"$log_file" + exec 2>&1 + # Used by direnv + exec 3>&- + exec 4>&- + + # Run command + exec "$cmd" "$@" + ) & + ) & + + # Release that file descriptor + exec 200>&- + } + ''; + }; +} diff --git a/nyx/modules/core/common/system/os/programs/nano.nix b/nyx/modules/core/common/system/os/programs/nano.nix new file mode 100644 index 0000000..8c80807 --- /dev/null +++ b/nyx/modules/core/common/system/os/programs/nano.nix @@ -0,0 +1,48 @@ +{pkgs, ...}: { + programs.nano = { + # enabled by default anyway, we can keep it in case my neovim config breaks + enable = true; + nanorc = '' + include ${pkgs.nanorc}/share/*.nanorc # extended syntax highlighting + + # Options + # https://github.com/davidhcefx/Modern-Nano-Keybindings + set tabsize 4 + set tabstospaces + set linenumbers + set numbercolor yellow,normal + set indicator # side-bar for indicating cur position + set smarthome # `Home` jumps to line start first + set afterends # `Ctrl+Right` move to word ends instead of word starts + set wordchars "_" # recognize '_' as part of a word + set zap # delete selected text as a whole + set historylog # remember search history + set multibuffer # read files into multibuffer instead of insert + set mouse # enable mouse support + bind M-R redo main + bind ^C copy main + bind ^X cut main + bind ^V paste main + bind ^K zap main + bind ^H chopwordleft all + bind ^Q exit all + bind ^Z suspend main + bind M-/ comment main + bind ^Space complete main + + bind M-C location main + bind ^E wherewas all + bind M-E findprevious all + bind ^R replace main + bind ^B pageup all # vim-like support + bind ^F pagedown all + bind ^G firstline all + bind M-G lastline all + + bind M-1 help all # fix ^G been used + bind Sh-M-C constantshow main # fix M-C, M-F and M-b been used + bind Sh-M-F formatter main + bind Sh-M-B linter main + ''; + }; +} diff --git a/nyx/modules/core/common/system/os/services/default.nix b/nyx/modules/core/common/system/os/services/default.nix new file mode 100644 index 0000000..c0d62ae --- /dev/null +++ b/nyx/modules/core/common/system/os/services/default.nix @@ -0,0 +1,12 @@ +{ + imports = [ + ./systemd + + ./fstrim.nix + ./fwupd.nix + ./logrotate.nix + ./lvm.nix + ./thermald.nix + ./zram.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/services/fstrim.nix b/nyx/modules/core/common/system/os/services/fstrim.nix new file mode 100644 index 0000000..746b545 --- /dev/null +++ b/nyx/modules/core/common/system/os/services/fstrim.nix @@ -0,0 +1,39 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf; +in { + # if lvm is enabled, then tell it to issue discards + # (this is good for SSDs and has almost no downsides on HDDs, so + # it's a good idea to enable it unconditionally) + environment.etc."lvm/lvm.conf".text = mkIf config.services.lvm.enable '' + devices { + issue_discards = 1 + } + ''; + + # discard blocks that are not in use by the filesystem, good for SSDs + services.fstrim = { + # we may enable this unconditionally across all systems becuase it's performance + # impact is negligible on systems without a SSD - which means it's a no-op with + # almost no downsides aside from the service firing once per week + enable = true; + + # the default value, good enough for average-load systems + interval = "weekly"; + }; + + # tweak fstim service to run only when on AC power + # and to be nice to other processes + # (this is a good idea for any service that runs periodically) + systemd.services.fstrim = { + unitConfig.ConditionACPower = true; + + serviceConfig = { + Nice = 19; + IOSchedulingClass = "idle"; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/services/fwupd.nix b/nyx/modules/core/common/system/os/services/fwupd.nix new file mode 100644 index 0000000..9d85bf1 --- /dev/null +++ b/nyx/modules/core/common/system/os/services/fwupd.nix @@ -0,0 +1,13 @@ +{config, ...}: { + # firmware updater for machine hardware + services.fwupd = { + enable = true; + daemonSettings.EspLocation = config.boot.loader.efi.efiSysMountPoint; + + # newer hardware may have their firmware in testing + # e.g. Framework devices don't have their firmware in stable yet + # TODO: make a system-level option that sets this value for hosts + # that have testing firmware + # extraRemotes = [ "lvfs-testing" ]; + }; +} diff --git a/nyx/modules/core/common/system/os/services/logrotate.nix b/nyx/modules/core/common/system/os/services/logrotate.nix new file mode 100644 index 0000000..40a0013 --- /dev/null +++ b/nyx/modules/core/common/system/os/services/logrotate.nix @@ -0,0 +1,28 @@ +{ + pkgs, + lib, + ... +}: { + services.logrotate.settings.header = { + # general + global = true; + dateext = true; + dateformat = "-%Y-%m-%d"; + nomail = true; + missingok = true; + copytruncate = true; + + # rotation frequency + priority = 1; + frequency = "weekly"; + rotate = 7; # special value, means every 7 days + minage = 7; # avoid removing logs that are less than 7 days old + + # compression + compress = true; # lets compress logs to save space + compresscmd = "${lib.getExe' pkgs.zstd "zstd"}"; + compressoptions = " -Xcompression-level 10"; + compressext = "zst"; + uncompresscmd = "${lib.getExe' pkgs.zstd "unzstd"}"; + }; +} diff --git a/nyx/modules/core/common/system/os/services/lvm.nix b/nyx/modules/core/common/system/os/services/lvm.nix new file mode 100644 index 0000000..f7df88d --- /dev/null +++ b/nyx/modules/core/common/system/os/services/lvm.nix @@ -0,0 +1,6 @@ +{lib, ...}: let + inherit (lib) mkDefault; +in { + # I don't use lvm, can be disabled + services.lvm.enable = mkDefault false; +} diff --git a/nyx/modules/core/common/system/os/services/systemd/brightnessd.nix b/nyx/modules/core/common/system/os/services/systemd/brightnessd.nix new file mode 100644 index 0000000..6cff200 --- /dev/null +++ b/nyx/modules/core/common/system/os/services/systemd/brightnessd.nix @@ -0,0 +1,32 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + inherit (config) modules; + env = modules.usrEnv; + + cfg = env.brightness; +in { + config = mkIf cfg.enable { + systemd.services."system-brightnessd" = { + description = "Automatic backlight management with systemd"; + + # TODO: maybe this needs to be a part of graphical-session.target? + # I am not very sure how wantedBy and partOf really work + wantedBy = ["default.target"]; + partOf = ["graphical-session.target"]; + + # TODO: this needs to be hardened + # not that a backlight service is a security risk, but it's a good habit + # to keep our systemd services as secure as possible + serviceConfig = { + Type = "${cfg.serviceType}"; + ExecStart = "${lib.getExe cfg.package}"; + Restart = "never"; + RestartSec = "5s"; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/services/systemd/default.nix b/nyx/modules/core/common/system/os/services/systemd/default.nix new file mode 100644 index 0000000..27e3b1d --- /dev/null +++ b/nyx/modules/core/common/system/os/services/systemd/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./brightnessd.nix + ./oomd.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/services/systemd/oomd.nix b/nyx/modules/core/common/system/os/services/systemd/oomd.nix new file mode 100644 index 0000000..ead5624 --- /dev/null +++ b/nyx/modules/core/common/system/os/services/systemd/oomd.nix @@ -0,0 +1,31 @@ +{ + config, + lib, + ... +}: { + systemd = { + # Systemd OOMd + # Fedora enables these options by default. See the 10-oomd-* files here: + # https://src.fedoraproject.org/rpms/systemd/tree/3211e4adfcca38dfe24188e28a65b1cf385ecfd6 + # by default it only kills cgroups. So either systemd services marked for killing under OOM + # or (disabled by default, enabled by us) the entire user slice. Fedora used to kill root + # and system slices, but their oomd configuration has since changed. + # TODO: maybe disable user slice by default? + oomd = { + enable = !config.systemd.enableUnifiedCgroupHierarchy; + enableRootSlice = true; + enableSystemSlice = true; + enableUserSlices = true; + extraConfig = { + "DefaultMemoryPressureDurationSec" = "20s"; + }; + }; + + # make it that nix builds are more likely killed than important services. + # 100 is the default for user slices and 500 is systemd-coredumpd@ + # this is important because as my system got huge, nix flake check started + # causing OOMs and killing my desktop environment - which I do not like + # nuke nix-daemon if it gets too memory hungry + services.nix-daemon.serviceConfig.OOMScoreAdjust = lib.mkDefault 350; + }; +} diff --git a/nyx/modules/core/common/system/os/services/thermald.nix b/nyx/modules/core/common/system/os/services/thermald.nix new file mode 100644 index 0000000..ab03163 --- /dev/null +++ b/nyx/modules/core/common/system/os/services/thermald.nix @@ -0,0 +1,4 @@ +{ + # monitor and control temparature + services.thermald.enable = true; +} diff --git a/nyx/modules/core/common/system/os/services/zram.nix b/nyx/modules/core/common/system/os/services/zram.nix new file mode 100644 index 0000000..501457f --- /dev/null +++ b/nyx/modules/core/common/system/os/services/zram.nix @@ -0,0 +1,34 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; +in { + # compress half of the ram to use as swap + # basically, get more memory per memory + zramSwap = { + enable = true; + algorithm = "zstd"; + memoryPercent = 90; # defaults to 50 + }; + + # + boot.kernel.sysctl = mkIf config.zramSwap.enable { + # zram is relatively cheap, prefer swap + # swappiness refers to the kernel's willingness prefer swap + # over memory. higher values mean that we'll utilize swap more often + # which preserves memory, but will cause performance issues as well + # as wear on the drive + "vm.swappiness" = 180; # 0-200 + # level of reclaim when memory is being fragmented + "vm.watermark_boost_factor" = 0; # 0 to disable + # aggressiveness of kswapd + # it defines the amount of memory left in a node/system before kswapd is woken up + "vm.watermark_scale_factor" = 125; # 0-300 + # zram is in memory, no need to readahead + # page-cluster refers to the number of pages up to which + # consecutive pages are read in from swap in a single attempt + "vm.page-cluster" = 0; + }; +} diff --git a/nyx/modules/core/common/system/os/theme/default.nix b/nyx/modules/core/common/system/os/theme/default.nix new file mode 100644 index 0000000..d8f7903 --- /dev/null +++ b/nyx/modules/core/common/system/os/theme/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./qt.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/theme/qt.nix b/nyx/modules/core/common/system/os/theme/qt.nix new file mode 100644 index 0000000..54879ba --- /dev/null +++ b/nyx/modules/core/common/system/os/theme/qt.nix @@ -0,0 +1,16 @@ +{ + lib, + pkgs, + ... +}: { + environment.variables = let + qmlPackages = with pkgs; [ + plasma5Packages.qqc2-desktop-style + plasma5Packages.kirigami2 + ]; + + qtVersion = pkgs.qt515.qtbase.version; + in { + "QML2_IMPORT_PATH" = "${lib.concatStringsSep ":" (builtins.map (p: "${p}/lib/qt-${qtVersion}/qml") qmlPackages)}"; + }; +} diff --git a/nyx/modules/core/common/system/os/users/default.nix b/nyx/modules/core/common/system/os/users/default.nix new file mode 100644 index 0000000..5eea5be --- /dev/null +++ b/nyx/modules/core/common/system/os/users/default.nix @@ -0,0 +1,9 @@ +{ + # we want to handle user configurations on a per-file basis + # users that are not in users/.nix don't get to be a real user + imports = [ + ./notashelf.nix + ./nix-builder.nix + ./root.nix + ]; +} diff --git a/nyx/modules/core/common/system/os/users/nix-builder.nix b/nyx/modules/core/common/system/os/users/nix-builder.nix new file mode 100644 index 0000000..c92f0c9 --- /dev/null +++ b/nyx/modules/core/common/system/os/users/nix-builder.nix @@ -0,0 +1,17 @@ +{ + users = { + groups.nix = {}; + + users.nix-builder = { + useDefaultShell = true; + isSystemUser = true; + createHome = true; + group = "nix"; + home = "/var/tmp/nix-builder"; + openssh.authorizedKeys = { + keys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK3Oglg7aVYQJzGa4JhnvDhRYx0jkLHwDT/9IyiLUNS2 notashelf@enyo"]; + # keyFiles = []; # TODO: can this be used with agenix? + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/os/users/notashelf.nix b/nyx/modules/core/common/system/os/users/notashelf.nix new file mode 100644 index 0000000..a698c0d --- /dev/null +++ b/nyx/modules/core/common/system/os/users/notashelf.nix @@ -0,0 +1,42 @@ +{ + pkgs, + config, + lib, + ... +}: let + keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIABG2T60uEoq4qTZtAZfSBPtlqWs2b4V4O+EptQ6S/ru notashelf@prometheus" + ]; +in { + boot.initrd.network.ssh.authorizedKeys = keys; + + users.users.notashelf = { + isNormalUser = true; + shell = pkgs.zsh; + initialPassword = "changeme"; + openssh.authorizedKeys.keys = keys; + extraGroups = + [ + "wheel" + "systemd-journal" + "audio" + "video" + "input" + "plugdev" + "lp" + "tss" + "power" + "nix" + ] + ++ lib.ifTheyExist config [ + "network" + "networkmanager" + "wireshark" + "mysql" + "docker" + "podman" + "git" + "libvirtd" + ]; + }; +} diff --git a/nyx/modules/core/common/system/os/users/root.nix b/nyx/modules/core/common/system/os/users/root.nix new file mode 100644 index 0000000..5a79857 --- /dev/null +++ b/nyx/modules/core/common/system/os/users/root.nix @@ -0,0 +1,3 @@ +{ + users.users.root.hashedPassword = "*"; # lock root account +} diff --git a/nyx/modules/core/common/system/security/apparmor.nix b/nyx/modules/core/common/system/security/apparmor.nix new file mode 100644 index 0000000..9428189 --- /dev/null +++ b/nyx/modules/core/common/system/security/apparmor.nix @@ -0,0 +1,71 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; +in { + config = mkIf (lib.isx86Linux pkgs) { + services.dbus.apparmor = "enabled"; + + environment.systemPackages = with pkgs; [ + apparmor-pam + apparmor-utils + apparmor-parser + apparmor-profiles + apparmor-bin-utils + apparmor-kernel-patches + libapparmor + ]; + + # apparmor configuration + security.apparmor = { + enable = true; + + # whether to enable the AppArmor cache + # in /var/cache/apparmore + enableCache = true; + + # whether to kill processes which have an AppArmor profile enabled + # but are not confined (AppArmor can only confine new processes) + killUnconfinedConfinables = true; + + # packages to be added to AppArmor’s include path + packages = [pkgs.apparmor-profiles]; + + # apparmor policies + policies = { + "default_deny" = { + enforce = false; + enable = false; + profile = '' + profile default_deny /** { } + ''; + }; + + "sudo" = { + enforce = false; + enable = false; + profile = '' + ${pkgs.sudo}/bin/sudo { + file /** rwlkUx, + } + ''; + }; + + "nix" = { + enforce = false; + enable = false; + profile = '' + ${config.nix.package}/bin/nix { + unconfined, + } + ''; + }; + }; + + # TODO: includes + }; + }; +} diff --git a/nyx/modules/core/common/system/security/auditd.nix b/nyx/modules/core/common/system/security/auditd.nix new file mode 100644 index 0000000..11c9fcf --- /dev/null +++ b/nyx/modules/core/common/system/security/auditd.nix @@ -0,0 +1,56 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + auditEnabled = sys.security.auditd.enable; +in { + config = mkIf auditEnabled { + security = { + # system audit + auditd.enable = true; + audit = { + enable = true; + backlogLimit = 8192; + failureMode = "printk"; + rules = [ + "-a exit,always -F arch=b64 -S execve" + ]; + }; + }; + + systemd = { + # a systemd timer to clean /var/log/audit.log daily + # this can probably be weekly, but daily means we get to clean it every 2-3 days instead of once a week + timers."clean-audit-log" = { + description = "Periodically clean audit log"; + wantedBy = ["timers.target"]; + timerConfig = { + OnCalendar = "daily"; + Persistent = true; + }; + }; + + # clean audit log if it's more than 524,288,000 bytes, which is roughly 500 megabytes + # it can grow MASSIVE in size if left unchecked + services."clean-audit-log" = { + script = '' + set -eu + if [[ $(stat -c "%s" /var/log/audit/audit.log) -gt 524288000 ]]; then + echo "Clearing Audit Log"; + rm -rvf /var/log/audit/audit.log; + echo "Done!" + fi + ''; + + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/security/clamav.nix b/nyx/modules/core/common/system/security/clamav.nix new file mode 100644 index 0000000..85dbba5 --- /dev/null +++ b/nyx/modules/core/common/system/security/clamav.nix @@ -0,0 +1,77 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf optionalString; + + sys = config.modules.system; +in { + config = mkIf sys.security.clamav.enable { + services.clamav = { + daemon = {enable = true;} // sys.security.clamav.daemon; + updater = {enable = true;} // sys.security.clamav.updater; + }; + + systemd = { + tmpfiles.rules = [ + "D /var/lib/clamav 755 clamav clamav" + ]; + + services = { + clamav-daemon = { + serviceConfig = { + PrivateTmp = lib.mkForce "no"; + PrivateNetwork = lib.mkForce "no"; + Restart = "always"; + }; + + unitConfig = { + # only start clamav when required database files are present + # especially useful if you are deploying headlessly and don't want a service fail instantly + ConditionPathExistsGlob = [ + "/var/lib/clamav/main.{c[vl]d,inc}" + "/var/lib/clamav/daily.{c[vl]d,inc}" + ]; + }; + }; + + clamav-init-database = { + wantedBy = ["clamav-daemon.service"]; + before = ["clamav-daemon.service"]; + serviceConfig.ExecStart = "systemctl start clamav-freshclam"; + unitConfig = { + # opposite condition of clamav-daemon: only run this service if + # database files are not present in the database directory + ConditionPathExistsGlob = [ + "!/var/lib/clamav/main.{c[vl]d,inc}" + "!/var/lib/clamav/daily.{c[vl]d,inc}" + ]; + }; + }; + + clamav-freshclam = { + wants = ["clamav-daemon.service"]; + serviceConfig = { + ExecStart = let + message = "Updating ClamAV database"; + in '' + ${pkgs.coreutils}/bin/echo -en ${message} + ''; + SuccessExitStatus = lib.mkForce [11 40 50 51 52 53 54 55 56 57 58 59 60 61 62]; + }; + }; + }; + + timers.clamav-freshclam.timerConfig = { + # the default is to run the timer hourly but we do not want our entire infra to be overloaded + # trying to run clamscan at the same time. randomize the timer to something around an hour + # so that the window is consistent, but the load is not + RandomizedDelaySec = "60m"; + FixedRandomDelay = true; + Persistent = true; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/security/default.nix b/nyx/modules/core/common/system/security/default.nix new file mode 100644 index 0000000..66ea472 --- /dev/null +++ b/nyx/modules/core/common/system/security/default.nix @@ -0,0 +1,25 @@ +{ + # This is the entry point of the security module. + # This makes our system generally more secure as opposed to having nothing + # but keep in mind that certain things (e.g. webcam) might be broken + # as a result of the configurations provided below. Exercise caution and common sense. + # DO NOT COPY BLINDLY + # Also see: + # + # + imports = [ + ./apparmor.nix # apparmor configuration and policies + ./auditd.nix # auditd + ./clamav.nix # clamav antivirus + ./fprint.nix # fingerprint driver and login support + ./kernel.nix # kernel hardening + ./memalloc.nix # memory allocator hardening + ./pam.nix # pam configuration + ./pki.nix # pki certificate bundles + ./polkit.nix # polkit configuration + ./selinux.nix # selinux support + kernel patches + ./sudo.nix # sudo rules and configuration + ./virtualization.nix # hypervisor hardening + ./usbguard.nix # usbguard + ]; +} diff --git a/nyx/modules/core/common/system/security/fprint.nix b/nyx/modules/core/common/system/security/fprint.nix new file mode 100644 index 0000000..0d46686 --- /dev/null +++ b/nyx/modules/core/common/system/security/fprint.nix @@ -0,0 +1,25 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; +in { + config = mkIf sys.security.fprint.enable { + # fingerprint login + # doesn't work because thanks drivers + services.fprintd = { + enable = false; + tod.enable = true; + tod.driver = pkgs.libfprint-2-tod1-goodix; + }; + + security.pam.services = { + login.fprintAuth = true; + swaylock.fprintAuth = true; + }; + }; +} diff --git a/nyx/modules/core/common/system/security/kernel.nix b/nyx/modules/core/common/system/security/kernel.nix new file mode 100644 index 0000000..66f409d --- /dev/null +++ b/nyx/modules/core/common/system/security/kernel.nix @@ -0,0 +1,287 @@ +{ + config, + lib, + ... +}: let + inherit (lib) optionals versionOlder mkForce; + mitigationFlags = + ( + optionals (versionOlder config.boot.kernelPackages.kernel.version "5.1.13") + [ + # we don't need restricted indirect branch speculation + "noibrs" + # we don't need no indirect branch prediction barrier either, it sounds funny + "noibpb" + # allow programs to get data from some other program when they shouldn't be able to - maybe they need it! + "nospectre_v1" + "nospectre_v2" + # why flush the L1 cache? what if we need it later. anyone being able to get it is a small consequence, I think + "l1tf=off" + # of course we want to use, not bypass, the stored data + "nospec_store_bypass_disable" + "no_stf_barrier" # We don't need no barriers between software, they could be friends + "mds=off" # Zombieload attacks are fine + ] + ) + ++ [ + "mitigations=off" # Of course we don't want no mitigations + ]; + + sys = config.modules.system; + cfg = sys.security; +in { + config = { + # failsafe for idiots, god knows there are plenty + assertions = + optionals cfg.mitigations.disable + [ + { + assertion = cfg.mitigations.acceptRisk; + message = '' + You have enabled `config.modules.system.security.mitigations`. + + To make sure you are not doing this out of sheer idiocy, you must explicitly + accept the risk of running your kernel without Spectre or Meltdown mitigations. + + Set `config.modules.system.security.mitigations.acceptRisk` to `true` only if you know what your doing! + + If you don't know what you are doing, but still insist on disabling mitigations; perish on your own accord. + ''; + } + ]; + + security = { + protectKernelImage = true; # disables hibernation + + # Breaks virtd, wireguard and iptables by disallowing them from loading + # modules during runtime. You may enable this module if you wish, but do + # make sure that the necessary modules are loaded declaratively before + # doing so. Failing to add those modules may result in an unbootable system! + lockKernelModules = false; + + # Force-enable the Page Table Isolation (PTI) Linux kernel feature + # helps mitigate Meltdown and prevent some KASLR bypasses. + forcePageTableIsolation = true; + + # User namespaces are required for sandboxing. Better than nothing imo. + allowUserNamespaces = true; + + # Disable unprivileged user namespaces, unless containers are enabled + # required by podman to run containers in rootless mode. + unprivilegedUsernsClone = config.virtualisation.containers.enable; + + allowSimultaneousMultithreading = true; + }; + + boot = { + kernel = { + sysctl = { + # The Magic SysRq key is a key combo that allows users connected to the + # system console of a Linux kernel to perform some low-level commands. + # Disable it, since we don't need it, and is a potential security concern. + "kernel.sysrq" = mkForce 0; + + # Restrict ptrace() usage to processes with a pre-defined relationship + # (e.g., parent/child) + # FIXME: this breaks game launchers, find a way to launch them with privileges (steam) + # gamescope wrapped with the capabilities *might* solve the issue + # spoiler: it didn't + # "kernel.yama.ptrace_scope" = 2; + + # Hide kptrs even for processes with CAP_SYSLOG + # also prevents printing kernel pointers + "kernel.kptr_restrict" = 2; + + # Disable bpf() JIT (to eliminate spray attacks) + "net.core.bpf_jit_enable" = false; + + # Disable ftrace debugging + "kernel.ftrace_enabled" = false; + + # Avoid kernel memory address exposures via dmesg (this value can also be set by CONFIG_SECURITY_DMESG_RESTRICT). + "kernel.dmesg_restrict" = 1; + + # Prevent creating files in potentially attacker-controlled environments such + # as world-writable directories to make data spoofing attacks more difficult + "fs.protected_fifos" = 2; + + # Prevent unintended writes to already-created files + "fs.protected_regular" = 2; + + # Disable SUID binary dump + "fs.suid_dumpable" = 0; + + # Disable late module loading + # "kernel.modules_disabled" = 1; + + # Disallow profiling at all levels without CAP_SYS_ADMIN + "kernel.perf_event_paranoid" = 3; + + # Require CAP_BPF to use bpf + "kernel.unprvileged_bpf_disabled" = 1; + + # Prevent boot console kernel log information leaks + "kernel.printk" = "3 3 3 3"; + + # Restrict loading TTY line disciplines to the CAP_SYS_MODULE capability to + # prevent unprivileged attackers from loading vulnerable line disciplines with + # the TIOCSETD ioctl + "dev.tty.ldisc_autoload" = "0"; + }; + }; + + # https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html + kernelParams = + [ + # make stack-based attacks on the kernel harder + "randomize_kstack_offset=on" + + # Disable vsyscalls as they are obsolete and have been replaced with vDSO. + # vsyscalls are also at fixed addresses in memory, making them a potential + # target for ROP attacks + # this breaks really old binaries for security + "vsyscall=none" + + # reduce most of the exposure of a heap attack to a single cache + # Disable slab merging which significantly increases the difficulty of heap + # exploitation by preventing overwriting objects from merged caches and by + # making it harder to influence slab cache layout + "slab_nomerge" + + # Disable debugfs which exposes a lot of sensitive information about the + # kernel. Some programs, such as powertop, use this interface to gather + # information about the system, but it is not necessary for the system to + # actually publish those. I can live without it. + "debugfs=off" + + # Sometimes certain kernel exploits will cause what is known as an "oops". + # This parameter will cause the kernel to panic on such oopses, thereby + # preventing those exploits + "oops=panic" + + # Only allow kernel modules that have been signed with a valid key to be + # loaded, which increases security by making it much harder to load a + # malicious kernel module + "module.sig_enforce=1" + + # The kernel lockdown LSM can eliminate many methods that user space code + # could abuse to escalate to kernel privileges and extract sensitive + # information. This LSM is necessary to implement a clear security boundary + # between user space and the kernel + # integrity: kernel features that allow userland to modify the running kernel + # are disabled + # confidentiality: kernel features that allow userland to extract confidential + # information from the kernel are also disabled + "lockdown=confidentiality" + + # enable buddy allocator free poisoning + # on: memory will befilled with a specific byte pattern + # that is unlikely to occur in normal operation. + # off (default): page poisoning will be disabled + "page_poison=on" + + # performance improvement for direct-mapped memory-side-cache utilization + # reduces the predictability of page allocations + "page_alloc.shuffle=1" + + # for debugging kernel-level slab issues + "slub_debug=FZP" + + # ignore access time (atime) updates on files + # except when they coincide with updates to the ctime or mtime + "rootflags=noatime" + + # linux security modules + "lsm=landlock,lockdown,yama,integrity,apparmor,bpf,tomoyo,selinux" + + # prevent the kernel from blanking plymouth out of the fb + "fbcon=nodefer" + + # the format that will be used for integrity audit logs + # 0 (default): basic integrity auditing messages + # 1: additional integrity auditing messages + "integrity_audit=1" + ] + ++ optionals cfg.mitigations.disable mitigationFlags; + + blacklistedKernelModules = lib.concatLists [ + # Obscure network protocols + [ + "dccp" # Datagram Congestion Control Protocol + "sctp" # Stream Control Transmission Protocol + "rds" # Reliable Datagram Sockets + "tipc" # Transparent Inter-Process Communication + "n-hdlc" # High-level Data Link Control + "netrom" # NetRom + "x25" # X.25 + "ax25" # Amatuer X.25 + "rose" # ROSE + "decnet" # DECnet + "econet" # Econet + "af_802154" # IEEE 802.15.4 + "ipx" # Internetwork Packet Exchange + "appletalk" # Appletalk + "psnap" # SubnetworkAccess Protocol + "p8022" # IEEE 802.3 + "p8023" # Novell raw IEEE 802.3 + "can" # Controller Area Network + "atm" # ATM + ] + + # Old or rare or insufficiently audited filesystems + [ + "adfs" # Active Directory Federation Services + "affs" # Amiga Fast File System + "befs" # "Be File System" + "bfs" # BFS, used by SCO UnixWare OS for the /stand slice + "cifs" # Common Internet File System + "cramfs" # compressed ROM/RAM file system + "efs" # Extent File System + "erofs" # Enhanced Read-Only File System + "exofs" # EXtended Object File System + "freevxfs" # Veritas filesystem driver + "f2fs" # Flash-Friendly File System + "vivid" # Virtual Video Test Driver (unnecessary, and a historical cause of escalation issues) + "gfs2" # Global File System 2 + "hpfs" # High Performance File System (used by OS/2) + "hfs" # Hierarchical File System (Macintosh) + "hfsplus" # " same as above, but with extended attributes + "jffs2" # Journalling Flash File System (v2) + "jfs" # Journaled File System - only useful for VMWare sessions + "ksmbd" # SMB3 Kernel Server + "minix" # minix fs - used by the minix OS + "nfsv3" # " (v3) + "nfsv4" # Network File System (v4) + "nfs" # Network File System + "nilfs2" # New Implementation of a Log-structured File System + "omfs" # Optimized MPEG Filesystem + "qnx4" # extent-based file system used by the QNX4 and QNX6 OSes + "qnx6" # " + "squashfs" # compressed read-only file system (used by live CDs) + "sysv" # implements all of Xenix FS, SystemV/386 FS and Coherent FS. + "udf" # https://docs.kernel.org/5.15/filesystems/udf.html + ] + + # Disable Thunderbolt and FireWire to prevent DMA attacks + [ + "thunderbolt" + "firewire-core" + ] + + # you might possibly want your webcam to work + # we whitelsit the module if the system wants + # webcam to work + (optionals (!sys.security.fixWebcam) [ + "uvcvideo" # this is why your webcam no worky + ]) + + # if bluetooth is enabled, whitelist the module + # necessary for bluetooth dongles to work + (optionals (!sys.bluetooth.enable) [ + "bluetooth" # let bluetooth work + "btusb" # let bluetooth dongles work + ]) + ]; + }; + }; +} diff --git a/nyx/modules/core/common/system/security/memalloc.nix b/nyx/modules/core/common/system/security/memalloc.nix new file mode 100644 index 0000000..a81dc99 --- /dev/null +++ b/nyx/modules/core/common/system/security/memalloc.nix @@ -0,0 +1,18 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkDefault optionals; +in { + # FIXME: causes a mass rebuild + # scudo memalloc is unstable + # environment.memoryAllocator.provider = mkDefault "scudo"; # "graphene-hardened"; + + # dhcpcd broken with scudo or graphene malloc + nixpkgs.overlays = optionals (config.environment.memoryAllocator.provider != "libc") [ + (_final: prev: { + dhcpcd = prev.dhcpcd.override {enablePrivSep = false;}; + }) + ]; +} diff --git a/nyx/modules/core/common/system/security/pam.nix b/nyx/modules/core/common/system/security/pam.nix new file mode 100644 index 0000000..9a5ba11 --- /dev/null +++ b/nyx/modules/core/common/system/security/pam.nix @@ -0,0 +1,30 @@ +{ + security = { + pam = { + # fix "too many files open" errors while writing a lot of data at once + # (e.g. when building a large package) + # if this, somehow, doesn't meet your requirements you may just bump the numbers up + loginLimits = [ + { + domain = "@wheel"; + item = "nofile"; + type = "soft"; + value = "524288"; + } + { + domain = "@wheel"; + item = "nofile"; + type = "hard"; + value = "1048576"; + } + ]; + + # allow screen lockers to also unlock the screen + # (e.g. swaylock, gtklock) + services = { + swaylock.text = "auth include login"; + gtklock.text = "auth include login"; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/security/pki.nix b/nyx/modules/core/common/system/security/pki.nix new file mode 100644 index 0000000..f2e94ae --- /dev/null +++ b/nyx/modules/core/common/system/security/pki.nix @@ -0,0 +1,41 @@ +{lib, ...}: { + security.pki = { + certificates = lib.mkForce []; + caCertificateBlacklist = [ + # + "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" + "Autoridad de Certificacion Firmaprofesional CIF A62634068" + + # China Financial Certification Authority + "CFCA EV ROOT" + + # Chunghwa Telecom Co., Ltd + "ePKI Root Certification Authority" + "HiPKI Root CA - G1" + + # Dhimyotis + "Certigna" + "Certigna Root CA" + + # GUANG DONG CERTIFICATE AUTHORITY + "GDCA TrustAUTH R5 ROOT" + + # Hongkong Post + "Hongkong Post Root CA 3" + + # iTrusChina Co.,Ltd. + "vTrus ECC Root CA" + "vTrus Root CA" + + # Krajowa Izba Rozliczeniowa S.A. + "SZAFIR ROOT CA2" + + # NetLock Kft. + "NetLock Arany (Class Gold) Főtanúsítvány" + + # TAIWAN-CA + "TWCA Root Certification Authority" + "TWCA Global Root CA" + ]; + }; +} diff --git a/nyx/modules/core/common/system/security/polkit.nix b/nyx/modules/core/common/system/security/polkit.nix new file mode 100644 index 0000000..5d9c7a0 --- /dev/null +++ b/nyx/modules/core/common/system/security/polkit.nix @@ -0,0 +1,20 @@ +{ + config, + lib, + ... +}: { + # have polkit log all actions + security.polkit = { + enable = true; + debug = lib.mkDefault true; + + # the below configuration depends on security.polkit.debug being set to true + # so we have it written only if debugging is enabled + extraConfig = lib.mkIf config.security.polkit.debug '' + /* Log authorization checks. */ + polkit.addRule(function(action, subject) { + polkit.log("user " + subject.user + " is attempting action " + action.id + " from PID " + subject.pid); + }); + ''; + }; +} diff --git a/nyx/modules/core/common/system/security/selinux.nix b/nyx/modules/core/common/system/security/selinux.nix new file mode 100644 index 0000000..042fe35 --- /dev/null +++ b/nyx/modules/core/common/system/security/selinux.nix @@ -0,0 +1,62 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.security.selinux; +in { + config = mkIf cfg.enable { + # build systemd with SE Linux support so it loads policy at boot and supports file labelling + systemd.package = pkgs.systemd.override {withSelinux = true;}; + + # we cannot have apparmor and security together. disable apparmor + security.apparmor.enable = lib.mkForce false; + + boot = { + # tell kernel to use SE Linux by adding necessary parameters + kernelParams = ["security=selinux" "selinux=1"]; + + # compile kernel with SE Linux support + # with additional support for other LSM modules + kernelPatches = [ + { + name = "selinux-config"; + patch = null; + extraConfig = '' + SECURITY_SELINUX y + SECURITY_SELINUX_BOOTPARAM n + SECURITY_SELINUX_DISABLE n + SECURITY_SELINUX_DEVELOP y + SECURITY_SELINUX_AVC_STATS y + SECURITY_SELINUX_CHECKREQPROT_VALUE 0 + DEFAULT_SECURITY_SELINUX n + ''; + } + ]; + }; + + environment = { + systemPackages = with pkgs; [policycoreutils]; # for load_policy, fixfiles, setfiles, setsebool, semodile, and sestatus. + + # write selinux config to /etc/selinux + etc."selinux/config".text = '' + # This file controls the state of SELinux on the system. + # SELINUX= can take one of these three values: + # enforcing - SELinux security policy is enforced. + # permissive - SELinux prints warnings instead of enforcing. + # disabled - No SELinux policy is loaded. + SELINUX=${cfg.state} + + # SELINUXTYPE= can take one of three two values: + # targeted - Targeted processes are protected, + # minimum - Modification of targeted policy. Only selected processes are protected. + # mls - Multi Level Security protection. + SELINUXTYPE=${cfg.type} + ''; + }; + }; +} diff --git a/nyx/modules/core/common/system/security/sudo.nix b/nyx/modules/core/common/system/security/sudo.nix new file mode 100644 index 0000000..107a62f --- /dev/null +++ b/nyx/modules/core/common/system/security/sudo.nix @@ -0,0 +1,79 @@ +{lib, ...}: let + inherit (lib) mkForce mkDefault; +in { + security = { + # https://github.com/NixOS/nixpkgs/pull/256491 + # no nixpkgs, you are not breaking my system because of "muh rust" delusions again + # sudo-rs is still a feature-incomplete sudo fork that can and will mess things up + # also for the love of god stop rewriting things in rust + sudo-rs.enable = mkForce false; + + # the ol' reliable + sudo = { + enable = true; + + # WARNING: wheelNeedsPassword = false means wheel group can execute commands without a password + # this is especially useful if you are using --target-host option in nixos-rebuild switch + # however it's also a massive security flaw - which is why it should be replaced with the + # extraRules you will see below + wheelNeedsPassword = mkDefault false; + + # only allow members of the wheel group to execute sudo + # by setting the executable’s permissions accordingly + execWheelOnly = mkForce true; + + # additional sudo configuration + extraConfig = '' + Defaults lecture = never # rollback results in sudo lectures after each reboot, it's somewhat useless anyway + Defaults pwfeedback # password input feedback - makes typed password visible as asterisks + Defaults env_keep += "EDITOR PATH DISPLAY" # variables that will be passed to the root account + Defaults timestamp_timeout = 300 # makes sudo ask for password less often + ''; + + # additional sudo rules + # this is a better approach for making certain commands sudo-less instead of + # allowing the wheel users to run *anything* without password + # FIXME: something is missing, causing the rebuilds to ask for sudo regardless + extraRules = [ + { + # allow wheel group to run nixos-rebuild without password + # this is a less vulnerable alternative to having wheelNeedsPassword = false + # whitelist switch-to-configuration, allows --target-host option + # to deploy to remote servers without reading password from STDIN + groups = ["wheel"]; + commands = let + currentSystem = "/run/current-system/"; + storePath = "/nix/store/"; + in [ + { + command = "${storePath}/*/bin/switch-to-configuration"; + options = ["SETENV" "NOPASSWD"]; + } + { + command = "${currentSystem}/sw/bin/nix-store"; + options = ["SETENV" "NOPASSWD"]; + } + { + command = "${currentSystem}/sw/bin/nix-env"; + options = ["SETENV" "NOPASSWD"]; + } + { + command = "${currentSystem}/sw/bin/nixos-rebuild"; + options = ["NOPASSWD"]; + } + { + # let wheel group collect garbage without password + command = "${currentSystem}/sw/bin/nix-collect-garbage"; + options = ["SETENV" "NOPASSWD"]; + } + { + # let wheel group interact with systemd without password + command = "${currentSystem}/sw/bin/systemctl"; + options = ["NOPASSWD"]; + } + ]; + } + ]; + }; + }; +} diff --git a/nyx/modules/core/common/system/security/usbguard.nix b/nyx/modules/core/common/system/security/usbguard.nix new file mode 100644 index 0000000..b001b7a --- /dev/null +++ b/nyx/modules/core/common/system/security/usbguard.nix @@ -0,0 +1,29 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + env = config.modules.usrEnv; +in { + config = mkIf sys.security.usbguard.enable { + services.usbguard = { + IPCAllowedUsers = ["root" "${env.mainUser}"]; + presentDevicePolicy = "allow"; + rules = '' + allow with-interface equals { 08:*:* } + + # Reject devices with suspicious combination of interfaces + reject with-interface all-of { 08:*:* 03:00:* } + reject with-interface all-of { 08:*:* 03:01:* } + reject with-interface all-of { 08:*:* e0:*:* } + reject with-interface all-of { 08:*:* 02:*:* } + ''; + }; + + environment.systemPackages = [pkgs.usbguard]; + }; +} diff --git a/nyx/modules/core/common/system/security/virtualization.nix b/nyx/modules/core/common/system/security/virtualization.nix new file mode 100644 index 0000000..a9c3d31 --- /dev/null +++ b/nyx/modules/core/common/system/security/virtualization.nix @@ -0,0 +1,6 @@ +{ + security.virtualisation = { + # flush the L1 data cache before entering guests + flushL1DataCache = "always"; + }; +} diff --git a/nyx/modules/core/common/system/virtualization/default.nix b/nyx/modules/core/common/system/virtualization/default.nix new file mode 100644 index 0000000..ee3f0a8 --- /dev/null +++ b/nyx/modules/core/common/system/virtualization/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./distrobox.nix + ./podman.nix + ./qemu.nix + ./waydroid.nix + ]; +} diff --git a/nyx/modules/core/common/system/virtualization/distrobox.nix b/nyx/modules/core/common/system/virtualization/distrobox.nix new file mode 100644 index 0000000..59d637c --- /dev/null +++ b/nyx/modules/core/common/system/virtualization/distrobox.nix @@ -0,0 +1,39 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system.virtualization; +in { + config = mkIf sys.distrobox.enable { + environment.systemPackages = with pkgs; [ + distrobox + ]; + + # if distrobox is enabled, update it periodically + systemd.user = { + timers."distrobox-update" = { + enable = true; + wantedBy = ["timers.target"]; + timerConfig = { + OnBootSec = "1h"; + OnUnitActiveSec = "1d"; + Unit = "distrobox-update.service"; + }; + }; + + services."distrobox-update" = { + enable = true; + script = '' + ${pkgs.distrobox}/bin/distrobox upgrade --all + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/virtualization/podman.nix b/nyx/modules/core/common/system/virtualization/podman.nix new file mode 100644 index 0000000..1d4e0ee --- /dev/null +++ b/nyx/modules/core/common/system/virtualization/podman.nix @@ -0,0 +1,39 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system.virtualization; +in { + config = mkIf (sys.docker.enable || sys.podman.enable) { + environment.systemPackages = with pkgs; [ + podman-compose + podman-desktop + ]; + + virtualisation.podman = { + enable = true; + + # make docker backwards compatible with docker interface + # certain interface elements will be different, but unless hardcoded + # does not cause problems for us + dockerCompat = true; + dockerSocket.enable = true; + + defaultNetwork.settings.dns_enabled = true; + + # enable nvidia support if any of the video drivers are nvidia + enableNvidia = builtins.any (driver: driver == "nvidia") config.services.xserver.videoDrivers; + + # prune images and containers periodically + autoPrune = { + enable = true; + flags = ["--all"]; + dates = "weekly"; + }; + }; + }; +} diff --git a/nyx/modules/core/common/system/virtualization/qemu.nix b/nyx/modules/core/common/system/virtualization/qemu.nix new file mode 100644 index 0000000..69db72f --- /dev/null +++ b/nyx/modules/core/common/system/virtualization/qemu.nix @@ -0,0 +1,62 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system.virtualization; +in { + config = mkIf sys.qemu.enable { + environment.systemPackages = with pkgs; [ + virt-manager + virt-viewer + qemu_kvm + qemu + ]; + + virtualisation = { + kvmgt.enable = true; + spiceUSBRedirection.enable = true; + + libvirtd = { + enable = true; + qemu = { + package = pkgs.qemu_kvm; + runAsRoot = false; + swtpm.enable = true; + + ovmf = { + enable = true; + packages = [pkgs.OVMFFull.fd]; + }; + + verbatimConfig = '' + namespaces = [] + + # Whether libvirt should dynamically change file ownership + dynamic_ownership = 0 + ''; + }; + + onBoot = "ignore"; + onShutdown = "shutdown"; + }; + }; + + # this allows libvirt to use pulseaudio socket + # which is useful for virt-manager + hardware.pulseaudio.extraConfig = '' + load-module module-native-protocol-unix auth-group=qemu-libvirtd socket=/tmp/pulse-socket + ''; + + # additional kernel modules that may be needed by libvirt + boot.kernelModules = [ + "vfio-pci" + ]; + + # trust bridge network interface(s) + networking.firewall.trustedInterfaces = ["virbr0" "br0"]; + }; +} diff --git a/nyx/modules/core/common/system/virtualization/waydroid.nix b/nyx/modules/core/common/system/virtualization/waydroid.nix new file mode 100644 index 0000000..8b50c6c --- /dev/null +++ b/nyx/modules/core/common/system/virtualization/waydroid.nix @@ -0,0 +1,34 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + + waydroid-ui = pkgs.writeShellScriptBin "waydroid-ui" '' + export WAYLAND_DISPLAY=wayland-0 + ${pkgs.weston}/bin/weston -Swayland-1 --width=600 --height=1000 --shell="kiosk-shell.so" & + WESTON_PID=$! + + export WAYLAND_DISPLAY=wayland-1 + ${pkgs.waydroid}/bin/waydroid show-full-ui & + + wait $WESTON_PID + waydroid session stop + ''; +in { + config = mkIf sys.virtualization.waydroid.enable { + environment.systemPackages = with pkgs; [ + waydroid + waydroid-ui + ]; + + virtualisation = { + lxd.enable = sys.waydroid.enable; # TODO: make this also acceept sys.lxd.enable + waydroid.enable = sys.waydroid.enable; + }; + }; +} diff --git a/nyx/modules/core/profiles/default.nix b/nyx/modules/core/profiles/default.nix new file mode 100644 index 0000000..d5b8ab4 --- /dev/null +++ b/nyx/modules/core/profiles/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./gaming.nix + ./workstation.nix + ]; +} diff --git a/nyx/modules/core/profiles/gaming.nix b/nyx/modules/core/profiles/gaming.nix new file mode 100644 index 0000000..fe73a31 --- /dev/null +++ b/nyx/modules/core/profiles/gaming.nix @@ -0,0 +1,12 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; +in { + config.modules.system.programs = mkIf config.modules.profiles.gaming.enable { + steam.enable = true; + gaming.enable = true; + }; +} diff --git a/nyx/modules/core/profiles/workstation.nix b/nyx/modules/core/profiles/workstation.nix new file mode 100644 index 0000000..bd190d7 --- /dev/null +++ b/nyx/modules/core/profiles/workstation.nix @@ -0,0 +1,16 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; +in { + config.modules.system.programs = mkIf config.modules.profiles.workstation.enable { + webcord.enable = true; + element.enable = true; + libreoffice.enable = true; + firefox.enable = true; + thunderbird.enable = true; + zathura.enable = true; + }; +} diff --git a/nyx/modules/core/roles/graphical/default.nix b/nyx/modules/core/roles/graphical/default.nix new file mode 100644 index 0000000..2394f45 --- /dev/null +++ b/nyx/modules/core/roles/graphical/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./system + ]; + + system.nixos.tags = ["graphical"]; +} diff --git a/nyx/modules/core/roles/graphical/system/default.nix b/nyx/modules/core/roles/graphical/system/default.nix new file mode 100644 index 0000000..3d8048c --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./security + ./services + + ./environment.nix + ]; +} diff --git a/nyx/modules/core/roles/graphical/system/environment.nix b/nyx/modules/core/roles/graphical/system/environment.nix new file mode 100644 index 0000000..e377ce5 --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/environment.nix @@ -0,0 +1,6 @@ +{ + environment.variables = { + # open links with the default browser + BROWSER = "firefox"; + }; +} diff --git a/nyx/modules/core/roles/graphical/system/security/default.nix b/nyx/modules/core/roles/graphical/system/security/default.nix new file mode 100644 index 0000000..586ca7a --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/security/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./polkit.nix + ]; +} diff --git a/nyx/modules/core/roles/graphical/system/security/polkit.nix b/nyx/modules/core/roles/graphical/system/security/polkit.nix new file mode 100644 index 0000000..521ab78 --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/security/polkit.nix @@ -0,0 +1,4 @@ +{ + # enable polkit for privilege escalation + security.polkit.enable = true; +} diff --git a/nyx/modules/core/roles/graphical/system/services/default.nix b/nyx/modules/core/roles/graphical/system/services/default.nix new file mode 100644 index 0000000..8a63516 --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/services/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./login + + ./xserver.nix + ]; +} diff --git a/nyx/modules/core/roles/graphical/system/services/login/default.nix b/nyx/modules/core/roles/graphical/system/services/login/default.nix new file mode 100644 index 0000000..0d0b11f --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/services/login/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./greetd.nix + ./logind.nix + ./pam.nix + ./session.nix + ]; +} diff --git a/nyx/modules/core/roles/graphical/system/services/login/greetd.nix b/nyx/modules/core/roles/graphical/system/services/login/greetd.nix new file mode 100644 index 0000000..6f526e6 --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/services/login/greetd.nix @@ -0,0 +1,53 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (lib.strings) concatStringsSep; + inherit (lib.meta) getExe; + + env = config.modules.usrEnv; + sys = config.modules.system; + + # make desktop session paths available to greetd + sessionData = config.services.xserver.displayManager.sessionData.desktops; + sessionPaths = concatStringsSep ":" [ + "${sessionData}/share/xsessions" + "${sessionData}/share/wayland-sessions" + ]; + + initialSession = { + user = "${sys.mainUser}"; + command = "${env.desktop}"; + }; + + defaultSession = { + user = "greeter"; + command = concatStringsSep " " [ + (getExe pkgs.greetd.tuigreet) + "--time" + "--remember" + "--remember-user-session" + "--asterisks" + "--sessions '${sessionPaths}'" + ]; + }; +in { + services.greetd = { + enable = true; + vt = 2; + restart = !sys.autoLogin; + + # + settings = { + # default session is what will be used if no session is selected + # in this case it'll be a TUI greeter + default_session = defaultSession; + + # initial session + initial_session = mkIf sys.autoLogin initialSession; + }; + }; +} diff --git a/nyx/modules/core/roles/graphical/system/services/login/logind.nix b/nyx/modules/core/roles/graphical/system/services/login/logind.nix new file mode 100644 index 0000000..71b4a68 --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/services/login/logind.nix @@ -0,0 +1,12 @@ +{ + # despite being under logind, this has nothing to do with login + # it's about power management + services.logind = { + lidSwitch = "suspend-then-hibernate"; + lidSwitchExternalPower = "lock"; + extraConfig = '' + HandlePowerKey=suspend-then-hibernate + HibernateDelaySec=3600 + ''; + }; +} diff --git a/nyx/modules/core/roles/graphical/system/services/login/pam.nix b/nyx/modules/core/roles/graphical/system/services/login/pam.nix new file mode 100644 index 0000000..7395b51 --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/services/login/pam.nix @@ -0,0 +1,25 @@ +{ + # unlock GPG keyring on login + security.pam.services = let + gnupg = { + enable = true; + noAutostart = true; + storeOnly = true; + }; + in { + login = { + enableGnomeKeyring = true; + inherit gnupg; + }; + + greetd = { + enableGnomeKeyring = true; + inherit gnupg; + }; + + tuigreet = { + enableGnomeKeyring = true; + inherit gnupg; + }; + }; +} diff --git a/nyx/modules/core/roles/graphical/system/services/login/session.nix b/nyx/modules/core/roles/graphical/system/services/login/session.nix new file mode 100644 index 0000000..68ffa74 --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/services/login/session.nix @@ -0,0 +1,27 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf; + + env = config.modules.usrEnv; +in { + # adding dessktop items to the environment is generally handled by the programs' respective + # nixos modules, however, to unify the desktop interface I prefer handling them manually + # and ignoring the nixos modules entirely. + services.xserver.displayManager = { + startx.enable = true; + session = [ + (mkIf env.desktops.i3.enable { + name = "i3wm"; + manage = "desktop"; + start = '' + ${pkgs.xorg.xinit}/bin/startx ${pkgs.i3-rounded}/bin/i3 -- vt2 & + waitPID=$! + ''; + }) + ]; + }; +} diff --git a/nyx/modules/core/roles/graphical/system/services/xserver.nix b/nyx/modules/core/roles/graphical/system/services/xserver.nix new file mode 100644 index 0000000..302eede --- /dev/null +++ b/nyx/modules/core/roles/graphical/system/services/xserver.nix @@ -0,0 +1,9 @@ +{ + config = { + services.xserver = { + enable = true; + displayManager.gdm.enable = false; + displayManager.lightdm.enable = false; + }; + }; +} diff --git a/nyx/modules/core/roles/headless/default.nix b/nyx/modules/core/roles/headless/default.nix new file mode 100644 index 0000000..69afc25 --- /dev/null +++ b/nyx/modules/core/roles/headless/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./system + ]; + + system.nixos.tags = ["headless"]; +} diff --git a/nyx/modules/core/roles/headless/system/default.nix b/nyx/modules/core/roles/headless/system/default.nix new file mode 100644 index 0000000..3bcf9f0 --- /dev/null +++ b/nyx/modules/core/roles/headless/system/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./environment.nix + ./systemd.nix + ./documentation.nix + ./fonts.nix + ./xdg.nix + ]; +} diff --git a/nyx/modules/core/roles/headless/system/documentation.nix b/nyx/modules/core/roles/headless/system/documentation.nix new file mode 100644 index 0000000..d5068a1 --- /dev/null +++ b/nyx/modules/core/roles/headless/system/documentation.nix @@ -0,0 +1,17 @@ +{lib, ...}: let + inherit (lib) mkForce mapAttrs; +in { + documentation = mapAttrs (_: mkForce) { + enable = false; + dev.enable = false; + doc.enable = false; + info.enable = false; + nixos.enable = false; + man = { + enable = false; + generateCaches = false; + man-db.enable = false; + mandoc.enable = false; + }; + }; +} diff --git a/nyx/modules/core/roles/headless/system/environment.nix b/nyx/modules/core/roles/headless/system/environment.nix new file mode 100644 index 0000000..df811a0 --- /dev/null +++ b/nyx/modules/core/roles/headless/system/environment.nix @@ -0,0 +1,45 @@ +{ + self, + config, + pkgs, + lib, + ... +}: { + environment = { + # normally we wouldn't need any Xlibs on a headless server but for whatever reason + # this affects whether or not some programs can build - such as pipewire + # noXlibs = true; + + # print the URL instead on servers + variables.BROWSER = "echo"; + + interactiveShellInit = let + exec = package: program: "${package}/bin/${program}"; + util = exec pkgs.coreutils; + uptime = exec pkgs.procps "uptime"; + grep = exec pkgs.gnugrep "grep"; + countUsers = ''${util "who"} -q | ${util "head"} -n1 | ${util "tr"} ' ' \\n | ${util "uniq"} | ${util "wc"} -l''; + countSessions = ''${util "who"} -q | ${util "head"} -n1 | ${util "wc"} -w''; + in '' + ( + + # Get the common color codes from lib + ${toString lib.common.shellColors} + + # Color accent to use in any primary text + CA=$PURPLE + CAB=$BPURPLE + + echo + echo -e " █ ''${BWHITE}Welcome back''${CO}" + echo " █" + echo -e " █ ''${BWHITE}Hostname......:''${CAB} ${config.networking.hostName}''${CO}" + echo -e " █ ''${BWHITE}OS Version....:''${CO} NixOS ''${CAB}${config.system.nixos.version}''${CO}" + echo -e " █ ''${BWHITE}Configuration.:''${CO} ''${CAB}${self.rev or "\${BRED}(✘)\${CO}\${BWHITE} Dirty"}''${CO}" + echo -e " █ ''${BWHITE}Uptime........:''${CO} $(${uptime} -p | ${util "cut"} -d ' ' -f2- | GREP_COLORS='mt=01;35' ${grep} --color=always '[0-9]*')" + echo -e " █ ''${BWHITE}SSH Logins....:''${CO} There are currently ''${CAB}$(${countUsers})''${CO} users logged in on ''${CAB}$(${countSessions})''${CO} sessions" + echo + ) + ''; + }; +} diff --git a/nyx/modules/core/roles/headless/system/fonts.nix b/nyx/modules/core/roles/headless/system/fonts.nix new file mode 100644 index 0000000..352ce39 --- /dev/null +++ b/nyx/modules/core/roles/headless/system/fonts.nix @@ -0,0 +1,5 @@ +{lib, ...}: { + # we don't need fontconfig on a server + # since there are no fonts to be configured outside the console + fonts.fontconfig.enable = lib.mkDefault false; +} diff --git a/nyx/modules/core/roles/headless/system/services.nix b/nyx/modules/core/roles/headless/system/services.nix new file mode 100644 index 0000000..67c7e67 --- /dev/null +++ b/nyx/modules/core/roles/headless/system/services.nix @@ -0,0 +1,5 @@ +{ + # a headless system shoudld not mount any removable media + # without explicit user action + services.udisks2.enable = false; +} diff --git a/nyx/modules/core/roles/headless/system/systemd.nix b/nyx/modules/core/roles/headless/system/systemd.nix new file mode 100644 index 0000000..4b1281e --- /dev/null +++ b/nyx/modules/core/roles/headless/system/systemd.nix @@ -0,0 +1,29 @@ +{ + # https://github.com/numtide/srvos/blob/main/nixos/server/default.nix + systemd = { + # given that our systems are headless, emergency mode is useless. + # we prefer the system to attempt to continue booting so + # that we can hopefully still access it remotely. + enableEmergencyMode = false; + + # For more detail, see: + # https://0pointer.de/blog/projects/watchdog.html + watchdog = { + # systemd will send a signal to the hardware watchdog at half + # the interval defined here, so every 10s. + # If the hardware watchdog does not get a signal for 20s, + # it will forcefully reboot the system. + runtimeTime = "20s"; + # Forcefully reboot if the final stage of the reboot + # hangs without progress for more than 30s. + # For more info, see: + # https://utcc.utoronto.ca/~cks/space/blog/linux/SystemdShutdownWatchdog + rebootTime = "30s"; + }; + + sleep.extraConfig = '' + AllowSuspend=no + AllowHibernation=no + ''; + }; +} diff --git a/nyx/modules/core/roles/headless/system/xdg.nix b/nyx/modules/core/roles/headless/system/xdg.nix new file mode 100644 index 0000000..490309c --- /dev/null +++ b/nyx/modules/core/roles/headless/system/xdg.nix @@ -0,0 +1,11 @@ +{lib, ...}: let + inherit (lib) mkForce mapAttrs; +in { + xdg = mapAttrs (_: mkForce) { + sounds.enable = false; + mime.enable = false; + menus.enable = false; + icons.enable = false; + autostart.enable = false; + }; +} diff --git a/nyx/modules/core/roles/iso/default.nix b/nyx/modules/core/roles/iso/default.nix new file mode 100644 index 0000000..da55b1d --- /dev/null +++ b/nyx/modules/core/roles/iso/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./image + ./system + ]; + + system.nixos.tags = ["iso-image"]; +} diff --git a/nyx/modules/core/roles/iso/image/default.nix b/nyx/modules/core/roles/iso/image/default.nix new file mode 100644 index 0000000..bd27ce2 --- /dev/null +++ b/nyx/modules/core/roles/iso/image/default.nix @@ -0,0 +1,71 @@ +{ + modulesPath, + self, + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkImageMediaOverride; +in { + imports = [ + "${modulesPath}/installer/cd-dvd/iso-image.nix" + + # make sure our installer can detect and interact with all hardware that is supported in Nixpkgs + # this loads basically every hardware related kernel module + "${modulesPath}/profiles/all-hardware.nix" + ]; + + # the ISO image must be completely immutable in the sense that we do not + # want the user to be able modify the ISO image after booting into it + # the below option will disable rebuild switches (i.e nixos-rebuild switch) + system.switch.enable = false; + + isoImage = let + # hostname will be set as a "top-level" attribute in hosts.nix, per-host. + # therefore we can use the networking.hostName to get the hostname of the live + # system without defining it explicitly in the system-agnostic ISO role module + hostname = config.networking.hostName or "nixos"; + + # if the system is built from a git repository, we want to include the git revision + # in the ISO name. if the tree is dirty, we use the term "dirty" to make it explicit + rev = self.shortRev or "dirty"; + + # the format of the iso will always be uniform: + # $hostname-$release-$rev-$arch + # therefore we can set it once to avoid repetition later on + name = "${hostname}-${config.system.nixos.release}-${rev}-${pkgs.stdenv.hostPlatform.uname.processor}"; + in { + # this will cause the resulting .iso file to be named as follows: + # $hostname-$release-$rev-$arch.iso + isoName = mkImageMediaOverride "${name}.iso"; + # this will cause the label or volume ID of the generated ISO image to be as follows: + # $hostname-$release-$rev-$arch + # volumeID is used is used by stage 1 of the boot process, so it must be distintctive + volumeID = mkImageMediaOverride "${name}"; + + # maximum compression, in exchange for build speed + squashfsCompression = "zstd -Xcompression-level 10"; # default uses gzip + + # ISO image should be an EFI-bootable volume + makeEfiBootable = true; + + # ISO image should be bootable from USB + # FIXME: the module decription is as follows: + # "Whether the ISO image should be bootable from CD as well as USB." + # is this supposed to make the ISO image bootable from *CD* instead of USB? + makeUsbBootable = true; + + # my module system already contains an option to add memtest86+ + # to the boot menu at will but in case our system is unbootable + # lets include memtest86+ in the ISO image + # so that we may test the memory of the system + # exclusively from the ISO image + contents = [ + { + source = pkgs.memtest86plus + "/memtest.bin"; + target = "boot/memtest.bin"; + } + ]; + }; +} diff --git a/nyx/modules/core/roles/iso/system/boot.nix b/nyx/modules/core/roles/iso/system/boot.nix new file mode 100644 index 0000000..884b007 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/boot.nix @@ -0,0 +1,37 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkForce; +in { + boot = { + # use the latest Linux kernel + kernelPackages = pkgs.linuxPackages_latest; + + # talk to me kernel + kernelParams = lib.mkAfter ["noquiet"]; + + # no need for systemd in the initrd stage on an installation media + # being put in to recovery mode, or having systemd in stage one is + # entirely pointless + initrd.systemd = { + enable = lib.mkImageMediaOverride false; + emergencyAccess = lib.mkImageMediaOverride true; + }; + + # Needed for https://github.com/NixOS/nixpkgs/issues/58959 + # tl;dr: ZFS is problematic and we don't want it + supportedFilesystems = mkForce [ + "btrfs" + "vfat" + "f2fs" + "xfs" + "ntfs" + "cifs" + ]; + + # disable software RAID + swraid.enable = mkForce false; + }; +} diff --git a/nyx/modules/core/roles/iso/system/default.nix b/nyx/modules/core/roles/iso/system/default.nix new file mode 100644 index 0000000..7f9fe84 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/default.nix @@ -0,0 +1,13 @@ +{ + imports = [ + ./misc + ./services + + ./boot.nix + ./environment.nix + ./hardware.nix + ./networking.nix + ./nix.nix + ./users.nix + ]; +} diff --git a/nyx/modules/core/roles/iso/system/environment.nix b/nyx/modules/core/roles/iso/system/environment.nix new file mode 100644 index 0000000..8ad9d47 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/environment.nix @@ -0,0 +1,46 @@ +{ + inputs, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkForce; +in { + environment = { + # our installer is a minimal, TUI-only environment. I don't find any + # good reason to keep X11 libs around while we will not be depending + # on any GUI frameworks. + noXlibs = true; + + # 24.04 has brought in a stub-ld that will throw a warning if you try to run a + # dynamically linked binary. This is an installer, so we probably won't try to run + # dynamically linked binaries on this system. Besides, it's annoying. + stub-ld.enable = mkForce false; + + # NixOS bundles a few packages by default + # it's not too large of a list, but I don't need it and I prefer + # my system containing only the packages I've declared. + defaultPackages = mkForce []; + + # packages I might want on an installer environment + systemPackages = with pkgs; [ + gitMinimal + curl + wget + pciutils + lshw + rsync + nixos-install-tools + ]; + + etc = { + # link a copy of our nixpkgs input as the nixpkgs channel + "nix/flake-channels/nixpkgs".source = inputs.nixpkgs; + + # fix an annoying warning + "mdadm.conf".text = '' + MAILADDR root + ''; + }; + }; +} diff --git a/nyx/modules/core/roles/iso/system/hardware.nix b/nyx/modules/core/roles/iso/system/hardware.nix new file mode 100644 index 0000000..b2a7810 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/hardware.nix @@ -0,0 +1,6 @@ +{ + # provide all hardware drivers, including proprietary ones + hardware = { + enableRedistributableFirmware = true; + }; +} diff --git a/nyx/modules/core/roles/iso/system/misc/console.nix b/nyx/modules/core/roles/iso/system/misc/console.nix new file mode 100644 index 0000000..f7624b7 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/misc/console.nix @@ -0,0 +1,10 @@ +{pkgs, ...}: { + # console locale + console = let + variant = "u24n"; + in { + # hidpi terminal font + font = "${pkgs.terminus_font}/share/consolefonts/ter-${variant}.psf.gz"; + keyMap = "trq"; + }; +} diff --git a/nyx/modules/core/roles/iso/system/misc/default.nix b/nyx/modules/core/roles/iso/system/misc/default.nix new file mode 100644 index 0000000..74176dc --- /dev/null +++ b/nyx/modules/core/roles/iso/system/misc/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./console.nix + ./sound.nix + ]; +} diff --git a/nyx/modules/core/roles/iso/system/misc/sound.nix b/nyx/modules/core/roles/iso/system/misc/sound.nix new file mode 100644 index 0000000..23dea30 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/misc/sound.nix @@ -0,0 +1,4 @@ +{ + # disable sound related programs + sound.enable = false; +} diff --git a/nyx/modules/core/roles/iso/system/networking.nix b/nyx/modules/core/roles/iso/system/networking.nix new file mode 100644 index 0000000..6deb9ba --- /dev/null +++ b/nyx/modules/core/roles/iso/system/networking.nix @@ -0,0 +1,20 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkForce; +in { + networking.networkmanager = { + enable = true; + plugins = mkForce []; + }; + + networking.wireless.enable = mkForce false; + + # Enable SSH in the boot process. + systemd.services.sshd.wantedBy = mkForce ["multi-user.target"]; + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHRDg2lu1rXKP4OfyghP17ZVL2csnyJEJcy9Km3LQm4r notashelf@enyo" + ]; +} diff --git a/nyx/modules/core/roles/iso/system/nix.nix b/nyx/modules/core/roles/iso/system/nix.nix new file mode 100644 index 0000000..7a5c112 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/nix.nix @@ -0,0 +1,12 @@ +{ + nix = { + settings = { + experimental-features = ["nix-command" "flakes" "repl-flake"]; + log-lines = 30; + warn-dirty = false; + http-connections = 50; + accept-flake-config = true; + auto-optimise-store = true; + }; + }; +} diff --git a/nyx/modules/core/roles/iso/system/security.nix b/nyx/modules/core/roles/iso/system/security.nix new file mode 100644 index 0000000..dcb208d --- /dev/null +++ b/nyx/modules/core/roles/iso/system/security.nix @@ -0,0 +1,11 @@ +{ + # attempt to fix "too many open files" + security.pam.loginLimits = [ + { + domain = "*"; + item = "nofile"; + type = "-"; + value = "65536"; + } + ]; +} diff --git a/nyx/modules/core/roles/iso/system/services/default.nix b/nyx/modules/core/roles/iso/system/services/default.nix new file mode 100644 index 0000000..4619942 --- /dev/null +++ b/nyx/modules/core/roles/iso/system/services/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./openssh.nix + ]; +} diff --git a/nyx/modules/core/roles/iso/system/services/openssh.nix b/nyx/modules/core/roles/iso/system/services/openssh.nix new file mode 100644 index 0000000..c8a09de --- /dev/null +++ b/nyx/modules/core/roles/iso/system/services/openssh.nix @@ -0,0 +1,88 @@ +{ + # Hardened SSH configuration + services.openssh = { + extraConfig = '' + AllowTcpForwarding no + HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com + PermitTunnel no + ''; + settings = { + Ciphers = [ + "aes256-gcm@openssh.com" + "aes256-ctr,aes192-ctr" + "aes128-ctr" + "aes128-gcm@openssh.com" + "chacha20-poly1305@openssh.com" + ]; + KbdInteractiveAuthentication = false; + KexAlgorithms = [ + "curve25519-sha256" + "curve25519-sha256@libssh.org" + "diffie-hellman-group16-sha512" + "diffie-hellman-group18-sha512" + "sntrup761x25519-sha512@openssh.com" + ]; + Macs = [ + "hmac-sha2-512-etm@openssh.com" + "hmac-sha2-256-etm@openssh.com" + "umac-128-etm@openssh.com" + ]; + X11Forwarding = false; + }; + }; + + # Client side SSH configuration + programs.ssh = { + ciphers = [ + "aes256-gcm@openssh.com" + "aes256-ctr,aes192-ctr" + "aes128-ctr" + "aes128-gcm@openssh.com" + "chacha20-poly1305@openssh.com" + ]; + + hostKeyAlgorithms = [ + "ssh-ed25519" + "ssh-ed25519-cert-v01@openssh.com" + "sk-ssh-ed25519@openssh.com" + "sk-ssh-ed25519-cert-v01@openssh.com" + "rsa-sha2-512" + "rsa-sha2-512-cert-v01@openssh.com" + "rsa-sha2-256" + "rsa-sha2-256-cert-v01@openssh.com" + ]; + + kexAlgorithms = [ + "curve25519-sha256" + "curve25519-sha256@libssh.org" + "diffie-hellman-group16-sha512" + "diffie-hellman-group18-sha512" + "sntrup761x25519-sha512@openssh.com" + ]; + + knownHosts = { + github-rsa = { + hostNames = ["github.com"]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="; + }; + github-ed25519 = { + hostNames = ["github.com"]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl"; + }; + gitlab-rsa = { + hostNames = ["gitlab.com"]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9"; + }; + gitlab-ed25519 = { + hostNames = ["gitlab.com"]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf"; + }; + }; + + macs = [ + "hmac-sha2-512-etm@openssh.com" + "hmac-sha2-256-etm@openssh.com" + "umac-128-etm@openssh.com" + ]; + }; +} diff --git a/nyx/modules/core/roles/iso/system/users.nix b/nyx/modules/core/roles/iso/system/users.nix new file mode 100644 index 0000000..5af1b3d --- /dev/null +++ b/nyx/modules/core/roles/iso/system/users.nix @@ -0,0 +1,11 @@ +{ + users.extraUsers.root.password = ""; + + users.users.nixos = { + uid = 1000; + password = "nixos"; + description = "default"; + isNormalUser = true; + extraGroups = ["wheel"]; + }; +} diff --git a/nyx/modules/core/roles/laptop/default.nix b/nyx/modules/core/roles/laptop/default.nix new file mode 100644 index 0000000..f8307ce --- /dev/null +++ b/nyx/modules/core/roles/laptop/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./system + ]; + + system.nixos.tags = ["laptop"]; +} diff --git a/nyx/modules/core/roles/laptop/system/default.nix b/nyx/modules/core/roles/laptop/system/default.nix new file mode 100644 index 0000000..ef21b27 --- /dev/null +++ b/nyx/modules/core/roles/laptop/system/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./power + + ./touchpad.nix + ]; +} diff --git a/nyx/modules/core/roles/laptop/system/power/default.nix b/nyx/modules/core/roles/laptop/system/power/default.nix new file mode 100644 index 0000000..e51e003 --- /dev/null +++ b/nyx/modules/core/roles/laptop/system/power/default.nix @@ -0,0 +1,75 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf mkDefault; + + dev = config.modules.device; + acceptedTypes = ["laptop" "hybrid"]; +in { + imports = [./monitor.nix]; + + config = mkIf (builtins.elem dev.type acceptedTypes) { + hardware.acpilight.enable = true; + + environment.systemPackages = with pkgs; [ + acpi + powertop + ]; + + services = { + # handle ACPI events + acpid.enable = true; + + # allows changing system behavior based upon user-selected power profiles + power-profiles-daemon.enable = true; + + # temperature target on battery + undervolt = { + tempBat = 65; # deg C + package = pkgs.undervolt; + }; + + # superior power management + auto-cpufreq = { + enable = true; + settings = let + MHz = x: x * 1000; + in { + battery = { + governor = "powersave"; + scaling_min_freq = mkDefault (MHz 1200); + scaling_max_freq = mkDefault (MHz 1800); + turbo = "never"; + }; + + charger = { + governor = "performance"; + scaling_min_freq = mkDefault (MHz 1800); + scaling_max_freq = mkDefault (MHz 3800); + turbo = "auto"; + }; + }; + }; + + # DBus service that provides power management support to applications. + upower = { + enable = true; + percentageLow = 15; + percentageCritical = 5; + percentageAction = 3; + criticalPowerAction = "Hibernate"; + }; + }; + + boot = { + kernelModules = ["acpi_call"]; + extraModulePackages = with config.boot.kernelPackages; [ + acpi_call + cpupower + ]; + }; + }; +} diff --git a/nyx/modules/core/roles/laptop/system/power/monitor.nix b/nyx/modules/core/roles/laptop/system/power/monitor.nix new file mode 100644 index 0000000..b1bedae --- /dev/null +++ b/nyx/modules/core/roles/laptop/system/power/monitor.nix @@ -0,0 +1,40 @@ +{ + inputs', + pkgs, + lib, + ... +}: let + inherit (builtins) readFile; + inherit (lib.modules) mkForce; + inherit (lib.strings) makeBinPath; + + dependencies = with pkgs; + [ + coreutils + power-profiles-daemon + inotify-tools + jaq + ] + ++ [ + inputs'.hyprland.packages.hyprland + ]; +in { + config = { + # Power state monitor. Switches Power profiles based on charging state. + # Plugged in - performance + # Unplugged - power-saver + systemd.services."power-monitor" = { + description = "Power Monitoring Service"; + environment.PATH = mkForce "/run/wrappers/bin:${makeBinPath dependencies}"; + script = readFile ./scripts/power_monitor.sh; + + serviceConfig = { + Type = "simple"; + Restart = "on-failure"; + }; + + wants = ["power-profiles-daemon.service"]; + wantedBy = ["default.target"]; + }; + }; +} diff --git a/nyx/modules/core/roles/laptop/system/power/scripts/power_monitor.sh b/nyx/modules/core/roles/laptop/system/power/scripts/power_monitor.sh new file mode 100644 index 0000000..d47e1db --- /dev/null +++ b/nyx/modules/core/roles/laptop/system/power/scripts/power_monitor.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +BAT=$(echo /sys/class/power_supply/BAT*) +BAT_STATUS="$BAT/status" +BAT_CAP="$BAT/capacity" +AC_PROFILE="performance" +BAT_PROFILE="balanced" + +# low and critical battery levels +LOW_BAT_PERCENT=25 +CRIT_BAT_PERCENT=5 + +# how long to wait before suspending +SUSPEND_WAIT=60s + +# define the wait & suspend function +wait_and_suspend() { + sleep "$SUSPEND_WAIT" + + # check if we're still discharging + if [[ $(cat "$BAT_STATUS") == "Discharging" ]]; then + systemctl suspend + fi +} + +# wait a while if needed +[[ -z $STARTUP_WAIT ]] || sleep "$STARTUP_WAIT" + +# start the monitor loop +prev=0 +while true; do + # read the current state + if [[ $(cat "$BAT_STATUS") == "Discharging" ]]; then + profile=$BAT_PROFILE + else + profile=$AC_PROFILE + fi + + # set the new profile + if [[ $prev != "$profile" ]]; then + echo -en "Setting power profile to ${profile}\n" + powerprofilesctl set $profile + fi + prev=$profile + + if [[ $(cat "$BAT_CAP") -le $LOW_BAT_PERCENT && $BAT_STATUS == "Discharging" ]]; then + notify-send --urgency=critical --hint=int:transient:1 --icon=battery_empty "Battery Low" \ + "Consider plugging in." + + for i in $(hyprctl instances -j | jaq ".[].instance" -r); do + hyprctl -i "$i" --batch 'keyword decoration:blur:enabled false; keyword animations:enabled false' + done + fi + + if [[ $(cat "$BAT_CAP") -le $CRIT_BAT_PERCENT && $BAT_STATUS == "Discharging" ]]; then + notify-send --urgency=critical --hint=int:transient:1 --icon=battery_empty "Battery Critically Low" \ + "Computer will suspend in 60 seconds." + wait_and_suspend & + fi + + if [[ $(cat "$BAT_CAP") -gt $LOW_BAT_PERCENT && $BAT_STATUS == "Charging" ]]; then + for i in $(hyprctl instances -j | jaq ".[].instance" -r); do + hyprctl -i "$i" --batch 'keyword decoration:blur:enabled true; keyword animations:enabled true' + done + fi + + # wait for the next power change event + inotifywait -qq "$BAT_STATUS" "$BAT_CAP" +done diff --git a/nyx/modules/core/roles/laptop/system/power/tlp.nix b/nyx/modules/core/roles/laptop/system/power/tlp.nix new file mode 100644 index 0000000..1fb8649 --- /dev/null +++ b/nyx/modules/core/roles/laptop/system/power/tlp.nix @@ -0,0 +1,133 @@ +let + MHz = x: x * 1000; +in { + config = { + services = { + tlp = { + enable = false; + settings = { + TLP_ENABLE = 1; + TLP_DEFAULT_MODE = "BAT"; + + # Timeout (in seconds) for the audio power saving mode (supports Intel HDA, AC97). + # A value of 1 is recommended for Linux desktop environments with PulseAudio, + # systems without PulseAudio may require 10. The value 0 disables power save. + SOUND_POWER_SAVE_ON_AC = 10; + SOUND_POWER_SAVE_ON_BAT = 10; + + # SOUND_POWER_SAVE_CONTROLLER = "Y"; + + START_CHARGE_THRESH_BAT0 = 80; + STOP_CHARGE_THRESH_BAT0 = 95; + + RESTORE_THRESHOLDS_ON_BAT = 1; + + # battery care drivers + # NATACPI_ENABLE = 1; + # TPACPI_ENABLE = 1; + # TPSMAPI_ENABLE = 1; + + # DISK_DEVICES = "nvme0n1 mmcblk0"; + + # DISK_APM_LEVEL_ON_AC = "254 254"; + # DISK_APM_LEVEL_ON_BAT = "128 128"; + + # DISK_IDLE_SECS_ON_AC=0; + DISK_IDLE_SECS_ON_BAT = 5; + + # Timeout (in seconds) for writing unsaved data in file system buffers to disk. + # MAX_LOST_WORK_SECS_ON_AC = 15; + # MAX_LOST_WORK_SECS_ON_BAT = 60; + + # RADEON_DPM_PERF_LEVEL_ON_AC = "auto"; + RADEON_DPM_PERF_LEVEL_ON_BAT = "low"; + + # RADEON_DPM_STATE_ON_AC = "performance"; + # RADEON_DPM_STATE_ON_BAT = "battery"; + + RADEON_POWER_PROFILE_ON_AC = "high"; + RADEON_POWER_PROFILE_ON_BAT = "low"; + + # NMI_WATCHDOG = 0; + + # Sets Wi-Fi power saving mode. Adapter support depends on kernel and driver. + # WIFI_PWR_ON_AC = "off"; + # WIFI_PWR_ON_BAT = "on"; + + # WOL_DISABLE = "Y"; + + # Select the platform profile to control system operating characteristics + # around power/performance levels, thermal and fan speed. + # PLATFORM_PROFILE_ON_AC = "performance"; + # PLATFORM_PROFILE_ON_BAT = "low-power"; + + # + CPU_SCALING_GOVERNOR_ON_AC = "schedutil"; + CPU_SCALING_GOVERNOR_ON_BAT = "powersave"; + + CPU_SCALING_MIN_FREQ_ON_AC = MHz 1400; + CPU_SCALING_MAX_FREQ_ON_AC = MHz 1700; + CPU_SCALING_MIN_FREQ_ON_BAT = MHz 1400; + CPU_SCALING_MAX_FREQ_ON_BAT = MHz 1600; + + CPU_BOOST_ON_AC = 1; + CPU_BOOST_ON_BAT = 0; + + # SCHED_POWERSAVE_ON_AC = 0; + # SCHED_POWERSAVE_ON_BAT = 1; + + # Restores radio device state (builtin Bluetooth, Wi-Fi, WWAN) from previous shutdown on boot. + # RESTORE_DEVICE_STATE_ON_STARTUP = 0; + + DEVICES_TO_DISABLE_ON_STARTUP = "bluetooth wwan"; + DEVICES_TO_ENABLE_ON_STARTUP = "wifi"; + + # DEVICES_TO_DISABLE_ON_SHUTDOWN = "bluetooth wifi wwan"; + # DEVICES_TO_ENABLE_ON_SHUTDOWN = "bluetooth wifi wwan"; + + # has precedence + DEVICES_TO_ENABLE_ON_AC = ""; + DEVICES_TO_DISABLE_ON_BAT = ""; + + DEVICES_TO_DISABLE_ON_BAT_NOT_IN_USE = "bluetooth wwan"; + + DEVICES_TO_DISABLE_ON_LAN_CONNECT = "wwan"; + DEVICES_TO_DISABLE_ON_WIFI_CONNECT = ""; + DEVICES_TO_DISABLE_ON_WWAN_CONNECT = "wifi"; + + DEVICES_TO_ENABLE_ON_LAN_DISCONNECT = "wifi"; + DEVICES_TO_ENABLE_ON_WIFI_DISCONNECT = ""; + DEVICES_TO_ENABLE_ON_WWAN_DISCONNECT = ""; + + DEVICES_TO_ENABLE_ON_DOCK = "wifi bluetooth"; + # DEVICES_TO_DISABLE_ON_DOCK = ""; + + DEVICES_TO_ENABLE_ON_UNDOCK = ""; + DEVICES_TO_DISABLE_ON_UNDOCK = "bluetooth"; + + # RUNTIME_PM_ON_AC = "on"; + # RUNTIME_PM_ON_BAT = "auto"; + + # RUNTIME_PM_DENYLIST = "11:22.3 44:55.6"; + RUNTIME_PM_DRIVER_DENYLIST = "mei_me nouveau radeon psmouse"; + + # RUNTIME_PM_ENABLE="11:22.3"; + # RUNTIME_PM_DISABLE="44:55.6"; + + # PCIE_ASPM_ON_AC = "default"; + PCIE_ASPM_ON_BAT = "powersupersave"; + + # USB_AUTOSUSPEND = 1; + # USB_DENYLIST = "1111:2222 3333:4444"; + # USB_EXCLUDE_AUDIO = 1; + # USB_EXCLUDE_BTUSB = 1; + # USB_EXCLUDE_PHONE = 1; + # USB_EXCLUDE_PRINTER = 1; + # USB_EXCLUDE_WWAN = 0; + # USB_ALLOWLIST="5555:6666 7777:8888"; + # USB_AUTOSUSPEND_DISABLE_ON_SHUTDOWN = 0; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/laptop/system/touchpad.nix b/nyx/modules/core/roles/laptop/system/touchpad.nix new file mode 100644 index 0000000..a0d73ab --- /dev/null +++ b/nyx/modules/core/roles/laptop/system/touchpad.nix @@ -0,0 +1,27 @@ +{ + config = { + services = { + # Input settings for libinput + xserver.libinput = { + # enable libinput + enable = true; + + # disable mouse acceleration + mouse = { + accelProfile = "flat"; + accelSpeed = "0"; + middleEmulation = false; + }; + + # touchpad settings + touchpad = { + naturalScrolling = true; + tapping = true; + clickMethod = "clickfinger"; + horizontalScrolling = false; + disableWhileTyping = true; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/microvm/default.nix b/nyx/modules/core/roles/microvm/default.nix new file mode 100644 index 0000000..5de8b3c --- /dev/null +++ b/nyx/modules/core/roles/microvm/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./system + ]; + + system.nixos.tags = ["microvm"]; +} diff --git a/nyx/modules/core/roles/microvm/system/default.nix b/nyx/modules/core/roles/microvm/system/default.nix new file mode 100644 index 0000000..f79fc20 --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./nix + ./os + ./securiy + ]; +} diff --git a/nyx/modules/core/roles/microvm/system/nix/default.nix b/nyx/modules/core/roles/microvm/system/nix/default.nix new file mode 100644 index 0000000..849d917 --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/nix/default.nix @@ -0,0 +1,12 @@ +{pkgs, ...}: { + nix = { + settings.trusted-users = ["admin"]; + package = pkgs.nixUnstable; + keep-outputs = true; + keep-derivations = true; + extra-experimental-features = [ + "nix-command" + "flakes" + ]; + }; +} diff --git a/nyx/modules/core/roles/microvm/system/os/default.nix b/nyx/modules/core/roles/microvm/system/os/default.nix new file mode 100644 index 0000000..c48b7e8 --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./programs + ./users + + ./environment.nix + ./networking.nix + ]; +} diff --git a/nyx/modules/core/roles/microvm/system/os/environment.nix b/nyx/modules/core/roles/microvm/system/os/environment.nix new file mode 100644 index 0000000..4cf449d --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/environment.nix @@ -0,0 +1,31 @@ +{pkgs, ...}: { + time.timeZone = "UTC"; + i18n.defaultLocale = "en_US.UTF-8"; + + console = { + font = "ter-v32n"; + packages = [pkgs.terminus-font]; + }; + + environment = { + shells = with pkgs; [bash zsh]; + systemPackages = with pkgs; [ + vim + git + killall + bind.dnsutils + tcpdump + nmap + usbutils + wget + tmux + direnv + nix-direnv + sops + rage + ssh-to-age + pwgen + w3m + ]; + }; +} diff --git a/nyx/modules/core/roles/microvm/system/os/networking.nix b/nyx/modules/core/roles/microvm/system/os/networking.nix new file mode 100644 index 0000000..f287e5d --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/networking.nix @@ -0,0 +1,17 @@ +{lib, ...}: { + systemd.network.enable = true; + + # Enable the OpenSSH daemon. + services.openssh.enable = true; + + networking = { + useDHCP = false; + networkmanager.enable = false; + firewall = { + enable = true; + allowPing = lib.mkForce false; + allowedTCPPorts = lib.mkForce []; + allowedUDPPorts = lib.mkForce []; + }; + }; +} diff --git a/nyx/modules/core/roles/microvm/system/os/programs/default.nix b/nyx/modules/core/roles/microvm/system/os/programs/default.nix new file mode 100644 index 0000000..1ef960b --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/programs/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./git.nix + ./neovim.nix + ./tmux.nix + ./zsh.nix + ]; +} diff --git a/nyx/modules/core/roles/microvm/system/os/programs/git.nix b/nyx/modules/core/roles/microvm/system/os/programs/git.nix new file mode 100644 index 0000000..c5ba03b --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/programs/git.nix @@ -0,0 +1 @@ +{programs.git.enable = true;} diff --git a/nyx/modules/core/roles/microvm/system/os/programs/neovim.nix b/nyx/modules/core/roles/microvm/system/os/programs/neovim.nix new file mode 100644 index 0000000..b68c77e --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/programs/neovim.nix @@ -0,0 +1,23 @@ +{ + programs.neovim = { + enable = true; + viAlias = true; + vimAlias = true; + + configure.customRC = '' + syntax enable + + set noexpandtab + set shiftwidth=2 + set tabstop=2 + + set cindent + set smartindent + set autoindent + set foldmethod=syntax + nmap zA + nmap zR + nmap zM + ''; + }; +} diff --git a/nyx/modules/core/roles/microvm/system/os/programs/tmux.nix b/nyx/modules/core/roles/microvm/system/os/programs/tmux.nix new file mode 100644 index 0000000..d51d31e --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/programs/tmux.nix @@ -0,0 +1,20 @@ +{ + programs.tmux = { + enable = true; + baseIndex = 1; + clock24 = true; + historyLimit = 10000; + terminal = "tmux-256color"; + extraConfig = '' + unbind C-b + set-option -g prefix C-a + bind-key C-a last-window + set-option -g set-titles on + set-option -g set-titles-string '#H:#S.#I.#P #W #T' + setw -g monitor-activity on + set-option -g status-justify left + set-option -g status-bg yellow + set-option -g status-fg black + ''; + }; +} diff --git a/nyx/modules/core/roles/microvm/system/os/programs/zsh.nix b/nyx/modules/core/roles/microvm/system/os/programs/zsh.nix new file mode 100644 index 0000000..320a91e --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/programs/zsh.nix @@ -0,0 +1,11 @@ +{ + environment.pathsToLink = ["/share/zsh"]; + programs.zsh = { + enable = true; + enableCompletion = true; + autosuggestions = { + enable = true; + async = true; + }; + }; +} diff --git a/nyx/modules/core/roles/microvm/system/os/users/admin.nix b/nyx/modules/core/roles/microvm/system/os/users/admin.nix new file mode 100644 index 0000000..67e926c --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/users/admin.nix @@ -0,0 +1,7 @@ +{ + users.users.admin = { + isNormalUser = true; + extraGroups = ["wheel"]; + openssh.authorizedKeys.keys = []; + }; +} diff --git a/nyx/modules/core/roles/microvm/system/os/users/default.nix b/nyx/modules/core/roles/microvm/system/os/users/default.nix new file mode 100644 index 0000000..f6abeb1 --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/os/users/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./admin.nix + ]; +} diff --git a/nyx/modules/core/roles/microvm/system/security/default.nix b/nyx/modules/core/roles/microvm/system/security/default.nix new file mode 100644 index 0000000..05bd4ce --- /dev/null +++ b/nyx/modules/core/roles/microvm/system/security/default.nix @@ -0,0 +1,13 @@ +{ + security.sudo.extraRules = [ + { + users = ["admin"]; + commands = [ + { + command = "ALL"; + options = ["SETENV" "NOPASSWD"]; + } + ]; + } + ]; +} diff --git a/nyx/modules/core/roles/server/default.nix b/nyx/modules/core/roles/server/default.nix new file mode 100644 index 0000000..bcde5ab --- /dev/null +++ b/nyx/modules/core/roles/server/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./system + ]; + + system.nixos.tags = ["server"]; +} diff --git a/nyx/modules/core/roles/server/system/default.nix b/nyx/modules/core/roles/server/system/default.nix new file mode 100644 index 0000000..f35bfde --- /dev/null +++ b/nyx/modules/core/roles/server/system/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./services + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/bincache/atticd.nix b/nyx/modules/core/roles/server/system/services/bincache/atticd.nix new file mode 100644 index 0000000..e18cb4b --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/bincache/atticd.nix @@ -0,0 +1,89 @@ +{ + inputs, + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services.bincache.atticd; + + domain = "cache" + config.networking.domain; + inherit (cfg.settings) host port; +in { + imports = [inputs.atticd.nixosModules.atticd]; + config = mkIf cfg.enable { + environment.systemPackages = [pkgs.attic-client]; + + networking.firewall.allowedTCPPorts = [port]; + + users = { + groups.atticd = {}; + users."atticd" = { + isSystemUser = true; + group = "atticd"; + }; + }; + + systemd.services.atticd = { + serviceConfig.DynamicUser = lib.mkForce false; + }; + + services = { + atticd = { + enable = true; + credentialsFile = config.age.secrets.attic-env.path; + user = "atticd"; + group = "atticd"; + + settings = { + listen = "${host}:${toString port}"; # this listens ONLY locally + database.url = "postgresql:///atticd?host=/run/postgresql"; + + allowed-hosts = ["${domain}"]; + api-endpoint = "https://${domain}/"; + require-proof-of-possession = false; + + /* + storage = { + type = "s3"; + region = "helios"; + bucket = "attic-cache"; + endpoint = "https://s3.notashelf.dev"; + }; + */ + + chunking = let + KB = x: x * 1024; + in { + nar-size-threshold = KB 64; + min-size = KB 16; + avg-size = KB 64; + max-size = KB 256; + }; + + garbage-collection = { + interval = "24 hours"; + default-retention-period = "6 weeks"; + }; + }; + }; + + nginx.virtualHosts."${domain}" = { + extraConfig = '' + client_max_body_size 0; + + proxy_read_timeout 300s; + proxy_send_timeout 300s; + ''; + + locations."/" = { + recommendedProxySettings = true; + proxyPass = "http://${host}:${toString port}"; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/bincache/default.nix b/nyx/modules/core/roles/server/system/services/bincache/default.nix new file mode 100644 index 0000000..9e3df2f --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/bincache/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./atticd.nix + ./harmonia.nix + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/bincache/harmonia.nix b/nyx/modules/core/roles/server/system/services/bincache/harmonia.nix new file mode 100644 index 0000000..9c0b70d --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/bincache/harmonia.nix @@ -0,0 +1,60 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services.bincache.harmonia; + + inherit (cfg.settings) port host; +in { + config = mkIf cfg.enable { + users = { + groups.harmonia = {}; + users.harmonia = { + isSystemUser = true; + createHome = true; + group = "harmonia"; + home = "/srv/storage/harmonia"; + }; + }; + + services = { + harmonia = { + enable = true; + # NOTE: generated via + # $ nix-store --generate-binary-cache-key cache.domain.tld-1 /var/lib/secrets/harmonia.secret /var/lib/secrets/harmonia.pub + signKeyPath = config.age.secrets.harmonia-privateKey.path; + settings = { + # default ip:hostname to bind to + bind = "${host}:${toString port}"; + }; + }; + }; + + nix.settings.allowed-users = ["harmonia"]; + + services.nginx = { + virtualHosts."cache.notashelf.dev" = + { + locations."/".extraConfig = '' + proxy_pass http://127.0.0.1:${toString port}; + proxy_set_header Host $host; + proxy_redirect http:// https://; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + zstd on; + zstd_types application/x-nix-archive; + ''; + + quic = true; + } + // lib.sslTemplate; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/databases/default.nix b/nyx/modules/core/roles/server/system/services/databases/default.nix new file mode 100644 index 0000000..8b9fcc2 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/databases/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./mongodb.nix + ./postgresql.nix + ./mysql.nix + ./redis.nix + ./garage.nix + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/databases/garage.nix b/nyx/modules/core/roles/server/system/services/databases/garage.nix new file mode 100644 index 0000000..b0f7484 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/databases/garage.nix @@ -0,0 +1,118 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.database.garage.enable { + networking.firewall.allowedTCPPorts = [3900 3901 3903]; + + environment.systemPackages = [ + pkgs.garage + ]; + + systemd = let + sc = config.systemd.services.garage.serviceConfig; + gc = config.services.garage.settings; + in { + tmpfiles.rules = [ + "d /srv/storage/garage 0755 ${sc.User} ${sc.Group}" + "d '${gc.data_dir}' 0700 ${sc.User} ${sc.Group} - -" + "d '${gc.metadata_dir}' 0700 ${sc.User} ${sc.Group} - -" + ]; + + services.garage = { + # this lets custom data directory work by having a real user own the service process + # the user and its group need to be created in the users section + serviceConfig = { + User = "garage"; + Group = "garage"; + ReadWritePaths = [gc.data_dir gc.metadata_dir]; + RequiresMountsFor = [gc.data_dir]; + DynamicUser = false; + PrivateTmp = true; + ProtectSystem = true; + }; + + environment = { + RUST_LOG = "debug"; + }; + }; + }; + + users = { + groups.garage = {}; + + users.garage = { + isSystemUser = true; + createHome = false; + group = "garage"; + }; + }; + + services = { + garage = { + enable = true; + package = pkgs.garage; + + environmentFile = config.age.secrets.garage-env.path; + + settings = { + metadata_dir = "/srv/storage/garage/meta"; + data_dir = "/srv/storage/garage/data"; + metadata_fsync = false; # synchronous mode for the database engine + + db_engine = "lmdb"; + replication_mode = "none"; + compression_level = -1; + + # For inter-node comms + rpc_bind_addr = "[::]:3901"; + rpc_secret_file = config.age.secrets.garage-env.path; + # rpc_public_addr = "127.0.0.1:3901"; + + # Standard S3 api endpoint + s3_api = { + s3_region = "helios"; + api_bind_addr = "[::]:3900"; + }; + + # Static file serve endpoint + /* + s3_web = { + bind_addr = "[::1]:3902"; + root_domain = "s3.notashelf.dev"; + index = "index.html"; + }; + + "k2v_api" = { + "api_bind_addr" = "[::1]:3904"; + }; + */ + + # Admin api endpoint + admin = { + api_bind_addr = "[::]:3903"; + }; + }; + }; + + nginx.virtualHosts."s3.notashelf.dev" = + { + locations."/".proxyPass = "http://127.0.0.1:3900"; + extraConfig = '' + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + # Disable buffering to a temporary file. + proxy_max_temp_file_size 0; + ''; + } + // lib.sslTemplate; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/databases/mongodb.nix b/nyx/modules/core/roles/server/system/services/databases/mongodb.nix new file mode 100644 index 0000000..55ed09d --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/databases/mongodb.nix @@ -0,0 +1,24 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.database.mongodb.enable { + services.mongodb = { + enable = true; + package = pkgs.mongodb; + enableAuth = true; + initialRootPassword = config.age.secrets.mongodb-secret.path; + #bind_ip = "0.0.0.0"; + extraConfig = '' + operationProfiling.mode: all + ''; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/databases/mysql.nix b/nyx/modules/core/roles/server/system/services/databases/mysql.nix new file mode 100644 index 0000000..a78cb04 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/databases/mysql.nix @@ -0,0 +1,29 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.database.mysql.enable { + services.mysql = { + enable = true; + package = pkgs.mariadb; + + # databases and users + ensureDatabases = ["mkm"]; + ensureUsers = [ + { + name = "mkm"; + ensurePermissions = { + "mkm.*" = "ALL PRIVILEGES"; + }; + } + ]; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/databases/postgresql.nix b/nyx/modules/core/roles/server/system/services/databases/postgresql.nix new file mode 100644 index 0000000..d2a43d1 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/databases/postgresql.nix @@ -0,0 +1,143 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.database.postgresql.enable { + services.postgresql = { + enable = true; + package = pkgs.postgresql_15; + dataDir = "/srv/storage/postgresql/${config.services.postgresql.package.psqlSchema}"; + + ensureDatabases = [ + "nextcloud" + "forgejo" + "grafana" + "vaultwarden" + "roundcube" + "headscale" + "atticd" + ]; + + ensureUsers = [ + { + name = "postgres"; + ensureClauses = { + superuser = true; + login = true; # not implied by superuser + createrole = true; + createdb = true; + replication = true; + }; + } + { + name = "forgejo"; + ensureDBOwnership = true; + } + { + name = "grafana"; + ensureDBOwnership = true; + } + { + name = "vaultwarden"; + ensureDBOwnership = true; + } + { + name = "nextcloud"; + ensureDBOwnership = true; + } + { + name = "roundcube"; + ensureDBOwnership = true; + } + { + name = "headscale"; + ensureDBOwnership = true; + } + { + name = "atticd"; + ensureDBOwnership = true; + } + ]; + + checkConfig = true; + enableTCPIP = false; + + # http://pgconfigurator.cybertec.at/; + # https://git.darmstadt.ccc.de/maralorn/nixos-config/-/blob/master/nixos/roles/matrix-synapse/postgres-tuning.nix + settings = { + # Connectivity; + max_connections = 100; + superuser_reserved_connections = 3; + + # Memory Settings; + shared_buffers = "1024 MB"; + work_mem = "32 MB"; + maintenance_work_mem = "320 MB"; + huge_pages = "off"; + effective_cache_size = "2 GB"; + effective_io_concurrency = 100; # concurrent IO only really activated if OS supports posix_fadvise function; + random_page_cost = 1.25; # speed of random disk access relative to sequential access (1.0); + # Monitoring; + shared_preload_libraries = "pg_stat_statements,auto_explain"; # per statement resource usage stats & log explain statements for slow queries + track_io_timing = "on"; # measure exact block IO times; + track_functions = "pl"; # track execution times of pl-language procedures if any; + # Replication; + wal_level = "replica"; # consider using at least "replica"; + max_wal_senders = 0; + synchronous_commit = "on"; + + # Checkpointing: ; + checkpoint_timeout = "15 min"; + checkpoint_completion_target = 0.9; + max_wal_size = "1024 MB"; + min_wal_size = "512 MB"; + + # WAL writing; + wal_compression = "on"; + wal_buffers = -1; # auto-tuned by Postgres till maximum of segment size (16MB by default); + wal_writer_delay = "200ms"; + wal_writer_flush_after = "1MB"; + + # Background writer; + bgwriter_delay = "200ms"; + bgwriter_lru_maxpages = 100; + bgwriter_lru_multiplier = 2.0; + bgwriter_flush_after = 0; + + # Parallel queries: ; + max_worker_processes = 6; + max_parallel_workers_per_gather = 3; + max_parallel_maintenance_workers = 3; + max_parallel_workers = 6; + parallel_leader_participation = "on"; + + # Advanced features ; + enable_partitionwise_join = "on"; + enable_partitionwise_aggregate = "on"; + jit = "on"; + + jit_above_cost = 100000; + jit_inline_above_cost = 150000; + jit_optimize_above_cost = 500000; + + # log slow queries + log_min_duration_statement = 100; + "auto_explain.log_min_duration" = 100; + + # logging configuration + log_connections = true; + log_statement = "all"; + logging_collector = true; + log_disconnections = true; + log_destination = lib.mkForce "syslog"; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/databases/redis.nix b/nyx/modules/core/roles/server/system/services/databases/redis.nix new file mode 100644 index 0000000..66d8460 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/databases/redis.nix @@ -0,0 +1,49 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.database.redis.enable { + services.redis = { + vmOverCommit = true; + servers = mkIf cfg.nextcloud.enable { + nextcloud = { + enable = true; + user = "nextcloud"; + port = 0; + }; + + searxng = mkIf cfg.searxng.enable { + enable = true; + user = "searx"; + port = 6370; + databases = 16; + logLevel = "debug"; + requirePass = "searxng"; + }; + + forgejo = mkIf cfg.forgejo.enable { + enable = true; + user = "forgejo"; + port = 6371; + databases = 16; + logLevel = "debug"; + requirePass = "forgejo"; + }; + + mastodon = mkIf cfg.social.mastodon.enable { + enable = true; + user = "mastodon"; + port = 6372; + databases = 16; + logLevel = "debug"; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/default.nix b/nyx/modules/core/roles/server/system/services/default.nix new file mode 100644 index 0000000..8810a96 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/default.nix @@ -0,0 +1,27 @@ +{ + imports = [ + # essentials + ./databases # mysql, postgreqsl, redis and more + ./nginx # base nginx webserver configuration + + # other services + ./bincache # atticd and harmonia + ./monitoring # prometheus, grafana, loki and uptime-kuma + ./networking # wireguard and headscale + ./social # mastodon and matrix + ./forgejo.nix # lightweight git service, fork of gitea + ./forgejo-runner.nix # self-hosted runner for forgejo + ./nextcloud.nix # cloud storage (not a backup solution) + ./vaultwarden.nix # bitwarden compatible password manager + ./mailserver.nix # nixos-mailserver setup + ./jellyfin.nix # media server + ./tor.nix # tor relay + ./searxng.nix # searx search engine + ./reposilite.nix # self-hosted maven repository + ./elasticsearch.nix # elasticsearch + ./kanidm.nix # kanidm identity management + + # misc + ./mkm.nix # holy fuck + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/elasticsearch.nix b/nyx/modules/core/roles/server/system/services/elasticsearch.nix new file mode 100644 index 0000000..b145a3b --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/elasticsearch.nix @@ -0,0 +1,22 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.elasticsearch.enable { + services.elasticsearch = { + enable = true; + single_node = true; + cluster_name = "elasticsearch-${config.networking.hostName}"; + + extraConf = '' + xpack.security.enabled: false + ''; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/forgejo-runner.nix b/nyx/modules/core/roles/server/system/services/forgejo-runner.nix new file mode 100644 index 0000000..2d56fe1 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/forgejo-runner.nix @@ -0,0 +1,74 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + cfg = config.modules.system.services; + + # construct each runner using the mkRunner function + # you can pass additional configuration options in the instance submodule + # it'll be merged to the below configuration + mkRunner = { + name, + settings, + }: + { + enable = true; + inherit name; + + url = "https://git.notashelf.dev"; + + # NOTE: changing (i.e adding or removing) labels causes your old registration token to expire + # make sure your labels are final before deploying + labels = [ + "debian-latest:docker://node:18-bullseye" + "ubuntu-latest:docker://node:18-bullseye" + "act:docker://ghcr.io/catthehacker/ubuntu:act-latest" + #"native:host" + ]; + } + // settings; +in { + config = mkIf cfg.forgejo.enable { + users = { + groups.gitea-runner = {}; + users.gitea-runner = { + isSystemUser = true; + createHome = true; + home = "/var/lib/gitea-runner"; + group = "gitea-runner"; + extraGroups = ["docker"]; + }; + }; + + services.gitea-actions-runner = { + package = pkgs.forgejo-actions-runner; + instances = { + "runner-01" = mkRunner { + name = "runner-01"; + settings = { + tokenFile = config.age.secrets.forgejo-runner-token.path; + settings = { + capacity = 4; + container.network = "host"; + cache.enabled = true; + }; + + # packages that'll be made available to the host + # when the runner is configured with a host execution label. + hostPackages = with pkgs; [ + bash + curl + coreutils + wget + gitMinimal + ]; + }; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/forgejo.nix b/nyx/modules/core/roles/server/system/services/forgejo.nix new file mode 100644 index 0000000..8ed0706 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/forgejo.nix @@ -0,0 +1,134 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + cfg = config.modules.system.services; + domain = "git.notashelf.dev"; + + inherit (cfg.forgejo.settings) port; +in { + config = mkIf cfg.forgejo.enable { + modules.system.services = { + nginx.enable = true; + database = { + redis.enable = true; + postgresql.enable = true; + }; + }; + + networking.firewall.allowedTCPPorts = [ + # make sure the service is reachable from outside + config.services.forgejo.settings.server.HTTP_PORT + config.services.forgejo.settings.server.SSH_PORT + ]; + + users = { + users.git = { + isSystemUser = true; + createHome = false; + group = "git"; + }; + + groups.git = {}; + }; + + services = { + forgejo = { + enable = true; + package = pkgs.forgejo; + stateDir = "/srv/storage/forgejo/data"; + + mailerPasswordFile = config.age.secrets.mailserver-forgejo-secret.path; + lfs.enable = true; + + settings = { + default.APP_NAME = "The Secret Shelf"; + + actions = { + ENABLED = true; + DEFAULT_ACTIONS_URL = "https://git.notashelf.dev"; + }; + + other = { + SHOW_FOOTER_VERSION = false; + SHOW_FOOTER_TEMPLATE_LOAD_TIME = false; + }; + + session = { + COOKIE_SECURE = true; + SAME_SITE = "strict"; + }; + + server = { + PROTOCOL = "http+unix"; + HTTP_PORT = port; + ROOT_URL = "https://${domain}"; + DOMAIN = "${domain}"; + DISABLE_ROUTER_LOG = true; + SSH_CREATE_AUTHORIZED_KEYS_FILE = true; + LANDING_PAGE = "/explore"; + + START_SSH_SERVER = true; + SSH_PORT = 2222; + SSH_LISTEN_PORT = 2222; + }; + + database = { + DB_TYPE = lib.mkForce "postgres"; + HOST = "/run/postgresql"; + NAME = "forgejo"; + USER = "forgejo"; + PASSWD = "forgejo"; + }; + + cache = { + ENABLED = true; + ADAPTER = "redis"; + HOST = "redis://:forgejo@localhost:6371"; + }; + + mailer = mkIf config.modules.system.services.mailserver.enable { + ENABLED = true; + PROTOCOL = "smtps"; + SMTP_ADDR = "mail.notashelf.dev"; + USER = "git@notashelf.dev"; + }; + + ui.DEFAULT_THEME = "arc-green"; + attachment.ALLOWED_TYPES = "*/*"; + service.DISABLE_REGISTRATION = true; + packages.ENABLED = false; + repository.PREFERRED_LICENSES = "MIT,GPL-3.0,GPL-2.0,LGPL-3.0,LGPL-2.1"; + log.LEVEL = "Debug"; + "repository.upload" = { + FILE_MAX_SIZE = 100; + MAX_FILES = 10; + }; + }; + + # backup + dump = { + enable = true; + backupDir = "/srv/storage/forgejo/dump"; + interval = "06:00"; + type = "tar.zst"; + }; + }; + + nginx.virtualHosts."git.notashelf.dev" = + { + locations."/" = { + recommendedProxySettings = true; + proxyPass = "http://unix:/run/forgejo/forgejo.sock"; + }; + + quic = true; + } + // lib.sslTemplate; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/jellyfin.nix b/nyx/modules/core/roles/server/system/services/jellyfin.nix new file mode 100644 index 0000000..7c87c12 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/jellyfin.nix @@ -0,0 +1,38 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.jellyfin.enable { + modules.system.services = { + nginx.enable = true; + }; + + services = { + jellyfin = { + enable = true; + group = "jellyfin"; + user = "jellyfin"; + openFirewall = true; + }; + + nginx.virtualHosts. "fin.notashelf.dev" = + { + locations."/" = { + # TODO: the port is not customizable in the upstream service, PR nixpkgs + proxyPass = "http://127.0.0.1:${cfg.jellyfin.settings.port}/"; + proxyWebsockets = true; + extraConfig = "proxy_pass_header Authorization;"; + }; + + quic = true; + } + // lib.sslTemplate; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/kanidm.nix b/nyx/modules/core/roles/server/system/services/kanidm.nix new file mode 100644 index 0000000..3476a7f --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/kanidm.nix @@ -0,0 +1,47 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + domain = "idm.notashelf.dev"; + certDir = config.security.acme.certs.${domain}.directory; + + sys = config.modules.system; + cfg = sys.services; + + inherit (cfg.kanidm.settings) host port; +in { + config = mkIf cfg.kanidm.enable { + services.kanidm = { + enableServer = true; + serverSettings = { + inherit domain; + origin = "https://${domain}"; + bindaddress = "${host}:${toString port}"; + trust_x_forward_for = true; + #tls_chain = "${certDir}/fullchain.pem"; + #tls_key = "${certDir}/key.pem"; + online_backup = { + path = "/srv/storage/kanidm/backups"; + schedule = "0 0 * * *"; # Every day at midnight. + }; + }; + }; + + systemd.services.kanidm = { + after = ["acme-selfsigned-internal.${domain}.target"]; + serviceConfig = { + SupplementaryGroups = [config.security.acme.certs.${domain}.group]; + BindReadOnlyPaths = [certDir]; + }; + }; + + services.nginx.virtualHosts.${domain} = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "https://${host}:${toString port}"; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/mailserver.nix b/nyx/modules/core/roles/server/system/services/mailserver.nix new file mode 100644 index 0000000..d60b311 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/mailserver.nix @@ -0,0 +1,193 @@ +{ + config, + lib, + pkgs, + inputs, + ... +}: let + inherit (lib) mkIf; + inherit (config.age) secrets; + + sys = config.modules.system; + cfg = sys.services; +in { + imports = [ + inputs.simple-nixos-mailserver.nixosModule + ]; + + config = mkIf cfg.mailserver.enable { + # required for roundcube + networking.firewall.allowedTCPPorts = [80 443]; + + mailserver = { + enable = true; + mailDirectory = "/srv/storage/mail/vmail"; + dkimKeyDirectory = "/srv/storage/mail/dkim"; + sieveDirectory = "/srv/storage/mail/sieve"; + openFirewall = true; + enableImap = true; + enableImapSsl = true; + enablePop3 = false; + enablePop3Ssl = false; + enableSubmission = false; + enableSubmissionSsl = true; + hierarchySeparator = "/"; + localDnsResolver = false; + fqdn = "mail.notashelf.dev"; + certificateScheme = "acme-nginx"; + domains = ["notashelf.dev"]; + loginAccounts = { + "raf@notashelf.dev" = { + hashedPasswordFile = secrets.mailserver-secret.path; + aliases = [ + "me" + "raf" + "me@notashelf.dev" + "admin" + "admin@notashelf.dev" + "root" + "root@notashelf.dev" + "postmaster" + "postmaster@notashelf.dev" + ]; + }; + + "noreply@notashelf.dev" = { + aliases = ["noreply"]; + hashedPasswordFile = secrets.mailserver-noreply-secret.path; + sendOnly = true; + sendOnlyRejectMessage = ""; + }; + + "git@notashelf.dev" = mkIf cfg.forgejo.enable { + aliases = ["git" "forgejo"]; + hashedPasswordFile = secrets.mailserver-forgejo-secret.path; + sendOnly = true; + sendOnlyRejectMessage = ""; + }; + + "vaultwarden@notashelf.dev" = mkIf cfg.vaultwarden.enable { + aliases = ["vaultwarden" "vault"]; + hashedPasswordFile = secrets.mailserver-vaultwarden-secret.path; + sendOnly = true; + sendOnlyRejectMessage = ""; + }; + + "matrix@notashelf.dev" = mkIf cfg.social.matrix.enable { + aliases = ["matrix"]; + hashedPasswordFile = secrets.mailserver-matrix-secret.path; + sendOnly = true; + sendOnlyRejectMessage = ""; + }; + + "cloud@notashelf.dev" = mkIf cfg.nextcloud.enable { + aliases = ["cloud" "nextcloud"]; + hashedPasswordFile = secrets.mailserver-cloud-secret.path; + sendOnly = true; + sendOnlyRejectMessage = ""; + }; + }; + + mailboxes = { + Archive = { + auto = "subscribe"; + specialUse = "Archive"; + }; + Drafts = { + auto = "subscribe"; + specialUse = "Drafts"; + }; + Sent = { + auto = "subscribe"; + specialUse = "Sent"; + }; + Junk = { + auto = "subscribe"; + specialUse = "Junk"; + }; + Trash = { + auto = "subscribe"; + specialUse = "Trash"; + }; + }; + + fullTextSearch = { + enable = true; + # index new email as they arrive + autoIndex = true; + # this only applies to plain text attachments, binary attachments are never indexed + indexAttachments = true; + enforced = "body"; + }; + + vmailUserName = "vmail"; + vmailGroupName = "vmail"; + + useFsLayout = true; + }; + + services = { + roundcube = { + enable = true; + database.username = "roundcube"; + maxAttachmentSize = 50; + dicts = with pkgs.aspellDicts; [en tr de]; + # this is the url of the vhost, not necessarily the same as the fqdn of + # the mailserver + hostName = "webmail.notashelf.dev"; + extraConfig = '' + $config['imap_host'] = array( + 'tls://mail.notashelf.dev' => "NotAShelf's Mail Server", + 'ssl://imap.gmail.com:993' => 'Google Mail', + ); + $config['username_domain'] = array( + 'mail.notashelf.dev' => 'notashelf.dev', + 'mail.gmail.com' => 'gmail.com', + ); + $config['x_frame_options'] = false; + # starttls needed for authentication, so the fqdn required to match + # the certificate + $config['smtp_host'] = "tls://${config.mailserver.fqdn}"; + $config['smtp_user'] = "%u"; + $config['smtp_pass'] = "%p"; + $config['plugins'] = [ "carddav" ]; + ''; + }; + + postfix = { + dnsBlacklists = [ + "all.s5h.net" + "b.barracudacentral.org" + "bl.spamcop.net" + "blacklist.woody.ch" + ]; + dnsBlacklistOverrides = '' + notashelf.dev OK + mail.notashelf.dev OK + 127.0.0.0/8 OK + 192.168.0.0/16 OK + ''; + headerChecks = [ + { + action = "IGNORE"; + pattern = "/^User-Agent.*Roundcube Webmail/"; + } + ]; + + config = { + smtp_helo_name = config.mailserver.fqdn; + }; + }; + + phpfpm.pools.roundcube.settings = { + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + }; + + nginx.virtualHosts = { + "mail.notashelf.dev" = {quic = true;} // lib.sslTemplate; + "webmail.notashelf.dev" = {quic = true;} // lib.sslTemplate; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/miniflux.nix b/nyx/modules/core/roles/server/system/services/miniflux.nix new file mode 100644 index 0000000..bdf2315 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/miniflux.nix @@ -0,0 +1,92 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf getExe'; + + dev = config.modules.device; + cfg = config.modules.system.services; + acceptedTypes = ["server" "hybrid"]; +in { + config = mkIf ((builtins.elem dev.type acceptedTypes) && cfg.miniflux.enable) { + # https://github.com/Gerg-L/nixos/blob/master/hosts/gerg-desktop/services/miniflux.nix + # miniflux setup courtesy of the funny frog man (he's bald) + + systemd.services = { + miniflux = { + description = "Miniflux service"; + wantedBy = ["multi-user.target"]; + requires = ["miniflux-dbsetup.service"]; + after = ["network.target" "postgresql.service" "miniflux-dbsetup.service"]; + script = getExe' pkgs.miniflux "miniflux"; + + serviceConfig = { + User = "miniflux"; + RuntimeDirectory = "miniflux"; + RuntimeDirectoryMode = "0770"; + EnvironmentFile = config.age.secrets.miniflux-env.path; + + # Hardening + CapabilityBoundingSet = [""]; + DeviceAllow = [""]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_UNIX"]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = ["@system-service" "~@privileged"]; + UMask = "0077"; + }; + + environment = { + BASE_URL = "https://flux.notashelf.dev"; + LISTEN_ADDR = "/run/miniflux/miniflux.sock"; + DATABASE_URL = "user=miniflux host=/run/postgresql dbname=miniflux"; + RUN_MIGRATIONS = "1"; + CREATE_ADMIN = "1"; + }; + }; + miniflux-dbsetup = { + description = "Miniflux database setup"; + requires = ["postgresql.service"]; + after = ["network.target" "postgresql.service"]; + script = '' + ${lib.getExe' config.services.postgresql.package "psql"} "miniflux" -c "CREATE EXTENSION IF NOT EXISTS hstore" + ''; + serviceConfig = { + Type = "oneshot"; + User = config.services.postgresql.superUser; + }; + }; + }; + users = { + groups.miniflux = { + gid = 377; + }; + users = { + miniflux = { + group = "miniflux"; + extraGroups = ["postgres"]; + isSystemUser = true; + uid = 377; + }; + ${config.services.nginx.user}.extraGroups = ["miniflux"]; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/mkm.nix b/nyx/modules/core/roles/server/system/services/mkm.nix new file mode 100644 index 0000000..0dab4be --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/mkm.nix @@ -0,0 +1,31 @@ +{ + inputs', + config, + lib, + ... +}: let + inherit (lib) mkIf; + cfg = config.modules.system.services; +in { + config = mkIf cfg.mkm.enable { + virtualisation.oci-containers = { + backend = "podman"; + containers = { + "mkm-web" = mkIf (config.networking.hostName == "helios") { + autoStart = true; + environmentFiles = [ + config.age.secrets.mkm-web.path + ]; + ports = [ + "3005:3005" + "3306:3306" + ]; + extraOptions = ["--network=host"]; + + image = "mkm-web"; + imageFile = inputs'.mkm.packages.dockerImage; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/default.nix b/nyx/modules/core/roles/server/system/services/monitoring/default.nix new file mode 100644 index 0000000..d98f495 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./grafana + ./prometheus.nix + ./loki.nix + ./uptime-kuma.nix + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/grafana/dashboards.nix b/nyx/modules/core/roles/server/system/services/monitoring/grafana/dashboards.nix new file mode 100644 index 0000000..b8de96a --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/grafana/dashboards.nix @@ -0,0 +1,26 @@ +{ + lib, + pkgs, + ... +}: let + loadDashboard = file: + lib.pipe file [ + lib.importJSON + ({dashboard, ...}: rec { + name = "provision-dashboard-${dashboard.uid}.json"; + path = builtins.toFile name (builtins.toJSON dashboard); + }) + ]; + + dashboardsDir = + pkgs.linkFarm + "grafana-provisioning-dashboards" + (map loadDashboard (lib.filesystem.listFilesRecursive ./objects/dashboards)); +in { + services.grafana.provision.dashboards.settings = { + providers = lib.singleton { + options.path = dashboardsDir; + allowUiUpdates = true; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/grafana/default.nix b/nyx/modules/core/roles/server/system/services/monitoring/grafana/default.nix new file mode 100644 index 0000000..ab39fc2 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/grafana/default.nix @@ -0,0 +1,128 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + # imports = [./dashboards.nix]; + config = mkIf cfg.monitoring.grafana.enable { + networking.firewall.allowedTCPPorts = [config.services.grafana.settings.server.http_port]; + + modules.system.services.database = { + postgresql.enable = true; + }; + + services = { + grafana = { + enable = true; + settings = { + server = { + http_addr = "0.0.0.0"; + http_port = 3000; + + root_url = "https://dash.notashelf.dev"; + domain = "dash.notashelf.dev"; + enforce_domain = true; + }; + + database = { + type = "postgres"; + host = "/run/postgresql"; + name = "grafana"; + user = "grafana"; + ssl_mode = "disable"; + }; + + security = { + cookie_secure = true; + disable_gravatar = true; + }; + + analytics = { + reporting_enabled = false; + check_for_updates = false; + }; + + "auth.anonymous".enabled = false; + "auth.basic".enabled = false; + + users = { + allow_signup = false; + }; + }; + + provision = { + enable = true; + datasources.settings = { + datasources = [ + (mkIf sys.services.monitoring.prometheus.enable { + name = "Prometheus"; + type = "prometheus"; + access = "proxy"; + orgId = 1; + uid = "Y4SSG429DWCGDQ3R"; + url = "http://127.0.0.1:${toString config.services.prometheus.port}"; + isDefault = true; + version = 1; + editable = true; + jsonData = { + graphiteVersion = "1.1"; + tlsAuth = false; + tlsAuthWithCACert = false; + }; + }) + + (mkIf sys.services.monitoring.loki.enable { + name = "Loki"; + type = "loki"; + access = "proxy"; + url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}"; + }) + + (mkIf sys.services.database.postgresql.enable { + name = "PostgreSQL"; + type = "postgres"; + access = "proxy"; + url = "http://127.0.0.1:9103"; + }) + ]; + + # typos go here + deleteDatasources = [ + { + name = "postgres"; + orgId = 0; + } + { + name = "redis"; + orgId = 0; + } + { + name = "Endlessh-go"; + orgId = 0; + } + ]; + }; + }; + }; + + nginx.virtualHosts."dash.notashelf.dev" = + { + locations."/" = { + proxyPass = with config.services.grafana.settings.server; "http://${toString http_addr}:${toString http_port}/"; + proxyWebsockets = true; + }; + + quic = true; + } + // { + addSSL = true; + enableACME = true; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/grafana/objects/dashboards/dashboard-01.json b/nyx/modules/core/roles/server/system/services/monitoring/grafana/objects/dashboards/dashboard-01.json new file mode 100644 index 0000000..1607e00 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/grafana/objects/dashboards/dashboard-01.json @@ -0,0 +1,23804 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:1058", + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 1860, + "graphTooltip": 1, + "id": 17, + "links": [ + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "GitHub", + "type": "link", + "url": "https://github.com/rfmoz/grafana-dashboards" + }, + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "Grafana", + "type": "link", + "url": "https://grafana.com/grafana/dashboards/1860" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 261, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Quick CPU / Mem / Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Busy state of all CPU cores together", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 20, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "(sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode!=\"idle\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))) * 100", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "", + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "CPU Busy", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Busy state of all CPU cores together (5 min average)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 1 + }, + "id": 155, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time(node_load5{instance=\"$node\",job=\"$job\"}[$__rate_interval]) * 100 / on(instance) group_left sum by (instance)(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]))", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "Sys Load (5m avg)", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Busy state of all CPU cores together (15 min average)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 19, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time(node_load15{instance=\"$node\",job=\"$job\"}[$__rate_interval]) * 100 / on(instance) group_left sum by (instance)(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]))", + "hide": false, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "Sys Load (15m avg)", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Non available RAM memory", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 9, + "y": 1 + }, + "hideTimeOverride": false, + "id": 16, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "((avg_over_time(node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval]) - avg_over_time(node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])) / (avg_over_time(node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval]) )) * 100", + "format": "time_series", + "hide": true, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "100 - ((avg_over_time(node_memory_MemAvailable_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval]) * 100) / avg_over_time(node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval]))", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "B", + "step": 240 + } + ], + "title": "RAM Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Used Swap", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 25 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 1 + }, + "id": 21, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "((avg_over_time(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval]) - avg_over_time(node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])) / (avg_over_time(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval]) )) * 100", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "SWAP Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Used Root FS", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 1 + }, + "id": 154, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "100 - ((avg_over_time(node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"}[$__rate_interval]) * 100) / avg_over_time(node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"}[$__rate_interval]))", + "format": "time_series", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "Root FS Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Total number of CPU cores", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 18, + "y": 1 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "CPU Cores", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "System uptime", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 20, + "y": 1 + }, + "hideTimeOverride": true, + "id": 15, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_time_seconds{instance=\"$node\",job=\"$job\"} - node_boot_time_seconds{instance=\"$node\",job=\"$job\"}", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Total RootFS", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 70 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 18, + "y": 3 + }, + "id": 23, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"}", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "RootFS Total", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Total RAM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 20, + "y": 3 + }, + "id": 75, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "RAM Total", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Total SWAP", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 22, + "y": 3 + }, + "id": 18, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"}", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "SWAP Total", + "type": "stat" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 263, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Basic CPU / Mem / Net / Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Basic CPU info", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Busy Iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy Iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy System" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy User" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy Other" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 77, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"system\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Busy System", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Busy User", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"iowait\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy Iowait", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=~\".*irq\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy IRQs", + "range": true, + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode!='idle',mode!='user',mode!='system',mode!='iowait',mode!='irq',mode!='softirq'}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy Other", + "range": true, + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"idle\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Idle", + "range": true, + "refId": "F", + "step": 240 + } + ], + "title": "CPU Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Basic memory usage", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SWAP Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Cache + Buffer" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DEDAF7", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 78, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "RAM Total", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"} - (node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} + node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} + node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "RAM Used", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} + node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} + node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "RAM Cache + Buffer", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "RAM Free", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SWAP Used", + "refId": "E", + "step": 240 + } + ], + "title": "Memory Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Basic network info per interface", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Recv_bytes_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_drop_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_errs_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CCA300", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_bytes_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_drop_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_errs_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CCA300", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_drop_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#967302", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_errs_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_bytes_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_drop_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#967302", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_errs_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 74, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "recv {{device}}", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "trans {{device}} ", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Disk space used of all filesystems mounted", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 152, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "100 - ((node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'} * 100) / node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}}", + "refId": "A", + "step": 240 + } + ], + "title": "Disk Space Used Basic", + "type": "timeseries" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 265, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "percentage", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Idle - Waiting for something to happen" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Iowait - Waiting for I/O to complete" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Irq - Servicing interrupts" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Nice - Niced processes executing in user mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Softirq - Servicing softirqs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Steal - Time spent in other operating systems when running in a virtualized environment" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCE2DE", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "System - Processes executing in kernel mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "User - Normal processes executing in user mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5195CE", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 23 + }, + "id": 3, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"system\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "System - Processes executing in kernel mode", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "User - Normal processes executing in user mode", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"nice\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Nice - Niced processes executing in user mode", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"iowait\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Iowait - Waiting for I/O to complete", + "range": true, + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"irq\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Irq - Servicing interrupts", + "range": true, + "refId": "F", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"softirq\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Softirq - Servicing softirqs", + "range": true, + "refId": "G", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"steal\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Steal - Time spent in other operating systems when running in a virtualized environment", + "range": true, + "refId": "H", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"idle\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Idle - Waiting for something to happen", + "range": true, + "refId": "J", + "step": 240 + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap - Swap memory usage" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused - Free memory unassigned" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Hardware Corrupted - *./" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 24, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Slab_bytes{instance=\"$node\",job=\"$job\"} - node_memory_PageTables_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapCached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Apps - Memory used by user-space applications", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_PageTables_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "PageTables - Memory used to map between virtual and physical memory addresses", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_SwapCached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SwapCache - Memory that keeps track of pages that have been fetched from swap but not yet been modified", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Slab_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Slab - Memory used by the kernel to cache data structures for its own use (caches like inode, dentry, etc)", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Cache - Parked file data (file content) cache", + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Buffers - Block device (e.g. harddisk) cache", + "refId": "F", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Unused - Free memory unassigned", + "refId": "G", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Swap - Swap space used", + "refId": "H", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_HardwareCorrupted_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working", + "refId": "I", + "step": 240 + } + ], + "title": "Memory Stack", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bits out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "receive_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "receive_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 84, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 156, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'} - node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}}", + "refId": "A", + "step": 240 + } + ], + "title": "Disk Space Used", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IO read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 229, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "intervalFactor": 4, + "legendFormat": "{{device}} - Reads completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Writes completed", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "io time" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*read*./" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 42, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_read_bytes_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Successfully read bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_written_bytes_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Successfully written bytes", + "refId": "B", + "step": 240 + } + ], + "title": "I/O Usage Read / Write", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "%util", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "io time" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 127, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_io_time_seconds_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"} [$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}}", + "refId": "A", + "step": 240 + } + ], + "title": "I/O Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "percentage", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 3, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^Guest - /" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5195ce", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^GuestNice - /" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#c15c17", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 319, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_guest_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[1m])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[1m])))", + "hide": false, + "legendFormat": "Guest - Time spent running a virtual CPU for a guest operating system", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_guest_seconds_total{instance=\"$node\",job=\"$job\", mode=\"nice\"}[1m])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[1m])))", + "hide": false, + "legendFormat": "GuestNice - Time spent running a niced guest (virtual CPU for guest operating system)", + "range": true, + "refId": "B" + } + ], + "title": "CPU spent seconds in guests (VMs)", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "CPU / Memory / Net / Disk", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 266, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 54 + }, + "id": 136, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Inactive_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Inactive - Memory which has been less recently used. It is more eligible to be reclaimed for other purposes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Active_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Active - Memory that has been used more recently and usually not reclaimed unless absolutely necessary", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Active / Inactive", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*CommitLimit - *./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 54 + }, + "id": 135, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Committed_AS_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Committed_AS - Amount of memory presently allocated on the system", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_CommitLimit_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CommitLimit - Amount of memory currently available to be allocated on the system", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Committed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 64 + }, + "id": 191, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Inactive_file_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inactive_file - File-backed memory on inactive LRU list", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Inactive_anon_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inactive_anon - Anonymous and swap cache on inactive LRU list, including tmpfs (shmem)", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Active_file_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Active_file - File-backed memory on active LRU list", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Active_anon_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Active_anon - Anonymous and swap cache on active least-recently-used (LRU) list, including tmpfs", + "refId": "D", + "step": 240 + } + ], + "title": "Memory Active / Inactive Detail", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 64 + }, + "id": 130, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Writeback_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Writeback - Memory which is actively being written back to disk", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_WritebackTmp_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "WritebackTmp - Memory used by FUSE for temporary writeback buffers", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Dirty_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Dirty - Memory which is waiting to get written back to the disk", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Writeback and Dirty", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 74 + }, + "id": 138, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Mapped_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Mapped - Used memory in mapped pages files which have been mapped, such as libraries", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Shmem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Shmem - Used shared memory (shared between several processes, thus including RAM disks)", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_ShmemHugePages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_ShmemPmdMapped_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ShmemPmdMapped - Amount of shared (shmem/tmpfs) memory backed by huge pages", + "refId": "D", + "step": 240 + } + ], + "title": "Memory Shared and Mapped", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 74 + }, + "id": 131, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_SUnreclaim_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SUnreclaim - Part of Slab, that cannot be reclaimed on memory pressure", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SReclaimable - Part of Slab, that might be reclaimed, such as caches", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Slab", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 84 + }, + "id": 70, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_VmallocChunk_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocChunk - Largest contiguous block of vmalloc area which is free", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_VmallocTotal_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocTotal - Total size of vmalloc memory area", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_VmallocUsed_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocUsed - Amount of vmalloc area which is used", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Vmalloc", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 84 + }, + "id": 159, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Bounce_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Bounce - Memory used for block device bounce buffers", + "refId": "A", + "step": 240 + } + ], + "title": "Memory Bounce", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Inactive *./" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 94 + }, + "id": 129, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_AnonHugePages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "AnonHugePages - Memory in anonymous huge pages", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_AnonPages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "AnonPages - Memory in user pages not backed by files", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Anonymous", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 94 + }, + "id": 160, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_KernelStack_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "KernelStack - Kernel memory stack. This is not reclaimable", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Percpu_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PerCPU - Per CPU memory allocated dynamically by loadable modules", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Kernel / CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 104 + }, + "id": 140, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_HugePages_Free{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Free - Huge pages in the pool that are not yet allocated", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_HugePages_Rsvd{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Rsvd - Huge pages for which a commitment to allocate from the pool has been made, but no allocation has yet been made", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_HugePages_Surp{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Surp - Huge pages in the pool above the value in /proc/sys/vm/nr_hugepages", + "refId": "C", + "step": 240 + } + ], + "title": "Memory HugePages Counter", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 104 + }, + "id": 71, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_HugePages_Total{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages - Total size of the pool of huge pages", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Hugepagesize_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Hugepagesize - Huge Page size", + "refId": "B", + "step": 240 + } + ], + "title": "Memory HugePages Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 114 + }, + "id": 128, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_DirectMap1G_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "DirectMap1G - Amount of pages mapped as this size", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_DirectMap2M_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "DirectMap2M - Amount of pages mapped as this size", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_DirectMap4k_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "DirectMap4K - Amount of pages mapped as this size", + "refId": "C", + "step": 240 + } + ], + "title": "Memory DirectMap", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 114 + }, + "id": 137, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Unevictable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unevictable - Amount of unevictable memory that can't be swapped out for a variety of reasons", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_Mlocked_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "MLocked - Size of pages locked to memory using the mlock() system call", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Unevictable and MLocked", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 124 + }, + "id": 132, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_memory_NFS_Unstable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NFS Unstable - Memory in NFS pages sent to the server, but not yet committed to the storage", + "refId": "A", + "step": 240 + } + ], + "title": "Memory NFS", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Memory Meminfo", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 267, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*out/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 41 + }, + "id": 176, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_pgpgin{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pagesin - Page in operations", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_pgpgout{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pagesout - Page out operations", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Pages In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*out/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 41 + }, + "id": 22, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_pswpin{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pswpin - Pages swapped in", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_pswpout{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pswpout - Pages swapped out", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Pages Swap In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "faults", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Pgfault - Page major and minor fault operations" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 51 + }, + "id": 175, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_pgfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgfault - Page major and minor fault operations", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_pgmajfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgmajfault - Major page fault operations", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_pgfault{instance=\"$node\",job=\"$job\"}[$__rate_interval]) - irate(node_vmstat_pgmajfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgminfault - Minor page fault operations", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Page Faults", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 51 + }, + "id": 307, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_vmstat_oom_kill{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "oom killer invocations ", + "refId": "A", + "step": 240 + } + ], + "title": "OOM Killer", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Memory Vmstat", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 293, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Variation*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 56 + }, + "id": 260, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_estimated_error_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Estimated error in seconds", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_offset_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Time offset in between local system and reference clock", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_maxerror_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum error in seconds", + "refId": "C", + "step": 240 + } + ], + "title": "Time Synchronized Drift", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 56 + }, + "id": 291, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_loop_time_constant{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Phase-locked loop time adjust", + "refId": "A", + "step": 240 + } + ], + "title": "Time PLL Adjust", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Variation*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 66 + }, + "id": 168, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_sync_status{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Is clock synchronized to a reliable server (1 = yes, 0 = no)", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_frequency_adjustment_ratio{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Local clock frequency adjustment", + "refId": "B", + "step": 240 + } + ], + "title": "Time Synchronized Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 66 + }, + "id": 294, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_tick_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Seconds between clock ticks", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_timex_tai_offset_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "International Atomic Time (TAI) offset", + "refId": "B", + "step": 240 + } + ], + "title": "Time Misc", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "System Timesync", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 312, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 43 + }, + "id": 62, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_procs_blocked{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processes blocked waiting for I/O to complete", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_procs_running{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processes in runnable state", + "refId": "B", + "step": 240 + } + ], + "title": "Processes Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 43 + }, + "id": 315, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_processes_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ state }}", + "refId": "A", + "step": 240 + } + ], + "title": "Processes State", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "forks / sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 148, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_forks_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Processes forks second", + "refId": "A", + "step": 240 + } + ], + "title": "Processes Forks", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max.*/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 149, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(process_virtual_memory_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Processes virtual memory size in bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "process_resident_memory_max_bytes{instance=\"$node\",job=\"$job\"}", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum amount of virtual memory available in bytes", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(process_virtual_memory_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Processes virtual memory size in bytes", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(process_virtual_memory_max_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum amount of virtual memory available in bytes", + "refId": "D", + "step": 240 + } + ], + "title": "Processes Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PIDs limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 63 + }, + "id": 313, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_processes_pids{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Number of PIDs", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_processes_max_processes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PIDs limit", + "refId": "B", + "step": 240 + } + ], + "title": "PIDs Number and Limit", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*waiting.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 63 + }, + "id": 305, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_schedstat_running_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }} - seconds spent running a process", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_schedstat_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }} - seconds spent by processing waiting for this CPU", + "refId": "B", + "step": 240 + } + ], + "title": "Process schedule stats Running / Waiting", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Threads limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 73 + }, + "id": 314, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_processes_threads{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Allocated threads", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_processes_max_threads{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Threads limit", + "refId": "B", + "step": 240 + } + ], + "title": "Threads Number and Limit", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "System Processes", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 269, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 8, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_context_switches_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Context switches", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_intr_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Interrupts", + "refId": "B", + "step": 240 + } + ], + "title": "Context Switches / Interrupts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 7, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_load1{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 1m", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_load5{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 5m", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_load15{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 15m", + "refId": "C", + "step": 240 + } + ], + "title": "System Load", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "hertz" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Max" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 10 + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": false, + "viz": false + } + }, + { + "id": "custom.fillBelowTo", + "value": "Min" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Min" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": false, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 321, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "node_cpu_scaling_frequency_hertz{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }}", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "avg(node_cpu_scaling_frequency_max_hertz{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Max", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "avg(node_cpu_scaling_frequency_min_hertz{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Min", + "range": true, + "refId": "C", + "step": 240 + } + ], + "title": "CPU Frequency Scaling", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "https://docs.kernel.org/accounting/psi.html", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Memory some" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Memory full" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "I/O some" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "I/O full" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 322, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "rate(node_pressure_cpu_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CPU some", + "range": true, + "refId": "CPU some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "rate(node_pressure_memory_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Memory some", + "range": true, + "refId": "Memory some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "rate(node_pressure_memory_stalled_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Memory full", + "range": true, + "refId": "Memory full", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "rate(node_pressure_io_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "I/O some", + "range": true, + "refId": "I/O some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "rate(node_pressure_io_stalled_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "I/O full", + "range": true, + "refId": "I/O full", + "step": 240 + } + ], + "title": "Pressure Stall Information", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Critical*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 259, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_interrupts_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ type }} - {{ info }}", + "refId": "A", + "step": 240 + } + ], + "title": "Interrupts Detail", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 306, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_schedstat_timeslices_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }}", + "refId": "A", + "step": 240 + } + ], + "title": "Schedule timeslices executed by each cpu", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 56 + }, + "id": 151, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_entropy_available_bits{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Entropy available to random number generators", + "refId": "A", + "step": 240 + } + ], + "title": "Entropy", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 56 + }, + "id": 308, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(process_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Time spent", + "refId": "A", + "step": 240 + } + ], + "title": "CPU time spent in user and system contexts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 66 + }, + "id": 64, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "process_max_fds{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum open file descriptors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "process_open_fds{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Open file descriptors", + "refId": "B", + "step": 240 + } + ], + "title": "File Descriptors", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "System Misc", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 304, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "temperature", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "celsius" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Critical*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 158, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_hwmon_temp_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} temp", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_hwmon_temp_crit_alarm_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Critical Alarm", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_hwmon_temp_crit_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Critical", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_hwmon_temp_crit_hyst_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Critical Historical", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_hwmon_temp_max_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Max", + "refId": "E", + "step": 240 + } + ], + "title": "Hardware temperature monitor", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 300, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_cooling_device_cur_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Current {{ name }} in {{ type }}", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_cooling_device_max_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Max {{ name }} in {{ type }}", + "refId": "B", + "step": 240 + } + ], + "title": "Throttle cooling device", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 69 + }, + "id": 302, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_power_supply_online{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ power_supply }} online", + "refId": "A", + "step": 240 + } + ], + "title": "Power supply", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Hardware Misc", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 296, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 297, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_systemd_socket_accepted_connections_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ name }} Connections", + "refId": "A", + "step": 240 + } + ], + "title": "Systemd Sockets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF9830", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Deactivating" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFCB7D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Activating" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C8F2C2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 298, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"activating\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Activating", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"active\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Active", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"deactivating\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Deactivating", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"failed\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Failed", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"inactive\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Inactive", + "refId": "E", + "step": 240 + } + ], + "title": "Systemd Units State", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Systemd", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 270, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "The number (after merges) of I/O requests completed per second for the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IO read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 9, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 4, + "legendFormat": "{{device}} - Reads completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Writes completed", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps Completed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "The number of bytes read from or written to the device per second", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 33, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_read_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "{{device}} - Read bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_written_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Written bytes", + "refId": "B", + "step": 240 + } + ], + "title": "Disk R/W Data", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "The average time for requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "time. read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 37, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_read_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]) / irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - Read wait time avg", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_write_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]) / irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Write wait time avg", + "refId": "B", + "step": 240 + } + ], + "title": "Disk Average Wait Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "The average queue length of the requests that were issued to the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "aqu-sz", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 35, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_io_time_weighted_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}}", + "refId": "A", + "step": 240 + } + ], + "title": "Average Queue Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "The number of read and write requests merged per second that were queued to the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "I/Os", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 67 + }, + "id": 133, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_reads_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Read merged", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_writes_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Write merged", + "refId": "B", + "step": 240 + } + ], + "title": "Disk R/W Merged", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Percentage of elapsed time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100% for devices serving requests serially. But for devices serving requests in parallel, such as RAID arrays and modern SSDs, this number does not reflect their performance limits.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "%util", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 67 + }, + "id": 36, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_io_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - IO", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_discard_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - discard", + "refId": "B", + "step": 240 + } + ], + "title": "Time Spent Doing I/Os", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "The number of outstanding requests at the instant the sample was taken. Incremented as requests are given to appropriate struct request_queue and decremented as they finish.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Outstanding req.", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 77 + }, + "id": 34, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_disk_io_now{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - IO now", + "refId": "A", + "step": 240 + } + ], + "title": "Instantaneous Queue Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IOs", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 77 + }, + "id": 301, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_discards_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - Discards completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_disk_discards_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Discards merged", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps Discards completed / merged", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Storage Disk", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 271, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 62 + }, + "id": 43, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Available", + "metric": "", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_free_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Free", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Size", + "refId": "C", + "step": 240 + } + ], + "title": "Filesystem space available", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "file nodes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 62 + }, + "id": 41, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_files_free{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Free file nodes", + "refId": "A", + "step": 240 + } + ], + "title": "File Nodes Free", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "files", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 72 + }, + "id": 28, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filefd_maximum{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Max open files", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filefd_allocated{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Open files", + "refId": "B", + "step": 240 + } + ], + "title": "File Descriptor", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "file Nodes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 72 + }, + "id": 219, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_files{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - File nodes total", + "refId": "A", + "step": 240 + } + ], + "title": "File Nodes Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "/ ReadOnly" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 82 + }, + "id": 44, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_readonly{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - ReadOnly", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_filesystem_device_error{instance=\"$node\",job=\"$job\",device!~'rootfs',fstype!~'tmpfs'}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Device error", + "refId": "B", + "step": 240 + } + ], + "title": "Filesystem in ReadOnly / Error", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Storage Filesystem", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 272, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "receive_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "receive_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 60, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_packets_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_packets_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic by Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 142, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_errs_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive errors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_errs_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Rransmit errors", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 143, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_drop_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive drop", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_drop_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit drop", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Drop", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 141, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_compressed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive compressed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_compressed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit compressed", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Compressed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 67 + }, + "id": 146, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_multicast_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive multicast", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Multicast", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 67 + }, + "id": 144, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_fifo_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive fifo", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_fifo_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit fifo", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Fifo", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 77 + }, + "id": 145, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_receive_frame_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive frame", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Frame", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 77 + }, + "id": 231, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_carrier_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Statistic transmit_carrier", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Carrier", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 232, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_network_transmit_colls_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit colls", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Colls", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "entries", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NF conntrack limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_nf_conntrack_entries{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NF conntrack entries", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_nf_conntrack_entries_limit{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NF conntrack limit", + "refId": "B", + "step": 240 + } + ], + "title": "NF Contrack", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Entries", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 97 + }, + "id": 230, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_arp_entries{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - ARP entries", + "refId": "A", + "step": 240 + } + ], + "title": "ARP Entries", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 97 + }, + "id": 288, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_network_mtu_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Bytes", + "refId": "A", + "step": 240 + } + ], + "title": "MTU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 107 + }, + "id": 280, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_network_speed_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Speed", + "refId": "A", + "step": 240 + } + ], + "title": "Speed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 107 + }, + "id": 289, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_network_transmit_queue_length{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Interface transmit queue length", + "refId": "A", + "step": 240 + } + ], + "title": "Queue Length", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packetes drop (-) / process (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Dropped.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 117 + }, + "id": 290, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_softnet_processed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Processed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_softnet_dropped_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Dropped", + "refId": "B", + "step": 240 + } + ], + "title": "Softnet Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 117 + }, + "id": 310, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_softnet_times_squeezed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Squeezed", + "refId": "A", + "step": 240 + } + ], + "title": "Softnet Out of Quota", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 127 + }, + "id": 309, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_network_up{operstate=\"up\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{interface}} - Operational state UP", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_network_carrier{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{device}} - Physical link state", + "refId": "B" + } + ], + "title": "Network Operational Status", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Network Traffic", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 273, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 63, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_TCP_alloc{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_alloc - Allocated sockets", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_TCP_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_inuse - Tcp sockets currently in use", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_TCP_mem{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_mem - Used memory for tcp", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_TCP_orphan{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_orphan - Orphan sockets", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_TCP_tw{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_tw - Sockets waiting close", + "refId": "E", + "step": 240 + } + ], + "title": "Sockstat TCP", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 124, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_UDPLITE_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDPLITE_inuse - Udplite sockets currently in use", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_UDP_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDP_inuse - Udp sockets currently in use", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_UDP_mem{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDP_mem - Used memory for udp", + "refId": "C", + "step": 240 + } + ], + "title": "Sockstat UDP", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 58 + }, + "id": 125, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_FRAG_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "FRAG_inuse - Frag sockets currently in use", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_RAW_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "RAW_inuse - Raw sockets currently in use", + "refId": "C", + "step": 240 + } + ], + "title": "Sockstat FRAG / RAW", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 58 + }, + "id": 220, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_TCP_mem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "mem_bytes - TCP sockets in that state", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_UDP_mem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "mem_bytes - UDP sockets in that state", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_FRAG_memory{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "FRAG_memory - Used memory for frag", + "refId": "C" + } + ], + "title": "Sockstat Memory Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "sockets", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 68 + }, + "id": 126, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_sockstat_sockets_used{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Sockets_used - Sockets currently in use", + "refId": "A", + "step": 240 + } + ], + "title": "Sockstat Used", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Network Sockstat", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 274, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "octets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 49 + }, + "id": 221, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_IpExt_InOctets{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InOctets - Received octets", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_IpExt_OutOctets{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "OutOctets - Sent octets", + "refId": "B", + "step": 240 + } + ], + "title": "Netstat IP In / Out Octets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 49 + }, + "id": 81, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Ip_Forwarding{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Forwarding - IP forwarding", + "refId": "A", + "step": 240 + } + ], + "title": "Netstat IP Forwarding", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "messages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 115, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Icmp_InMsgs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InMsgs - Messages which the entity received. Note that this counter includes all those counted by icmpInErrors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Icmp_OutMsgs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutMsgs - Messages which this entity attempted to send. Note that this counter includes all those counted by icmpOutErrors", + "refId": "B", + "step": 240 + } + ], + "title": "ICMP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "messages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 50, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Icmp_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InErrors - Messages which the entity received but determined as having ICMP-specific errors (bad ICMP checksums, bad length, etc.)", + "refId": "A", + "step": 240 + } + ], + "title": "ICMP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Snd.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 69 + }, + "id": 55, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Udp_InDatagrams{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InDatagrams - Datagrams received", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Udp_OutDatagrams{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutDatagrams - Datagrams sent", + "refId": "B", + "step": 240 + } + ], + "title": "UDP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 69 + }, + "id": 109, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Udp_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InErrors - UDP Datagrams that could not be delivered to an application", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Udp_NoPorts{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "NoPorts - UDP Datagrams received on a port with no listener", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_UdpLite_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "InErrors Lite - UDPLite Datagrams that could not be delivered to an application", + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Udp_RcvbufErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "RcvbufErrors - UDP buffer errors received", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Udp_SndbufErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "SndbufErrors - UDP buffer errors send", + "refId": "E", + "step": 240 + } + ], + "title": "UDP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Snd.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 79 + }, + "id": 299, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Tcp_InSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "InSegs - Segments received, including those received in error. This count includes segments received on currently established connections", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Tcp_OutSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutSegs - Segments sent, including those on current connections but excluding those containing only retransmitted octets", + "refId": "B", + "step": 240 + } + ], + "title": "TCP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 79 + }, + "id": 104, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_TcpExt_ListenOverflows{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "ListenOverflows - Times the listen queue of a socket overflowed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_TcpExt_ListenDrops{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "ListenDrops - SYNs to LISTEN sockets ignored", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_TcpExt_TCPSynRetrans{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCPSynRetrans - SYN-SYN/ACK retransmits to break down retransmissions in SYN, fast/timeout retransmits", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Tcp_RetransSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "RetransSegs - Segments retransmitted - that is, the number of TCP segments transmitted containing one or more previously transmitted octets", + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Tcp_InErrs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "InErrs - Segments received in error (e.g., bad TCP checksums)", + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Tcp_OutRsts{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "OutRsts - Segments sent with RST flag", + "refId": "F" + } + ], + "title": "TCP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*MaxConn *./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 89 + }, + "id": 85, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_netstat_Tcp_CurrEstab{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "CurrEstab - TCP connections for which the current state is either ESTABLISHED or CLOSE- WAIT", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_netstat_Tcp_MaxConn{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "MaxConn - Limit on the total number of TCP connections the entity can support (Dynamic is \"-1\")", + "refId": "B", + "step": 240 + } + ], + "title": "TCP Connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Sent.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 89 + }, + "id": 91, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesFailed{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesFailed - Invalid SYN cookies received", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesRecv{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesRecv - SYN cookies received", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesSent{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesSent - SYN cookies sent", + "refId": "C", + "step": 240 + } + ], + "title": "TCP SynCookie", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 99 + }, + "id": 82, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Tcp_ActiveOpens{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ActiveOpens - TCP connections that have made a direct transition to the SYN-SENT state from the CLOSED state", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "irate(node_netstat_Tcp_PassiveOpens{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PassiveOpens - TCP connections that have made a direct transition to the SYN-RCVD state from the LISTEN state", + "refId": "B", + "step": 240 + } + ], + "title": "TCP Direct Transition", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "Enable with --collector.tcpstat argument on node-exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 99 + }, + "id": 320, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"established\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "established - TCP sockets in established state", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"fin_wait2\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "fin_wait2 - TCP sockets in fin_wait2 state", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"listen\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "listen - TCP sockets in listen state", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"time_wait\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "time_wait - TCP sockets in time_wait state", + "range": true, + "refId": "D", + "step": 240 + } + ], + "title": "TCP Stat", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Network Netstat", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 33 + }, + "id": 279, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 66 + }, + "id": 40, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_scrape_collector_duration_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape duration", + "refId": "A", + "step": 240 + } + ], + "title": "Node Exporter Scrape Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*error.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 66 + }, + "id": 157, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_scrape_collector_success{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape success", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "expr": "node_textfile_scrape_error{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape textfile error (1 = true)", + "refId": "B", + "step": 240 + } + ], + "title": "Node Exporter Scrape", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Node Exporter", + "type": "row" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "tags": [ + "linux" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": "datasource", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": true, + "text": "node_internal", + "value": "node_internal" + }, + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Job", + "multi": false, + "name": "job", + "options": [], + "query": { + "query": "label_values(node_uname_info, job)", + "refId": "Prometheus-job-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "localhost:9101", + "value": "localhost:9101" + }, + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "definition": "label_values(node_uname_info{job=\"$job\"}, instance)", + "hide": 0, + "includeAll": false, + "label": "Host", + "multi": false, + "name": "node", + "options": [], + "query": { + "query": "label_values(node_uname_info{job=\"$job\"}, instance)", + "refId": "Prometheus-node-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "value": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+" + }, + "hide": 2, + "includeAll": false, + "multi": false, + "name": "diskdevices", + "options": [ + { + "selected": true, + "text": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "value": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+" + } + ], + "query": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Node Exporter Full", + "uid": "rYdddlPWk", + "version": 3, + "weekStart": "" +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/grafana/objects/dashboards/dashboard-02.json b/nyx/modules/core/roles/server/system/services/monitoring/grafana/objects/dashboards/dashboard-02.json new file mode 100644 index 0000000..937cb4e --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/grafana/objects/dashboards/dashboard-02.json @@ -0,0 +1,1413 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "Dashboard for endlessh (Update variables on time range changes)", + "editable": false, + "fiscalYearStartMonth": 0, + "gnetId": 15156, + "graphTooltip": 0, + "id": 22, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "GitHub", + "tooltip": "GitHub", + "type": "link", + "url": "https://github.com/shizunge/endlessh-go" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Grafana", + "tooltip": "Grafana Dashboard", + "type": "link", + "url": "https://grafana.com/grafana/dashboards/15156" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 36, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^Total number connections that endlessh trapped$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 49, + "refId": "A" + } + ], + "title": "Connections", + "transformations": [ + { + "id": "filterByRefId", + "options": { + "include": "Seen" + } + }, + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Value #Seen" + } + ], + "match": "any", + "type": "include" + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Value #Seen": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "ip": { + "aggregations": [], + "operation": "groupby" + } + } + } + }, + { + "id": "reduce", + "options": { + "includeTimeField": false, + "labelsToFields": false, + "mode": "reduceFields", + "reducers": ["sum"] + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "Value #Seen (sum)": "Total number connections that endlessh trapped" + } + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 42, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^Time spent on endlessh$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 49, + "refId": "A" + } + ], + "title": "Trapped Time", + "transformations": [ + { + "id": "filterByRefId", + "options": { + "include": "Trapped" + } + }, + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Value #Trapped" + } + ], + "match": "all", + "type": "include" + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Value #Trapped": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "ip": { + "aggregations": [], + "operation": "groupby" + } + } + } + }, + { + "id": "reduce", + "options": { + "includeTimeField": false, + "labelsToFields": false, + "mode": "reduceFields", + "reducers": ["sum"] + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "Total": "Seconds spent on endlessh", + "Value #Trapped (sum)": "Time spent on endlessh" + } + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 18, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "exemplar": true, + "expr": "sum(increase(endlessh_sent_bytes_total{instance=~\"$host\",job=~\"$job\"}[$__range]))", + "hide": false, + "interval": "", + "legendFormat": "Bytes sent by endlessh", + "refId": "sent_bytes" + } + ], + "title": "Sent Bytes", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 38, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^Unique IPs connected$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 49, + "refId": "A" + } + ], + "title": "Unique IPs", + "transformations": [ + { + "id": "filterByRefId", + "options": { + "include": "Seen" + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Value #Seen": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "ip": { + "aggregations": [], + "operation": "groupby" + } + } + } + }, + { + "id": "reduce", + "options": { + "includeTimeField": false, + "labelsToFields": false, + "mode": "reduceFields", + "reducers": ["count"] + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "Value #Seen (sum)": "Unique IPs connected", + "ip": "" + } + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "whois", + "url": "https://search.arin.net/rdap/?query=${__value.text}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 45, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^Client IP of the latest connection$/", + "values": false + }, + "text": {}, + "textMode": "value" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 49, + "refId": "A" + } + ], + "title": "Latest Connection", + "transformations": [ + { + "id": "filterByRefId", + "options": { + "include": "Seen" + } + }, + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Value #Seen" + } + ], + "match": "any", + "type": "include" + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Time": { + "aggregations": ["lastNotNull"], + "operation": "aggregate" + }, + "Value #Seen": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "ip": { + "aggregations": [], + "operation": "groupby" + } + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "Time (lastNotNull)" + } + ] + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "instance": true, + "job": true + }, + "indexByName": {}, + "renameByName": { + "Time (lastNotNull)": "Time", + "Value #Seen (sum)": "Count", + "ip": "Client IP of the latest connection" + } + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "red", + "value": 20 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 20, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "exemplar": true, + "expr": "sum((endlessh_client_open_count_total{instance=~\"$host\",job=~\"$job\"}) - (endlessh_client_closed_count_total{instance=~\"$host\",job=~\"$job\"} offset $__interval or endlessh_client_open_count_total{instance=~\"$host\",job=~\"$job\"} * 0))", + "instant": false, + "interval": "", + "legendFormat": "Open Connections", + "refId": "current_open" + } + ], + "title": "Current Connections", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": -0.01, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 3 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 20, + "refId": "A" + } + ], + "title": "Concurrent Connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 3 + }, + "id": 32, + "options": { + "displayLabels": [], + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": ["value", "percent"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 49, + "refId": "A" + } + ], + "title": "Connections by country", + "transformations": [ + { + "id": "filterByRefId", + "options": { + "include": "Seen" + } + }, + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Value #Seen" + } + ], + "match": "any", + "type": "include" + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Value #Seen": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "country": { + "aggregations": ["last"], + "operation": "aggregate" + }, + "ip": { + "aggregations": [], + "operation": "groupby" + } + } + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Value #Seen (sum)": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "country (last)": { + "aggregations": [], + "operation": "groupby" + } + } + } + }, + { + "id": "rowsToFields", + "options": {} + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#96D98D", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 48, + "links": [], + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "default" + }, + "controls": { + "mouseWheelZoom": false, + "showAttribution": false, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "color": { + "field": "Connections", + "fixed": "dark-green" + }, + "fillOpacity": 0.4, + "shape": "circle", + "showLegend": false, + "size": { + "field": "Connections", + "fixed": 5, + "max": 10, + "min": 2 + }, + "style": { + "color": { + "field": "Connections", + "fixed": "dark-green" + }, + "size": { + "field": "Connections", + "fixed": 5, + "max": 9, + "min": 2 + }, + "text": { + "field": "location (lastNotNull) (lastNotNull)", + "fixed": "", + "mode": "fixed" + } + } + }, + "location": { + "geohash": "Geohash", + "mode": "geohash" + }, + "name": "Layer 1", + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "zero", + "lat": 0, + "lon": 0, + "zoom": 1 + } + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 49, + "refId": "A" + } + ], + "title": "Locations", + "transformations": [ + { + "id": "filterByRefId", + "options": { + "include": "Seen" + } + }, + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Value #Seen" + } + ], + "match": "any", + "type": "include" + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Value #Seen": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "geohash": { + "aggregations": ["lastNotNull"], + "operation": "groupby" + }, + "location": { + "aggregations": ["lastNotNull"], + "operation": "aggregate" + } + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": { + "Value #geo (lastNotNull) (sum)": 2, + "geohash (lastNotNull)": 0, + "location (lastNotNull) (lastNotNull)": 1 + }, + "renameByName": { + "Value #Seen (sum)": "Connections", + "geohash": "Geohash", + "location (lastNotNull)": "Location" + } + } + } + ], + "type": "geomap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false, + "minWidth": 50 + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Last Connection" + }, + "properties": [ + { + "id": "custom.minWidth", + "value": 150 + }, + { + "id": "unit", + "value": "dateTimeAsIso" + }, + { + "id": "custom.align", + "value": "left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "IP" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "search ARIN", + "url": "https://search.arin.net/rdap/?query=${__data.fields.IP}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trapped Time" + }, + "properties": [ + { + "id": "unit", + "value": "s" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 49, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "frameIndex": 0, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Last Connection" + } + ] + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "exemplar": true, + "expr": "(endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"} - endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"} offset $__interval) > 0 or (endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"}!=0 unless endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"} offset $__interval)", + "format": "table", + "hide": false, + "interval": "", + "legendFormat": "Seen {{ip}}", + "refId": "Seen" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "exemplar": true, + "expr": "(endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"} - endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"} offset $__interval) > 0 or (endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"}!=0 unless endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"} offset $__interval)", + "format": "table", + "hide": false, + "interval": "", + "legendFormat": "Trapped {{ip}}", + "refId": "Trapped" + } + ], + "title": "Clients", + "transformations": [ + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Value #Seen" + }, + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Value #Trapped" + } + ], + "match": "any", + "type": "include" + } + }, + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "alias": "Seen", + "mode": "reduceRow", + "reduce": { + "include": ["Value #Seen"], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Trapped", + "mode": "reduceRow", + "reduce": { + "include": ["Value #Trapped"], + "reducer": "sum" + } + } + }, + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Seen" + }, + { + "config": { + "id": "greaterOrEqual", + "options": { + "value": 0 + } + }, + "fieldName": "Trapped" + } + ], + "match": "all", + "type": "include" + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "Seen": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "Time": { + "aggregations": ["max"], + "operation": "aggregate" + }, + "Trapped": { + "aggregations": ["sum"], + "operation": "aggregate" + }, + "country": { + "aggregations": ["lastNotNull"], + "operation": "aggregate" + }, + "ip": { + "aggregations": [], + "operation": "groupby" + } + } + } + }, + { + "id": "filterByValue", + "options": { + "filters": [ + { + "config": { + "id": "isNull", + "options": {} + }, + "fieldName": "ip" + } + ], + "match": "any", + "type": "exclude" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": { + "Seen (sum)": 3, + "Time (max)": 0, + "Trapped (sum)": 4, + "country (lastNotNull)": 2, + "ip": 1 + }, + "renameByName": { + "Seen (sum)": "Connections", + "Time (max)": "Last Connection", + "Trapped (sum)": "Trapped Time", + "country (lastNotNull)": "Country", + "ip": "IP" + } + } + } + ], + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 38, + "tags": ["prometheus"], + "templating": { + "list": [ + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "definition": "label_values(endlessh_client_open_count_total, job)", + "hide": 0, + "includeAll": true, + "label": "Job", + "multi": true, + "name": "job", + "options": [], + "query": { + "query": "label_values(endlessh_client_open_count_total, job)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "Y4SSG429DWCGDQ3R" + }, + "definition": "label_values(endlessh_client_open_count_total{job=~\"$job\"}, instance)", + "hide": 0, + "includeAll": true, + "label": "Host", + "multi": true, + "name": "host", + "options": [], + "query": { + "query": "label_values(endlessh_client_open_count_total{job=~\"$job\"}, instance)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Endlessh", + "uid": "ATIxYkO7k", + "version": 1, + "weekStart": "" +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/loki.nix b/nyx/modules/core/roles/server/system/services/monitoring/loki.nix new file mode 100644 index 0000000..e64ed65 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/loki.nix @@ -0,0 +1,95 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = config.services.loki; +in { + config = mkIf sys.services.monitoring.loki.enable { + # https://gist.github.com/rickhull/895b0cb38fdd537c1078a858cf15d63e + services.loki = { + enable = true; + dataDir = "/srv/storage/loki"; + extraFlags = ["--config.expand-env=true"]; + + configuration = { + auth_enabled = false; + + server = { + http_listen_port = 3030; + log_level = "warn"; + }; + + ingester = { + lifecycler = { + address = "127.0.0.1"; + ring = { + kvstore = { + store = "inmemory"; + }; + replication_factor = 1; + }; + }; + chunk_idle_period = "1h"; + max_chunk_age = "1h"; + chunk_target_size = 999999; + chunk_retain_period = "30s"; + max_transfer_retries = 0; + }; + + schema_config.configs = [ + { + from = "2022-05-14"; + store = "boltdb"; + object_store = "filesystem"; + schema = "v11"; + index = { + prefix = "index_"; + period = "168h"; + }; + } + ]; + + storage_config = { + boltdb.directory = "${cfg.dataDir}/boltdb-index"; + filesystem.directory = "${cfg.dataDir}/storage-chunks"; + + boltdb_shipper = { + active_index_directory = "/srv/storage/loki/boltdb-shipper-active"; + cache_location = "/srv/storage/loki/boltdb-shipper-cache"; + cache_ttl = "24h"; + shared_store = "filesystem"; + }; + }; + + limits_config = { + reject_old_samples = true; + reject_old_samples_max_age = "168h"; + }; + + chunk_store_config = { + max_look_back_period = "0s"; + }; + + table_manager = { + retention_deletes_enabled = false; + retention_period = "0s"; + }; + + compactor = { + shared_store = "filesystem"; + working_directory = "${cfg.dataDir}/compactor-work"; + compactor_ring = { + kvstore = { + store = "inmemory"; + }; + }; + }; + }; + # user, group, dataDir, extraFlags, (configFile) + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/prometheus.nix b/nyx/modules/core/roles/server/system/services/monitoring/prometheus.nix new file mode 100644 index 0000000..4d75f98 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/prometheus.nix @@ -0,0 +1,97 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.monitoring.prometheus.enable { + services = { + # Prometheus exporter for Grafana + prometheus = { + enable = true; + port = 9100; + + # relatively frequent scraping intervals + globalConfig = { + scrape_interval = "10s"; + scrape_timeout = "2s"; + }; + + # enabled exporters + exporters = { + node = { + enable = true; + port = 9101; + enabledCollectors = ["systemd" "processes"]; + }; + + redis = { + enable = true; + port = 9102; + user = "redis"; + }; + + postgres = { + enable = true; + port = 9103; + user = "postgres"; + }; + + nginx = { + enable = false; + port = 9104; + }; + + smartctl = { + inherit (config.services.smartd) enable; + openFirewall = config.services.smartd.enable; + # Defaults: + user = "smartctl-exporter"; + group = "disk"; + port = 9110; + }; + }; + + scrapeConfigs = [ + # internal scrape jobs + { + job_name = "prometheus"; + scrape_interval = "30s"; + static_configs = [{targets = ["localhost:9100"];}]; + } + { + job_name = "node"; + scrape_interval = "30s"; + static_configs = [{targets = ["localhost:9101"];}]; + } + { + job_name = "redis"; + scrape_interval = "30s"; + static_configs = [{targets = ["localhost:9102"];}]; + } + { + job_name = "postgres"; + scrape_interval = "30s"; + static_configs = [{targets = ["localhost:9103"];}]; + } + { + job_name = "nginx"; + scrape_interval = "30s"; + static_configs = [{targets = ["localhost:9104"];}]; + } + { + job_name = "endlessh-go"; + scrape_interval = "30s"; + static_configs = [{targets = ["localhost:9105"];}]; + } + + # TODO: exterenal scrape jobs - over tailscale/wireguard mesh + ]; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/monitoring/uptime-kuma.nix b/nyx/modules/core/roles/server/system/services/monitoring/uptime-kuma.nix new file mode 100644 index 0000000..73de5b2 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/monitoring/uptime-kuma.nix @@ -0,0 +1,41 @@ +{ + config, + lib, + ... +}: let + domain = "up.notashelf.dev"; +in { + users = { + users.uptime-kuma = { + isSystemUser = true; + group = "uptime-kuma"; + }; + groups.uptime-kuma = {}; + }; + + systemd.services.uptime-kuma = { + serviceConfig = { + DynamicUser = lib.mkForce false; + User = "uptime-kuma"; + Group = "uptime-kuma"; + }; + }; + + services = { + uptime-kuma = { + enable = true; + settings = { + PORT = "4000"; + }; + }; + + nginx.virtualHosts."${domain}" = + { + locations."/" = { + proxyPass = "http://127.0.0.1:${toString config.services.uptime-kuma.settings.PORT}"; + proxyWebsockets = true; + }; + } + // lib.sslTemplate; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/networking/default.nix b/nyx/modules/core/roles/server/system/services/networking/default.nix new file mode 100644 index 0000000..8221523 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/networking/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./wireguard + ./headscale.nix + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/networking/headscale.nix b/nyx/modules/core/roles/server/system/services/networking/headscale.nix new file mode 100644 index 0000000..28ea2f1 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/networking/headscale.nix @@ -0,0 +1,171 @@ +{ + inputs', + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.networking.headscale.enable { + environment.systemPackages = [config.services.headscale.package]; + networking.firewall.allowedUDPPorts = [8086]; # DERP + + services = { + headscale = { + enable = true; + address = "127.0.0.1"; + port = 8085; + + settings = { + grpc_listen_addr = "127.0.0.1:50443"; + grpc_allow_insecure = false; + + server_url = "https://hs.notashelf.dev"; + tls_cert_path = null; + tls_key_path = null; + + # default headscale prefix + ip_prefixes = [ + "100.64.0.0/10" + "fd7a:115c:a1e0::/48" + ]; + + dns_config = { + override_local_dns = true; + magic_dns = true; + base_domain = "notashelf.dev"; + domains = []; + nameservers = [ + "9.9.9.9" # no cloudflare, nice + ]; + + /* + extra_records = [ + { + name = "idm.notashelf.dev"; + type = "A"; + value = "100.64.0.1"; # NOTE: this should be the address of the "host" node - which is the server + } + ]; + */ + }; + + acl_policy_path = pkgs.writeText "headscale-acl" (builtins.toJSON { + acls = [ + { + # Allow client --> server traffic + # but not the other way around. + # Servers face the internet, clients + # do so far less. + action = "accept"; + proto = "tcp"; + src = ["tag:client"]; + dst = ["tag:server:*"]; + } + ]; + + # Allow all users to SSH into their own devices in check mode. + ssh = [ + { + action = "check"; + src = ["autogroup:member"]; + dst = ["autogroup:self"]; + users = ["autogroup:nonroot" "root"]; + } + ]; + }); + + derp = { + server = { + enabled = true; + region_id = 900; + region_code = "headscale"; + region_name = "Headscale Embedded DERP"; + stun_listen_addr = "0.0.0.0:8344"; + }; + + urls = []; + paths = []; + + auto_update_enabled = false; + update_frequency = "24h"; + }; + + disable_check_updates = true; + ephemeral_node_inactivity_timeout = "30m"; + node_update_check_interval = "10s"; + + /* + db_type = "postgres"; + db_host = "/run/postgresql"; + db_name = "headscale"; + db_user = "headscale"; + db_port = 5432; # not ignored for some reason + */ + + metrics_listen_addr = "127.0.0.1:8087"; + + log = { + format = "text"; + level = "info"; + }; + + # TODO: logtail + logtail = { + enabled = false; + }; + + randomize_client_port = false; + }; + }; + + nginx.virtualHosts."hs.notashelf.dev" = { + forceSSL = true; + enableACME = true; + locations = { + "/" = { + proxyPass = "http://localhost:${toString config.services.headscale.port}"; + proxyWebsockets = true; + }; + + # see before + # possibly using the web frontend + "/web" = { + root = "${inputs'.nyxpkgs.packages.headscale-ui}/share"; + }; + }; + }; + }; + + systemd.services = { + # TODO: consider enabling postgresql storage + # postgresql is normally pretty neat, but unless you expect your setup to receive + # very frequent logins, sqlite (default) storage may be more performant + # headscale.requires = ["postgresql.service"]; + + create-headscale-user = { + description = "Create a headscale user and preauth keys for this server"; + + wantedBy = ["multi-user.target"]; + after = ["headscale.service"]; + + serviceConfig = { + Type = "oneshot"; + User = "headscale"; + }; + + path = [pkgs.headscale]; + script = '' + if ! headscale users list | grep notashelf; then + headscale users create notashelf + headscale --user notashelf preauthkeys create --reusable --expiration 100y > /var/lib/headscale/preauth.key + fi + ''; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/networking/wireguard/default.nix b/nyx/modules/core/roles/server/system/services/networking/wireguard/default.nix new file mode 100644 index 0000000..217e7ff --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/networking/wireguard/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./server.nix + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/networking/wireguard/server.nix b/nyx/modules/core/roles/server/system/services/networking/wireguard/server.nix new file mode 100644 index 0000000..3507517 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/networking/wireguard/server.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; + + dev = config.modules.device; + acceptedTypes = ["server" "hybrid"]; +in { + config = mkIf ((builtins.elem dev.type acceptedTypes) && cfg.networking.wireguard.enable) { + networking = { + nat = { + enable = true; + externalInterface = "ens3"; + internalInterfaces = ["wg0"]; + }; + + firewall = { + allowedUDPPorts = [51820]; + trustedInterfaces = ["wg0"]; + }; + }; + + boot.kernelModules = [ + "wireguard" + ]; + + # Wireguard Server Peer Setup + networking.wireguard = { + enable = true; + interfaces = { + wg0 = { + # General settings + privateKeyFile = config.age.secrets.wg-server.path; + listenPort = 51820; + + # IPs + ips = [ + "10.255.255.10/24" # v4 general + "10.255.255.254/24" # v4 adtl + "fe80::10/64" # v6 link local + "2a01:4f9:c010:2cf9:f::10/80" #v6 general + "2a01:4f9:c010:2cf9:f::ffff/80" #v6 adtl + ]; + + # Peers + peers = [ + # enyo + { + allowedIPs = [ + "10.255.255.11/32" + "fe80::11/128" + "2a01:4f9:c010:2cf9:f::11/128" + ]; + publicKey = "u5Riuu4NEWEH06qATdnrPO+LacZTspoghqMnoWQ+uEQ="; + } + ]; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/networking/wireguard/wg-quick.nix b/nyx/modules/core/roles/server/system/services/networking/wireguard/wg-quick.nix new file mode 100644 index 0000000..09ab0df --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/networking/wireguard/wg-quick.nix @@ -0,0 +1,33 @@ +{ + config, + lib, + ... +}: { + networking = { + firewall.allowedUDPPorts = [51820 51821]; + + nat.internalInterfaces = ["wg0"]; + + wireguard.interfaces = { + wg0 = { + ips = ["10.0.0.1/24"]; + listenPort = 51820; + privateKeyFile = config.age.secrets.wireguard.path; + peers = [ + { + # enyo + publicKey = "vv190fxSVr+u7Zv0ujPcwE4aYs0QcbObHwzWGwUNSUA="; + allowedIPs = ["10.0.0.2/32"]; + } + /* + { + # test + publicKey = ""; + allowedIPs = ["10.0.0.3/32"]; + } + */ + ]; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/nextcloud.nix b/nyx/modules/core/roles/server/system/services/nextcloud.nix new file mode 100644 index 0000000..429b1fa --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/nextcloud.nix @@ -0,0 +1,167 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + domain = "cloud.notashelf.dev"; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.nextcloud.enable { + modules.system.services = { + nginx.enable = true; + database = { + redis.enable = true; + postgresql.enable = true; + }; + }; + + services = { + nextcloud = { + enable = true; + package = pkgs.nextcloud28; + + nginx.recommendedHttpHeaders = true; + https = true; + hostName = domain; + + home = "/srv/storage/nextcloud"; + maxUploadSize = "4G"; + enableImagemagick = true; + + extraApps = let + inherit (config.services.nextcloud.package.packages) apps; + in { + # wtf is this formatting + inherit (apps) mail polls onlyoffice contacts calendar tasks bookmarks deck forms cookbook impersonate groupfolders; + }; + + autoUpdateApps = { + enable = true; + startAt = "03:00"; + }; + + caching = { + apcu = true; + memcached = true; + redis = true; + }; + + config = { + # admin user settings + # only effective during setup + adminuser = "notashelf"; + adminpassFile = config.age.secrets.nextcloud-secret.path; + + # database + dbtype = "pgsql"; + dbhost = "/run/postgresql"; + dbname = "nextcloud"; + dbuser = "nextcloud"; + }; + + settings = { + "memories.exiftool" = "${lib.getExe pkgs.exiftool}"; + "memories.vod.ffmpeg" = "${pkgs.ffmpeg-headless}/bin/ffmpeg"; + "memories.vod.ffprobe" = "${pkgs.ffmpeg-headless}/bin/ffprobe"; + + # be very specific about the preview providers + enabledPreviewProviders = [ + "OC\\Preview\\BMP" + "OC\\Preview\\GIF" + "OC\\Preview\\JPEG" + "OC\\Preview\\Krita" + "OC\\Preview\\MarkDown" + "OC\\Preview\\MP3" + "OC\\Preview\\OpenDocument" + "OC\\Preview\\PNG" + "OC\\Preview\\TXT" + "OC\\Preview\\XBitmap" + "OC\\Preview\\HEIC" + ]; + + # run maintenance jobs at low-load hours + # i.e. 01:00am UTC and 05:00am UTC + maintenance_window_start = 1; + + # force https + overwriteprotocol = "https"; + trusted_domains = ["https://${toString domain}"]; + trusted_proxies = ["https://${toString domain}"]; + + redis = { + host = "/run/redis-default/redis.sock"; + dbindex = 0; + timeout = 3; + }; + + # other stuff + default_phone_region = "TR"; + lost_password_link = "disabled"; + }; + + phpOptions = { + "opcache.enable" = "1"; + "opcache.enable_cli" = "1"; + "opcache.jit" = "1255"; + "opcache.jit_buffer_size" = "256M"; + "opcache.validate_timestamps" = "0"; + "opcache.save_comments" = "1"; + + # fix the opcache "buffer is almost full" error in admin overview + "opcache.interned_strings_buffer" = "16"; + # try to resolve delays in displaying content or incomplete page rendering + "output_buffering" = "off"; + + "pm" = "dynamic"; + "pm.max_children" = "50"; + "pm.start_servers" = "15"; + "pm.min_spare_servers" = "15"; + "pm.max_spare_servers" = "25"; + "pm.max_requests" = "500"; + }; + + phpExtraExtensions = ext: [ext.redis]; + }; + + nginx.virtualHosts."cloud.notashelf.dev" = + { + quic = true; + http3 = true; + } + // lib.sslTemplate; + }; + + systemd.services = { + phpfpm-nextcloud.aliases = ["nextcloud.service"]; + "nextcloud-setup" = { + requires = ["postgresql.service"]; + after = ["postgresql.service"]; + serviceConfig = { + Restart = "on-failure"; + RestartSec = "10s"; + }; + }; + + /* + "nextcloud-preview" = { + description = "Generate previews for all images that haven't been rendered"; + startAt = "01:00:00"; + requires = ["nextcloud.service"]; + after = ["nextcloud.service"]; + path = [config.services.nextcloud.occ]; + script = "nextcloud-occ preview:generate"; + + serviceConfig = { + Restart = "on-failure"; + RestartSec = "10s"; + }; + }; + */ + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/nginx/default.nix b/nyx/modules/core/roles/server/system/services/nginx/default.nix new file mode 100644 index 0000000..1082d1c --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/nginx/default.nix @@ -0,0 +1,168 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.modules) mkIf mkDefault; + inherit (lib.strings) fileContents; + + sys = config.modules.system; + cfg = sys.services; + + inherit (config.networking) domain; +in { + config = mkIf cfg.nginx.enable { + security = { + acme = { + acceptTerms = true; + defaults.email = "me@notashelf.dev"; + }; + }; + + services = { + nginx = { + enable = true; + package = pkgs.nginxQuic.override {withKTLS = true;}; + + # makes /nginx_status endpoint available t o localhost + statusPage = true; + + recommendedTlsSettings = true; + recommendedBrotliSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedProxySettings = true; + recommendedZstdSettings = true; + + clientMaxBodySize = mkDefault "512m"; + serverNamesHashBucketSize = 1024; + appendHttpConfig = '' + # set the maximum size of the headers hash tables to 1024 bytes + # this applies to the total size of all headers in a client request + # or a server response. + proxy_headers_hash_max_size 1024; + + # set the bucket size for the headers hash tables to 256 bytes + # bucket size determines how many entries can be stored in + # each hash table bucket + proxy_headers_hash_bucket_size 256; + ''; + + # lets be more picky on our ciphers and protocols + sslCiphers = "EECDH+aRSA+AESGCM:EDH+aRSA:EECDH+aRSA:+AES256:+AES128:+SHA1:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL"; + sslProtocols = "TLSv1.3 TLSv1.2"; + + commonHttpConfig = '' + # map the scheme (HTTP or HTTPS) to the HSTS header for HTTPS + # the header includes max-age, includeSubdomains and preload + map $scheme $hsts_header { + https "max-age=31536000; includeSubdomains; preload"; + } + + # add the Referrer-Policy header with a value of "no-referrer" + # which instructs the browser not to send the 'Referer' header in + # subsequent requests + add_header "Referrer-Policy" "no-referrer"; + + # adds the Strict-Transport-Security header with a value derived from the mapped HSTS header + # which instructs the browser to always use HTTPS instead of HTTP + add_header Strict-Transport-Security $hsts_header; + + # sets the path for cookies to "/", and adds attributes "secure", "HttpOnly", and "SameSite=strict" + # "secure": ensures that the cookie is only sent over HTTPS + # "HttpOnly": prevents the cookie from being accessed by JavaScript + # "SameSite=strict": restricts the cookie to be sent only in requests originating from the same site + proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict"; + + # define a new map that anonymizes the remote address + # by replacing the last octet of IPv4 addresses with 0 + map $remote_addr $remote_addr_anon { + ~(?P\d+\.\d+\.\d+)\. $ip.0; + ~(?P[^:]+:[^:]+): $ip::; + default 0.0.0.0; + } + + # define a new log format that anonymizes the remote address + # and adds the remote user name, the time, the request line, + log_format combined_anon '$remote_addr_anon - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent"'; + + # write the access log to a file with the combined_anon format + # and a buffer size of 32k, flushing every 5 minutes + access_log /var/log/nginx/access.log combined_anon buffer=32k flush=5m; + + # define a new log format that anonymizes the remote address + # and adds remote user name, local time, the request line and http3 + # this is important for debugging quic enabled requests + log_format quic '$remote_addr_anon - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" "$http3"'; + + # write the access log to a file with the quic format + access_log /var/log/nginx/quic-access.log quic; + + # error log should log only "warn" level and above + error_log /var/log/nginx/error.log warn; + ''; + + virtualHosts = { + "${domain}" = { + default = true; + serverAliases = ["www.${domain}"]; + + locations = let + commonConfig = '' + try_files $uri $uri/ =404; + + default_type text/plain; + charset utf-8; + ''; + + # takes a path to a file and returns a + # configuration for a location that serves that file + mkStaticPage = { + name, + root, + header ? "", + footer ? "", + }: let + builtIndex = pkgs.writeTextDir "${name}" '' + ${header} + ${fileContents root} + ${footer} + ''; + in { + index = name; + root = builtIndex.outPath; + extraConfig = commonConfig; + }; + in { + # root location + "/" = mkStaticPage { + root = ./static/root.txt; + name = "root.txt"; + header = builtins.readFile ./static/header.txt; + footer = "> served by ${pkgs.nginx.outPath}"; + }; + + # /gpg endpoint for my gpg key + "/gpg" = mkStaticPage { + name = "gpg.txt"; + root = ./static/gpg.txt; + }; + }; + }; + }; + }; + + logrotate.settings.nginx = { + enable = true; + minsize = "50M"; + rotate = "4"; # 4 files of 50mb each + compress = true; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/nginx/static/gpg.txt b/nyx/modules/core/roles/server/system/services/nginx/static/gpg.txt new file mode 100644 index 0000000..4c018b4 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/nginx/static/gpg.txt @@ -0,0 +1,109 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBGSPW8UBEADcTMSnVlcCo19szLa1Lr5pHP7w+7pd+W+msaNBYkIC1d6FPAvK +PgAJVaRb1fHll2y8MRQXdYmkNwu1L0w57TK/Sm7/vdCAJ2BUYdwMmTY55vOZNQod +aAMPHRLjIGxAYt3HzgwePrTzXG1HtO/Vt7y9//9UJ+ZUGZ/fNmZCkFm9JTYmNpvc +Ami52IEOB/TGI4fwLODMX7q0MHMZQKthlrSfGebr283AOEamx18h5I8xGYp4bKt0 +cOwNURRkeGz/o0vQ41qQfgk9Virt/Pvxk5VJnV+hE81bclIIVsWY/xUTGEX7sw+b +vZg3RemI3IX4+nFe0llBWsrXVAFvivuMMv1m7GcpAO2c0QjtrazhNJpgfJa8aPXC +jSOoNxhCmWhTMpnudzKuIF+5xTJmvrzNbfcw5xzlPC52gvmiGtvOko34WWB3QbVY +BNxeVznUUAJqJz5AV+EjDQjGhpottY1j1/hYwH/MpwGjSyQMFdY7ZOK3/5/wIpnz +zQrTKO9aSPD5f87dSRTkGvI3Z53erpOpQHS8/cWIwTqp2Ht2lRu2lunfZ7MfA7HA +i/c1AHYIYFLONoVpDaDPlsyhcXbiMZ/bmg+wmlIhg4cEZGkjBco56fMOur+CTSl9 +5ylYWuKHR3oykOyxeHcqytM1/92oW/QrcLIU67r0HfaDRj4vQtEr5XamIQARAQAB +tB1Ob3RBU2hlbGYgPHJhZkBub3Rhc2hlbGYuZGV2PokCUgQTAQoAPBYhBF4bNk6K +zTPvDzln5LpGvMNukSkiBQJkj1vFAhsBBQkB4TOABAsJCAcEFQoJCAUWAgMBAAIe +BQIXgAAKCRC6RrzDbpEpInanEACaj0K5mPmqVRPwNBxwXDXYgoa0cwmP+5OZVKce +xTgDvkpTAItWrcdqXN8gYROSr0dymnWkRbvgzVLxny9TpO0dRGgg8b+ZCl6fAjgl +oN5818zm9Tj8HhTNXMr9770QLWjAd8+LTMeOLsXmzRXVx5nQn2H545PGeCxkIlBP +mwZLlPN99OW3vnv1HNzOlo4s9VqbycZQZS8i2MoaWX0ZDYtT5p4+d2wy+JEGJRoB +cb/gcHfUXk1nit7o+MxzwaE30wMFezZ3i4ufOGv1Iab6gdO+kGvXEIO4ybxQmB5Z +B4BzB2NsFvoD1gUul4RSdK8Rlp3Bs+ldzhZuqSFR75sAqwGrxI0Ub2KQCTSuVe8Q +AC5x8qcKJG6DfMV33s7+6ICqFdcs8KoBJCONYFAbwIlia31UcU9KGURwU5gChHIL +l5lzqD7/cs0FkltJuzjG942DGPkQHFmWmkmdI6690wHwg2EBJkQQyXRGiamOaCK9 +aXbX2MAGbY2bu+2Xw9L/wrh2GTbp34nunCCaQ7TGaGXImIIZOrK9htI9+u1uuSBo +G7REn+h8fua4AJ1NIu6LK3+G+2kCZVnxUr2mJ5n25O2EWsxkDK4syXtUGgcCQN0U +pjr1Bn3PcVvmznF2taGHxd7FXfmHXCTUsoUXwD8aSWb/veDXLb3ZvS9Jo0TtVVrH +avMRyrkCDQRkj1wTARAAvKtVro4KZKQq/aeZTW5ECsz5+Wpvmrqva/iTKQeXqspY +z1hjkXHeh0wDUY80IUDDR7wKkGm83pzHwq+cjXNytzPymXa+1b0yuUa97XRCb+kr +uW/w/LUds/mCNgkD4ps8cH0/WlApy7NXXiGG1Gf8/2K7z6GdJXb4A5LH2QqcQ5ix +0Tn+zTRRZUI1+PUMT8hJHeX+eaMc+shKnT1VZWHesLuzAmNkuYQdZ6LxyXm4Ocnm +dZ0/cpP4YzYFi0QWqbAji3CzFcxqJ9bCULy5jT3udgu+cDDI0nhIz1Dt7pSmJLx4 +9H7jmPD2Sln+69wWkGk1okQkMym6fZ5GYGSzrKkcdc42rRMVCfUJ7PWMQ2Xvv4Wu +gxVQp76GAYYwJ1i7GDqxT1UoS6c98Zou1GQzcCjaNiEGUduA/SuOE8BHI5SWU17s +Lf91r4gEgaMvo2ieB86azHcmaUC6SpDMOYJrj4V8ufn7jnsvGqPPI6sNBOyBu5Vo +097Wzd8cAFVTj3ezX8Rq5yzBZr5cPKZnpCOJxrSymZTKd2QJVQIbCnP/mpLMPswq +aavuCQUgiqSXZ7U7OxvweN9E7Fn3Vb+Uq1gm/sOkD15+Im3DiUbxpifTaYlmFtDk +Bglai/Kak4I6RmUXkWlfUoYaFzM74O/mUb+30LD4Ap0SQjqiDoImJj499eOCHt8A +EQEAAYkEcgQYAQoAJhYhBF4bNk6KzTPvDzln5LpGvMNukSkiBQJkj1wTAhsCBQkB +4TOAAkAJELpGvMNukSkiwXQgBBkBCgAdFiEERj+D8ob3yxzaZG3KAtHdP6CLaykF +AmSPXBMACgkQAtHdP6CLaymGbQ/+Oc5WQPQ+DVeanbeHggXv+zMkX+aayuOQWkAc +kZIUSn/3ZfJurJPdjSsuatYmN3lGaa1m6RgDDg5RBctHq6j7zv66Z2jEVL1+yWCt +VP60MauY22a2DVNqwjbBpIXE9tEb1Pjy320+c8p/SS03R0ShtiUJBCYgmPRou2k+ +XmpdU1dZJN5Bp5io2pOLcjqfAN5DWAqp+lKbbNmpskoa+PBZdFH4bkRojmQWO04U +uasa6yimPmpe9ZoynVPobNKPHWiUkRHKWz7dwGHNjts0CM6kbVe7q0T0mHLXgiLm +oO6gImOHfP1YBoNJ1KBeJ4/L9WF3/iXhDaGJqZ3ArUrw1r3B96s8b//k8OK/EGbL +9f3rFc9heN2SeTGCeFskYfeeCTvWKXHPI9oZ+2XM3cfYAfkO74BFS9/ETHWYZL66 +1A3FCxUCmnoZoW5oNumfK9Hbxyukg/wFMLSE3L9Mv3f4vsrrTeko3tNWFK0FhzCW +atpQX1c9HCfKflWCwZH/U19gcqXEMFcFdnxvTq4XcFbvDxtk/2gXqS6rTggwHufx +IggD9/aFgwC2w7a4GzWnYGbC/dOb3hy1tdXGLv/y6aavD8CrbDQ/SXARoIPgcETo +/RsLMqOPG+jPC5+3SFr8xVDT+8+Hh90AQ2Ebx7vbTjEPO5rjgq4zSeQaBF/+sHLn +dya6rU7a2g//S9+V0e4/IyBLYjxdHGyocmNoujVRoR1E9WII3zYh4jm0qLzjDEk4 +VfZ4t9VBqWat5fimqVwF68Z6KKoBo26TEuWDok3kzD6iLt6TqvPUiE4R2V+qO8dD +Gg95ZO7tAZXhFuq1/xSf0KIpfeCJ5PxisrxjZmVgcMM0gyae05rrxpWcaxiawlCl +0oPNN5oFfBwq1d94g/wJ2qywbVTnCjFhN7fl494C5rMRXeBo996XttlvILCci98U +m1xecq3vG6ZBGxwNe61NXkTtOZrJzoXTI9WHez0YJS0uXhlUmVy4T9r05UQWbzoT +hV2MSIEqdvE67K+MpLNhdTuSH/4zVug5/G4eMfxGi2fgzgm3WW862dpfUh2GQFuf +VfpBxWcdN7zffi44v509BnJe0kJmyPYgcvtmbigrsXLQjA2WM0QA1/Gi6IAPWcUc +KNvqZbsr3w2PZU6rrKEwDHlm2Lj9qyJFS53eImdaw7NnJBp4ujsC6abSCjkR7/gM +3qXS67cTcd1PeW4ephvMUVWSoy5bnhw2WwT2gPYX2diQWjbRIkuPl74foA4BM5XF +RpGozEV8ID3BqMWkYTbck0njpYr0h3SMw472tcMWtVVbeK2C4sLu3cTyxQtbgmXd +lrPzUVzOONGAygI9uleRYNMM58zNa/fLqHqf56ALcGTXybs97ko17be5Ag0EZI9c +JgEQAKFovIAsXHzUm2yFlPK/+XsHe7JvHHAbQqC1OTHz6DLT3/ADSqB/lLYGVKDA +ubPwc+5f+xWM3zBZchWbye9eoZ1TFNLnayXtKkoOY220u8uK4v3+o72Xj5B7CDLB +VIEPfDnAIXd2kc3X5l3LFzsiiM0joFSaoChdALAZpH8QLAxOGo68DuxvkVwjxpbH +fUxLahuKyiP375FTA1lV4WEV1f8+IJ5QxBPhDZG2rodV7ZlX05QzEMaxMoTRWiiB +WJ0U2nar4MXFbjPgxQkIcMxd2bfvcasi3GIVIkLmdE8PnMhmN/eO5xfWJgW7bYoJ +wA5tEGaX9mD+32yD/WTk2XyP9MS2e+RNFjBuNKNeVbnEzio31va8DiQ2JSB8mXkb +43jdBUnf/wPaHAx5CQG5mLUpmm2MpT6pTffHAwUdpejwfIFcU0rmFtq3ypKGKk2W +jjxbUBv+fGOAgyLcu5l8WWlZaBS2gN6TF43JAKw/arCTBVig+RHGcvlUhFqj4N/7 +5ese12s4yp+qUsg/Om5gDsfNEl5ZgaG4+ymmaG6WTl04qi9LsIGAmV90CcQkaoab +ipC8vibm82vus7AzTgZKWKD0l3OQtYw6FlhY0H0lDBs6v6Tn1Y9i7nMbS2cikSqP +Wi5/awq4C4Lu9sjT4+FK5IokzWOi0VzUtrJO42w0IOTl9WqRABEBAAGJAjwEGAEK +ACYWIQReGzZOis0z7w85Z+S6RrzDbpEpIgUCZI9cJgIbDAUJAeEzgAAKCRC6RrzD +bpEpIsDmEACgRFbI26SrZnKJ99UGPFbDkx+PT5237qaWTssK0BKADZ+uXDRHrGeN +8sJhiKK2L6nsuSmtHTkUVUuNEqA8bxSGGq231JBja8tdhqqV0TGMz6t9q7ZC/HsW +TBtsbgj8aSjkCzgRaYj7zlDrtrN//Z2vniNgk/5z4nxWx/crbuVI8utJrddXETsP +Q/bnpWcbI67bOWPF5Ku2sv65sxgYp7WFvMhF9Gov7+VE1rimkXb6nkjVSadlNafE +n8U16CnEDQRVhxaIbylGdsGBgUO1p/mReAv+XFJT/LN+xDKMgvJtazQK++bzwB/b +E7fvnbaEt5aTmEdwcP+zZhSIX0qpNvpCmH9l+nT+Xdy3pLFdd59S+N50Jm5oRP59 +aZYjaDYxlQMf4Jc+dIrVvMtksmBc+mphevkLk3eKM8eXyUmaOqjZO11bxHcE/Z1a +7e3WA3GzpL5IE4sdNEYwLaIjzbaMJ/B+oeZ9lTa5lZSINStl691mCNi2xgalVEza +JS7gS7UThCHmvYAdJpKeSEOh4FrMknsA6DaQjmcOymperK4qInNTusgnHvEiTaGH +4gJ5ylJ6B8XZDdIuVG8pfV7Kjlgo+iTDumvcx3Po1QRh1kL+qdj5k19l0V0Lfwi0 +cgKHWU5iZSLhu6Rbn+RgboxNN2sg0uHgGT63+8HyjTMcdg8MtiXKW7kCDQRkj1w1 +ARAAv+YZ+B8ijdsTwZVVztHTPuHYpe/RL4kv4JOFf0W9+J+emp1t1wRtxJAFPzu/ +lfG7T11ab7V/tg3q99fSxhLDsmspv4mNI0MB4JUv5xFf7AnNkod16JmTKmVEjgcj +vtGEsR3DzY0/Q4FT8baYbCk+YouxChu3Sm9YJFjOYzt7Vu/q0ESWM8tGpM9uz8FQ +RmAlWl57tsOBZwR0167EKeLPbp+fLQtNXToHi4neZi7UKhysLyQq2bvE6LOZ42cE +jGtU6mcVmdg6cHKBaxbDKdQlhf+cVjR2ngxFq3ok+/r5M/aH24YC0tOaXheXeG0u +mahQzVUbILei/BzqqWpdLd3GV43YQHYlKGplYT2OrX+DBGh89sn3XVL8DZuAInPm +j2uq3e23uEJHdwUF31cvHM7MntQcHQqDRYvNIkr2koz6EDkeaxT987g4xNXvtQZY +yL4uxDCErRDnAC9cqXwfCVfGzztvXBsQIikSnv/Ifv0ZsuOo5mo8Eiw0PWABIKne +O2C5MIWyOyuJJj+dhIzETu/rTH/9J5illHpy/ZJnGfbGz/c6cemTHfyFuVoWW3Wn +kPVERAR+Nb7/L9eZQVZY6sg4bNBv0sCHxwUrD/1kM+IvVcndVug3OxnUhB4+Bb/V +ZvhXH895Pk9V9epRKO0Bk+3vTEReUSq/u/tFFfyiD5cTbk8AEQEAAYkCPAQYAQoA +JhYhBF4bNk6KzTPvDzln5LpGvMNukSkiBQJkj1w1AhsgBQkB4TOAAAoJELpGvMNu +kSkia48QAJts/EAObyO1jGyuUwnEfDugHKRl3WT6jxOUoZiKrogkFmloGRMi6aw4 +2WF+TXrMwhQc39+qMicdqwjnjs1SVYngkrzmg8bCUcuJAvO2eTM4ukmynKTVgIBW +e0/WSYw8NG08m9Uh3YfCbJ0OZKaC7tewQPs7JgjA+TPvOpEcfhRve449SX0+x0Vh +ahDeGqeZZW/xfGJ4v2PsVCYPCj2Xrj/UP4P8H4tb23QWB5yCr/HhFxt0+Sm0go6w +/HUm2mdbVwngd2k6P4pz8TPpclfTUmCHVbcWrzMNmb4k1piMrF6a60n6ULBP8X04 +i9PW3a+Z3WvK92x5NhAjYDJ+QR1Q90L6uK6jdBcs1FwsQNFSXeMwyA5EYKTqarM8 +W0/4JiR1UmoerVXZAEo332UMg11ivbISH8gJTe7ImorT6F4dUtOBVsC6CtmYSxZ6 +ut5i9QuwHuyI7yJGk2jGRyshAmZslqCqSUJRhi8ajgk9azc60M3QOqmBLDAmQHzz +hKEB6tFwl+GwlozvzSfeUJNo8oR2dOY2v+/cZ0JCEvMqlmTZttqSyY4pM+0SAc4c +KNvlXqQdE86Zjq9LGVaHvJFnXbdERn+e0dJIaU13XFT52jMFGAnl5mOlfuVVq3QO +YDjs3k+jOpkNZLwDQrF7RpATQiP1/+0tW6KRajlO4ss/KIBv5RN/ +=QQXP +-----END PGP PUBLIC KEY BLOCK----- diff --git a/nyx/modules/core/roles/server/system/services/nginx/static/header.txt b/nyx/modules/core/roles/server/system/services/nginx/static/header.txt new file mode 100644 index 0000000..ef18b6b --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/nginx/static/header.txt @@ -0,0 +1,5 @@ + _ _ _ __ + _ __ ___ | |_ __ _ ___| |__ ___| |/ _| +| '_ \ / _ \| __/ _` / __| '_ \ / _ \ | |_ +| | | | (_) | || (_| \__ \ | | | __/ | _| +|_| |_|\___/ \__\__,_|___/_| |_|\___|_|_|.dev diff --git a/nyx/modules/core/roles/server/system/services/nginx/static/root.txt b/nyx/modules/core/roles/server/system/services/nginx/static/root.txt new file mode 100644 index 0000000..eda305b --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/nginx/static/root.txt @@ -0,0 +1,90 @@ +Howdy! + +I'm raf, more commonly known as NotAShelf on most online spaces. This +is my personal webpage, which is actually pure plaintext due to my utmosts +disdain for modern web technologies. + +Frequently Asked Questions + +*** + +Q: What do you do for a living? + +A: I am a professional sailmaker. I design, manufacture and sell sails. I also +work as a part-time Political Science instructor for the time being. Sometimes +I do digital art, other times I do sailing as a sport. + +*** + +Q: Did you study Computer Science? Why do you know programming? + +A: No, I graduated as an International Relations major. I've been teaching +myself programming and Linux system administration since 2018. I mostly enjoy +open-source software, and my primary stack (as of now) is mostly backend +development in Go. Programming is something I enjoy as a tool to help me get +from point A to point B, which is why I am interested in learning new +technologies as much as I can. + +*** + +Q: How are the International Relations? + +A: They're good, thanks for asking. + +*** + +Q: What programming languages do you know? + +A: I mostly work with JavaScript, Typescript, Go, C and Nix. I also have some +experience with Rust, C++ and Python. There are other languages I've used, but +don't really consider noteworthy. I hate PHP. PHP probably hates me back. Good. + +*** + +Q: What do you do now? + +A: I am currently working on my PhD in Political Science where I conduct +research on the impact of digital technologies on political participation and +executive functions as well as the effects of open-source software. on said +fields. I would love to go into further detail but I also would like to avoid +doxxing myself. Just know that I get the prefix of "Doctor" when I'm done. + +I frequently work with Nix and NixOS, embedded programming and Linux systems +in general. I also do some web development in my free time. + +*** + +If you want to contact me for any reason, you may just shoot me an email +@ raf [at] notashelf [dot] dev. In case you were unable to reach me +via email (e.g. your smtp server uses an outdated cipher, or my domain is +blacklisted by your provider), you may contact me via Matrix or Mastodon using +the links below. I am also on Discord, going by the same handle as my github +username. My public gpg key is available at https://notashelf.dev/gpg which +is also in plaintext. If you're a bot, you're probably having a field day. + +On that note, please stop scraping my website. I **do not** have anything +of your interest. + +*** + +List of stuff you might find interesting if you came here and are a human: + +- E-mail | raf [at] notashelf [dot] dev +- Matrix | https://matrix.to/#/@raf:notashelf.dev +- Mastodon | https://social.notashelf.dev/ +- Github | https://github.com/notashelf + - https://github.com/schizofox/schizofox + - https://github.com/hyprland-community/hyprkeys + - https://github.com/notashelf/catApi + - https://github.com/notashelf/neovim-flake + + +If you have found a vulnerability on this server, I'd be very grateful if you +told me about it. Contact me through any of the ways above. + +*** + +I can't have a footer but this is a good place to put a shoutout to the +awesome motherfuckingwebsite.com. + +*** diff --git a/nyx/modules/core/roles/server/system/services/reposilite.nix b/nyx/modules/core/roles/server/system/services/reposilite.nix new file mode 100644 index 0000000..8ec521f --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/reposilite.nix @@ -0,0 +1,46 @@ +{ + config, + lib, + inputs', + ... +}: let + inherit (lib) mkIf sslTemplate; + + sys = config.modules.system; + cfg = sys.services; + + inherit (cfg.reposilite.settings) port; +in { + config = mkIf sys.services.reposilite.enable { + modules.system.services = { + nginx.enable = true; + }; + + services.reposilite = { + enable = true; + package = inputs'.nyxpkgs.packages.reposilite-bin; + dataDir = "/srv/storage/reposilite"; + + openFirewall = true; + + user = "reposilite"; + group = "reposilite"; + + settings = { + inherit port; + }; + }; + + services.nginx.virtualHosts = { + "repo.notashelf.dev" = + { + locations."/".proxyPass = "http://127.0.0.1:${toString port}"; + extraConfig = '' + access_log /var/log/nginx/reposilite-access.log; + error_log /var/log/nginx/reposilite-error.log; + ''; + } + // sslTemplate; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/searxng.nix b/nyx/modules/core/roles/server/system/services/searxng.nix new file mode 100644 index 0000000..2e693af --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/searxng.nix @@ -0,0 +1,146 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; + + inherit (cfg.searxng.settings) host port; +in { + config = mkIf cfg.searxng.enable { + networking.firewall.allowedTCPPorts = [port]; + + modules.system.services = { + nginx.enable = true; + database.redis.enable = true; + }; + + users = { + users.searx = { + isSystemUser = true; + createHome = false; + group = lib.mkForce "searx-redis"; + }; + + groups.searx-redis = {}; + }; + + services = { + searx = { + enable = true; + package = pkgs.searxng; + environmentFile = config.age.secrets.searx-secretkey.path; + settings = { + use_default_settings = true; + + general = { + instance_name = "NotASearx"; + privacypolicy_url = false; + donation_url = "https://ko-fi.com/notashelf"; + contact_url = "mailto:raf@notashelf.dev"; + enable_metrics = true; + debug = false; + }; + + search = { + safe_search = 0; # 0 = None, 1 = Moderate, 2 = Strict + formats = ["html" "json" "rss"]; + autocomplete = "google"; # "dbpedia", "duckduckgo", "google", "startpage", "swisscows", "qwant", "wikipedia" - leave blank to turn it off by default + default_lang = "en"; + }; + + server = { + inherit port; + method = "GET"; + secret_key = "@SEARX_SECRET_KEY@"; # set in the environment file + limiter = false; + image_proxy = false; # no thanks, lol + default_http_headers = { + X-Content-Type-Options = "nosniff"; + X-XSS-Protection = "1; mode=block"; + X-Download-Options = "noopen"; + X-Robots-Tag = "noindex, nofollow"; + Referrer-Policy = "no-referrer"; + }; + }; + + ui = { + query_in_title = true; + theme_args.simple_style = "dark"; # auto, dark, light + results_on_new_tab = false; + }; + + redis = { + url = "unix://searxng:localhost@/run/redis-searxng?db=0"; + #url = "unix:///run/redis-searxng/redis.sock?db=0"; + #url = "redis://searxng@localhost:6370/0"; + }; + + outgoing = { + request_timeout = 15.0; + max_request_timeout = 30.0; + }; + + engines = [ + { + name = "wikipedia"; + engine = "wikipedia"; + shortcut = "w"; + base_url = "https://wikipedia.org/"; + } + { + name = "duckduckgo"; + engine = "duckduckgo"; + shortcut = "ddg"; + } + { + name = "google"; + engine = "google"; + shortcut = "g"; + use_mobile_ui = false; + } + { + name = "archwiki"; + engine = "archlinux"; + shortcut = "aw"; + } + { + name = "github"; + engine = "github"; + categories = "it"; + shortcut = "gh"; + } + { + name = "nixpkgs"; + shortcut = "nx"; + engine = "elasticsearch"; + categories = "dev,nix"; + base_url = "https://nixos-search-5886075189.us-east-1.bonsaisearch.net:443"; + index = "latest-31-nixos-unstable"; + query_type = "match"; + } + ]; + }; + }; + + nginx.virtualHosts."search.notashelf.dev" = + { + locations."/".proxyPass = "http://${host}:${toString port}"; + extraConfig = '' + access_log /dev/null; + error_log /dev/null; + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + ''; + + quic = true; + } + // lib.sslTemplate; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/social/default.nix b/nyx/modules/core/roles/server/system/services/social/default.nix new file mode 100644 index 0000000..4cb4394 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/social/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./matrix.nix # matrix communication server + ./mastodon.nix # decentralized social + ]; +} diff --git a/nyx/modules/core/roles/server/system/services/social/mastodon.nix b/nyx/modules/core/roles/server/system/services/social/mastodon.nix new file mode 100644 index 0000000..488d9a6 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/social/mastodon.nix @@ -0,0 +1,106 @@ +{ + inputs', + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services.social; +in { + config = mkIf cfg.mastodon.enable { + modules.system.services = { + elasticsearch.enable = true; + database = { + postgresql.enable = true; + redis.enable = true; + }; + }; + + services = { + mastodon = { + enable = true; + package = inputs'.nyxpkgs.packages.mastodon-bird-ui; + + user = "mastodon"; + + configureNginx = false; + trustedProxy = "127.0.0.1"; + localDomain = "social.notashelf.dev"; + streamingProcesses = 2; + + webPort = 55001; + sidekiqPort = 55002; + enableUnixSocket = true; + sidekiqThreads = 12; + + elasticsearch.host = "127.0.0.1"; + + redis = { + createLocally = false; + host = "localhost"; + port = 6372; + }; + + database = { + createLocally = true; + host = "/run/postgresql"; + name = "mastodon"; + user = "mastodon"; + }; + + # configure smtp + smtp = { + authenticate = true; + createLocally = false; + fromAddress = "noreply@notashelf.dev"; + user = "noreply"; + host = "mail.notashelf.dev"; + passwordFile = config.age.secrets.mailserver-noreply-secret.path; + }; + + # extra config + extraConfig = { + SINGLE_USER_MODE = "true"; + WEB_DOMAIN = "social.notashelf.dev"; + AUTHORIZED_FETCH = "true"; + }; + }; + + # this does what configureNginx option under the mastodon service is supposed to + # to be able to fine-grain the service, we move it to its own configuration block + # and also, I don't trust nixpkgs maintainers to properly maintain a service - so this is a safety net + # in case they break another thing without proper documentation + # /rant + nginx = { + virtualHosts."social.notashelf.dev" = + { + root = "${config.services.mastodon.package}/public/"; + quic = true; + + locations = { + "/" = { + tryFiles = "$uri @proxy"; + }; + + "/system/".alias = "/var/lib/mastodon/public-system/"; + + "@proxy" = { + proxyPass = "http://unix:/run/mastodon-web/web.socket"; + proxyWebsockets = true; + }; + + "/api/v1/streaming/" = { + proxyPass = "http://unix:/run/mastodon-streaming/streaming.socket"; + proxyWebsockets = true; + }; + }; + } + // lib.sslTemplate; + }; + }; + + users.groups.mastodon.members = [config.services.nginx.user]; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/social/matrix.nix b/nyx/modules/core/roles/server/system/services/social/matrix.nix new file mode 100644 index 0000000..3a4c765 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/social/matrix.nix @@ -0,0 +1,201 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services.social; + + inherit (cfg.matrix.settings) port; + bindAddress = "::1"; + serverConfig."m.server" = "${config.services.matrix-synapse.settings.server_name}:443"; + clientConfig = { + "m.homeserver".base_url = "https://${config.networking.domain}"; + "m.identity_server" = {}; + }; + + mkWellKnown = data: '' + add_header Content-Type application/json; + add_header Access-Control-Allow-Origin *; + add_header 'Referrer-Policy' 'origin-when-cross-origin'; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + return 200 '${builtins.toJSON data}'; + ''; +in { + config = mkIf cfg.matrix.enable { + networking.firewall.allowedTCPPorts = [port]; + + modules.system.services.database = { + postgresql.enable = true; + }; + + services = { + postgresql = { + initialScript = pkgs.writeText "synapse-init.sql" '' + CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; + CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + ''; + }; + + nginx.virtualHosts = { + "notashelf.dev" = + { + serverAliases = ["matrix.notashelf.dev"]; + locations = { + "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; + "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; + "/_matrix".proxyPass = "http://[${bindAddress}]:${toString port}"; + "/_synapse/client".proxyPass = "http://[${bindAddress}]:${toString port}"; + }; + + quic = true; + http3 = true; + } + // lib.sslTemplate; + }; + + matrix-synapse = { + enable = true; + + extraConfigFiles = [config.age.secrets.matrix-secret.path]; + settings = { + server_name = "notashelf.dev"; + public_baseurl = "https://notashelf.dev"; + + withJemalloc = true; + enable_registration = true; + registration_requires_token = true; + + bcrypt_rounds = 14; + + # Don't report anonymized usage statistics + report_stats = false; + + # db + database = { + name = "psycopg2"; + args = { + host = "/run/postgresql"; + user = "matrix-synapse"; + database = "matrix-synapse"; + cp_min = 5; + cp_max = 10; + }; + }; + + # media + media_retention.remote_media_lifetime = "30d"; + max_upload_size = "100M"; + url_preview_enabled = true; + url_preview_ip_range_blacklist = [ + "127.0.0.0/8" + "10.0.0.0/8" + "172.16.0.0/12" + "192.168.0.0/16" + "100.64.0.0/10" + "192.0.0.0/24" + "169.254.0.0/16" + "192.88.99.0/24" + "198.18.0.0/15" + "192.0.2.0/24" + "198.51.100.0/24" + "203.0.113.0/24" + "224.0.0.0/4" + "::1/128" + "fe80::/10" + "fc00::/7" + "2001:db8::/32" + "ff00::/8" + "fec0::/10" + ]; + + thumbnail_sizes = [ + { + width = 32; + height = 32; + method = "crop"; + } + { + width = 96; + height = 96; + method = "crop"; + } + { + width = 320; + height = 240; + method = "scale"; + } + { + width = 640; + height = 480; + method = "scale"; + } + { + width = 800; + height = 600; + method = "scale"; + } + ]; + + # listener configuration + listeners = [ + { + inherit port; + bind_addresses = ["${bindAddress}"]; + resources = [ + { + names = ["client" "federation"]; + compress = true; + } + ]; + tls = false; + type = "http"; + x_forwarded = true; + } + ]; + + experimental_features = { + msc3202_device_masquerading = true; + msc3202_transaction_extensions = true; + msc2409_to_device_messages_enabled = true; + }; + + logConfig = '' + version: 1 + + # In systemd's journal, loglevel is implicitly stored, so let's omit it + # from the message text. + formatters: + journal_fmt: + format: '%(name)s: [%(request)s] %(message)s' + + filters: + context: + (): synapse.util.logcontext.LoggingContextFilter + request: "" + + handlers: + journal: + class: systemd.journal.JournalHandler + formatter: journal_fmt + filters: [context] + SYSLOG_IDENTIFIER: synapse + + root: + level: WARNING + handlers: [journal] + + disable_existing_loggers: False + ''; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/tor.nix b/nyx/modules/core/roles/server/system/services/tor.nix new file mode 100644 index 0000000..c9d7d43 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/tor.nix @@ -0,0 +1,35 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; +in { + config = mkIf cfg.tor.enable { + services = { + tor = { + settings = { + AutomapHostsOnResolve = true; + AutomapHostsSuffixes = [".exit" ".onion"]; + EnforceDistinctSubnets = true; + ExitNodes = "{de}"; + EntryNodes = "{de}"; + NewCircuitPeriod = 120; + DNSPort = 9053; + BandWidthRate = "15 MBytes"; + }; + + relay.onionServices = { + # hide ssh from script kiddies + ssh = { + version = 3; + map = [{port = builtins.elemAt config.services.openssh.ports 0;}]; + }; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/server/system/services/vaultwarden.nix b/nyx/modules/core/roles/server/system/services/vaultwarden.nix new file mode 100644 index 0000000..f64f219 --- /dev/null +++ b/nyx/modules/core/roles/server/system/services/vaultwarden.nix @@ -0,0 +1,64 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; + cfg = sys.services; + + inherit (cfg.vaultwarden.settings) port host; +in { + config = mkIf cfg.vaultwarden.enable { + modules.system.services = { + nginx.enable = true; + }; + + # this forces the system to create backup folder + systemd.services.backup-vaultwarden.serviceConfig = { + User = "root"; + Group = "root"; + }; + + services = { + vaultwarden = { + enable = true; + environmentFile = config.age.secrets.vaultwarden-env.path; + backupDir = "/srv/storage/vaultwarden/backup"; + config = { + DOMAIN = "https://vault.notashelf.dev"; + SIGNUPS_ALLOWED = false; + ROCKET_ADDRESS = host; + ROCKET_PORT = port; + extendedLogging = true; + invitationsAllowed = false; + useSyslog = true; + logLevel = "warn"; + showPasswordHint = false; + signupsAllowed = false; + signupsDomainsWhitelist = "notashelf.dev"; + signupsVerify = true; + smtpAuthMechanism = "Login"; + smtpFrom = "vaultwarden@notashelf.dev"; + smtpFromName = "NotAShelf's Vaultwarden Service"; + smtpHost = "mail.notashelf.dev"; + smtpPort = 465; + smtpSecurity = "force_tls"; + dataDir = "/srv/storage/vaultwarden"; + }; + }; + + nginx.virtualHosts."vault.notashelf.dev" = + { + locations."/" = { + proxyPass = "http://${host}:${toString port}"; + extraConfig = "proxy_pass_header Authorization;"; + }; + + quic = true; + } + // lib.sslTemplate; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/default.nix b/nyx/modules/core/roles/workstation/default.nix new file mode 100644 index 0000000..1075444 --- /dev/null +++ b/nyx/modules/core/roles/workstation/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./system + ]; + + system.nixos.tags = ["workstation"]; +} diff --git a/nyx/modules/core/roles/workstation/system/default.nix b/nyx/modules/core/roles/workstation/system/default.nix new file mode 100644 index 0000000..167c9d4 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./programs + ./services + ./security + + ./fonts.nix + ]; +} diff --git a/nyx/modules/core/roles/workstation/system/fonts.nix b/nyx/modules/core/roles/workstation/system/fonts.nix new file mode 100644 index 0000000..c3ef5f6 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/fonts.nix @@ -0,0 +1,80 @@ +{pkgs, ...}: { + config = { + fonts = { + enableDefaultPackages = false; + + fontconfig = { + defaultFonts = let + common = [ + "Iosevka Nerd Font" + "Symbols Nerd Font" + "Noto Color Emoji" + ]; + in { + monospace = + [ + "Source Code Pro Medium" + "Source Han Mono" + ] + ++ common; + + sansSerif = + [ + "Lexend" + ] + ++ common; + + serif = + [ + "Noto Serif" + ] + ++ common; + + emoji = ["Noto Color Emoji"] ++ common; + }; + }; + + fontDir = { + enable = true; + decompressFonts = true; + }; + + # font packages that should be installed + packages = with pkgs; [ + # programming fonts + sarasa-gothic + + # desktop fonts + corefonts # MS fonts + b612 # high legibility + material-icons + material-design-icons + roboto + work-sans + comic-neue + source-sans + inter + lato + lexend + dejavu_fonts + noto-fonts + noto-fonts-cjk + + # emojis + noto-fonts-color-emoji + twemoji-color-font + openmoji-color + openmoji-black + + # defaults worth keeping + dejavu_fonts + freefont_ttf + gyre-fonts + liberation_ttf + unifont + + (nerdfonts.override {fonts = ["Iosevka" "JetBrainsMono" "NerdFontsSymbolsOnly"];}) + ]; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/misc.nix b/nyx/modules/core/roles/workstation/system/misc.nix new file mode 100644 index 0000000..153a835 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/misc.nix @@ -0,0 +1,21 @@ +{lib, ...}: let + inherit (lib) mkForce; +in { + # Firefox cache on tmpfs + fileSystems."/home/notashelf/.cache/mozilla/firefox" = { + device = "tmpfs"; + fsType = "tmpfs"; + noCheck = true; + options = [ + "noatime" + "nodev" + "nosuid" + "size=128M" + ]; + }; + + # enable the unified cgroup hierarchy (cgroupsv2) + # NOTE: we use mkForce ensure that we are making cgroupsv2 the default + # some services, i.e. lxd, tries to disable it + systemd.enableUnifiedCgroupHierarchy = mkForce true; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/ccache.nix b/nyx/modules/core/roles/workstation/system/programs/ccache.nix new file mode 100644 index 0000000..bbc8664 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/ccache.nix @@ -0,0 +1,48 @@ +{ + config, + lib, + ... +}: { + programs.ccache = { + enable = true; + cacheDir = "/var/cache/sccache"; + }; + + systemd.tmpfiles.rules = [ + "z ${config.programs.ccache.cacheDir} 770 root nixbld - -" + ]; + + nix.settings.extra-sandbox-paths = [ + config.programs.ccache.cacheDir + ]; + + nixpkgs.overlays = lib.mkIf (config.programs.ccache.enable && config.programs.ccache.packageNames == []) [ + (_: super: { + ccacheWrapper = super.ccacheWrapper.override { + extraConfig = '' + export CCACHE_COMPRESS=1 + export CCACHE_DIR="${config.programs.ccache.cacheDir}" + export CCACHE_UMASK=007 + export CCACHE_SLOPPINESS=include_file_mtime,time_macros + export CCACHE_NODIRECT=1 + if [ ! -d "$CCACHE_DIR" ]; then + echo "=====" + echo "Directory '$CCACHE_DIR' does not exist" + echo "Please create it with:" + echo " sudo mkdir -m0770 '$CCACHE_DIR'" + echo " sudo chown root:nixbld '$CCACHE_DIR'" + echo "=====" + exit 1 + fi + if [ ! -w "$CCACHE_DIR" ]; then + echo "=====" + echo "Directory '$CCACHE_DIR' is not accessible for user $(whoami)" + echo "Please verify its access permissions" + echo "=====" + exit 1 + fi + ''; + }; + }) + ]; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/default.nix b/nyx/modules/core/roles/workstation/system/programs/default.nix new file mode 100644 index 0000000..c07f272 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/default.nix @@ -0,0 +1,12 @@ +{ + imports = [ + ./ccache.nix + ./flatpak.nix + ./java.nix + ./misc.nix + ./nh.nix + ./thunar.nix + ./wine.nix + ./xdg-ninja.nix + ]; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/flatpak.nix b/nyx/modules/core/roles/workstation/system/programs/flatpak.nix new file mode 100644 index 0000000..0617c5b --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/flatpak.nix @@ -0,0 +1,6 @@ +{ + # enable flatpak, as well as xdgp to communicate with the host filesystems + services.flatpak.enable = false; + + environment.sessionVariables.XDG_DATA_DIRS = ["/var/lib/flatpak/exports/share"]; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/java.nix b/nyx/modules/core/roles/workstation/system/programs/java.nix new file mode 100644 index 0000000..756a7ad --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/java.nix @@ -0,0 +1,24 @@ +{ + pkgs, + lib, + ... +}: { + # "saying java is good because it runs on all systems is like saying + # anal sex is good because it works on all species" + # - sun tzu + programs.java = { + # adds JAVA_HOME to the global environment + # by sourcing the jdk’s setup-hook on shell init + # slightly slows down the shell since the java path needs + # to be realised + enable = true; + + # jdk package to use + package = pkgs.jre; + + # whether to enable binfmt for executing + # java jar’s and classes. This can be a security + # exploit. + binfmt = lib.mkForce false; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/misc.nix b/nyx/modules/core/roles/workstation/system/programs/misc.nix new file mode 100644 index 0000000..e9fe59e --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/misc.nix @@ -0,0 +1,21 @@ +{ + programs = { + # allow users to mount fuse filesystems with allow_other + fuse.userAllowOther = true; + + # show network usage + bandwhich.enable = true; + + # registry for linux, thanks to gnome + dconf.enable = true; + + # network inspection utility + wireshark.enable = true; + + # gnome's keyring manager + seahorse.enable = true; + + # networkmanager tray uility + nm-applet.enable = true; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/nh.nix b/nyx/modules/core/roles/workstation/system/programs/nh.nix new file mode 100644 index 0000000..7204aa6 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/nh.nix @@ -0,0 +1,23 @@ +{ + inputs, + pkgs, + ... +}: { + imports = [inputs.nh.nixosModules.default]; + + config = { + nh = { + enable = true; + package = pkgs.nh; + + # whether to let nh run gc on the store daily + # this is overall good for storage, but has negative + # implications on disk health and the performance + # of the nix daemon - which will be slowed during gc + clean = { + enable = true; + dates = "daily"; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/thunar.nix b/nyx/modules/core/roles/workstation/system/programs/thunar.nix new file mode 100644 index 0000000..ddf746d --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/thunar.nix @@ -0,0 +1,26 @@ +{pkgs, ...}: { + # the thunar file manager + # we enable thunar here and add plugins instead of in systemPackages + # it is enabled unconditionally as a relatively lightweight fallback + # option for my system file manager. I still use dolphin most of the time + programs.thunar = { + enable = true; + plugins = with pkgs.xfce; [ + thunar-archive-plugin + thunar-media-tags-plugin + ]; + }; + + environment = { + systemPackages = with pkgs; [ + # packages necessery for thunar thumbnails + xfce.tumbler + libgsf # odf files + ffmpegthumbnailer + ark # GUI archiver for thunar archive plugin + ]; + }; + + # thumbnail support on thunar + services.tumbler.enable = true; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/wine.nix b/nyx/modules/core/roles/workstation/system/programs/wine.nix new file mode 100644 index 0000000..1576a16 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/wine.nix @@ -0,0 +1,16 @@ +{ + config, + pkgs, + ... +}: let + env = config.modules.usrEnv; +in { + # determine which version of wine to be used + # then add it to systemPackages + environment.systemPackages = with pkgs; let + winePackage = + if env.isWayland + then wineWowPackages.waylandFull + else wineWowPackages.stableFull; + in [winePackage]; +} diff --git a/nyx/modules/core/roles/workstation/system/programs/xdg-ninja.nix b/nyx/modules/core/roles/workstation/system/programs/xdg-ninja.nix new file mode 100644 index 0000000..c682277 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/programs/xdg-ninja.nix @@ -0,0 +1,9 @@ +{lib, ...}: let + template = import lib.xdgTemplate "nixos"; +in { + environment = { + variables = template.glEnv; + sessionVariables = template.sysEnv; + etc = {inherit (template) pythonrc npmrc;}; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/security/default.nix b/nyx/modules/core/roles/workstation/system/security/default.nix new file mode 100644 index 0000000..4018f10 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/security/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./firejail.nix + ./tor.nix + ]; +} diff --git a/nyx/modules/core/roles/workstation/system/security/firejail.nix b/nyx/modules/core/roles/workstation/system/security/firejail.nix new file mode 100644 index 0000000..73deccd --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/security/firejail.nix @@ -0,0 +1,39 @@ +{ + lib, + pkgs, + ... +}: let + inherit (lib) getExe; +in { + programs.firejail = let + profiles = "${pkgs.firejail}/etc/firejail"; + in { + enable = true; + wrappedBinaries = with pkgs; { + thunderbird = { + executable = getExe thunderbird; + profile = "${profiles}/thunderbird.profile"; + }; + + spotify = { + executable = getExe spotify; + profile = "${profiles}/spotify.profile"; + }; + + mpv = { + executable = getExe mpv; + profile = "${profiles}/mpv.profile"; + }; + + imv = { + executable = pkgs.imv + /bin/imv; + profile = "${profiles}/imv.profile"; + }; + + zathura = { + executable = getExe zathura; + profile = "${profiles}/zathura.profile"; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/security/tor.nix b/nyx/modules/core/roles/workstation/system/security/tor.nix new file mode 100644 index 0000000..10cb4a3 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/security/tor.nix @@ -0,0 +1,52 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; +in { + config = mkIf sys.security.tor.enable { + services = { + tor = { + enable = true; + torsocks.enable = true; + client = { + enable = true; + dns.enable = true; + }; + }; + + networkd-dispatcher = { + enable = true; + rules."restart-tor" = { + onState = ["routable" "off"]; + script = '' + #!${pkgs.runtimeShell} + if [[ $IFACE == "wlan0" && $AdministrativeState == "configured" ]]; then + echo "Restarting Tor ..." + systemctl restart tor + fi + exit 0 + ''; + }; + }; + }; + + programs.proxychains = { + enable = true; + quietMode = false; + proxyDNS = true; + package = pkgs.proxychains-ng; + proxies = { + tor = { + type = "socks5"; + host = "127.0.0.1"; + port = 9050; + }; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/adb.nix b/nyx/modules/core/roles/workstation/system/services/adb.nix new file mode 100644 index 0000000..724bb18 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/adb.nix @@ -0,0 +1,14 @@ +{pkgs, ...}: { + programs.adb.enable = true; + + services.udev = { + packages = [ + pkgs.android-udev-rules + ]; + + extraRules = '' + # add my android device to adbusers + SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="adbusers" + ''; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/dbus.nix b/nyx/modules/core/roles/workstation/system/services/dbus.nix new file mode 100644 index 0000000..d595418 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/dbus.nix @@ -0,0 +1,10 @@ +{pkgs, ...}: { + services.dbus = { + enable = true; + packages = with pkgs; [dconf gcr udisks2]; + + # Use the faster dbus-broker instead of the classic dbus-daemon + # this setting is experimental, but after testing I've come to realise it broke nothing + implementation = "broker"; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/default.nix b/nyx/modules/core/roles/workstation/system/services/default.nix new file mode 100644 index 0000000..3ee69ad --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/default.nix @@ -0,0 +1,14 @@ +{ + imports = [ + ./adb.nix + ./dbus.nix + ./earlyoom.nix + ./gnome.nix + ./location.nix + ./printing.nix + ./misc.nix + ./runners.nix + ./systemd.nix + ./zswap.nix + ]; +} diff --git a/nyx/modules/core/roles/workstation/system/services/earlyoom.nix b/nyx/modules/core/roles/workstation/system/services/earlyoom.nix new file mode 100644 index 0000000..d934c3f --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/earlyoom.nix @@ -0,0 +1,22 @@ +{pkgs, ...}: { + # https://dataswamp.org/~solene/2022-09-28-earlyoom.html + # avoid the linux kernel locking itself when we're putting too much strain on the memory + # this helps avoid having to shut down forcefully when we OOM + services.earlyoom = { + enable = true; + enableNotifications = true; # annoying, but we want to know what's killed + freeSwapThreshold = 2; + freeMemThreshold = 2; + extraArgs = [ + "-g" # kill all processes within a process group + "--avoid 'Hyprland|soffice|soffice.bin|firefox|thunderbird)$'" # things we want to not kill + "--prefer '^(electron|.*.exe)$'" # I wish we could kill electron permanently + ]; + + # we should ideally write the logs into a designated log file; or even better, to the journal + # for now we can hope this echo sends the log to somewhere we can observe later + killHook = pkgs.writeShellScript "earlyoom-kill-hook" '' + echo "Process $EARLYOOM_NAME ($EARLYOOM_PID) was killed" + ''; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/gnome.nix b/nyx/modules/core/roles/workstation/system/services/gnome.nix new file mode 100644 index 0000000..eddf783 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/gnome.nix @@ -0,0 +1,26 @@ +{ + pkgs, + lib, + ... +}: { + config = { + services = { + udev.packages = with pkgs; [ + gnome.gnome-settings-daemon + ]; + + gnome = { + glib-networking.enable = true; + evolution-data-server.enable = true; + + # optional to use google/nextcloud calendar + gnome-online-accounts.enable = true; + + # optional to use google/nextcloud calendar + gnome-keyring.enable = true; + + gnome-remote-desktop.enable = lib.mkForce false; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/location.nix b/nyx/modules/core/roles/workstation/system/services/location.nix new file mode 100644 index 0000000..0321fac --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/location.nix @@ -0,0 +1,14 @@ +{config, ...}: { + location.provider = "geoclue2"; + + services.geoclue2 = { + # enable geoclue2 only if location.provider is geoclue2 + enable = config.location.provider == "geoclue2"; + + # TODO: make gammastep fall back to local if geoclue2 is disabled + appConfig.gammastep = { + isAllowed = true; + isSystem = false; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/misc.nix b/nyx/modules/core/roles/workstation/system/services/misc.nix new file mode 100644 index 0000000..61d52b8 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/misc.nix @@ -0,0 +1,20 @@ +{ + config, + pkgs, + lib, + ... +}: { + config = { + services = { + # enable GVfs, a userspace virtual filesystem. + gvfs.enable = true; + + # storage daemon required for udiskie auto-mount + udisks2.enable = !config.boot.isContainer; + + # disable chrony in favor if systemd-timesyncd + timesyncd.enable = lib.mkDefault true; + chrony.enable = lib.mkDefault false; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/printing.nix b/nyx/modules/core/roles/workstation/system/services/printing.nix new file mode 100644 index 0000000..f296cce --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/printing.nix @@ -0,0 +1,32 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf; + + sys = config.modules.system; +in { + config = mkIf sys.printing.enable { + # enable cups and add some drivers for common printers + services = { + printing = { + enable = true; + drivers = with pkgs; [ + gutenprint + hplip + ]; + }; + + # required for network discovery of printers + avahi = { + enable = true; + # resolve .local domains for printers + nssmdns4 = true; + # pass avahi port(s) to the firewall + openFirewall = true; + }; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/runners.nix b/nyx/modules/core/roles/workstation/system/services/runners.nix new file mode 100644 index 0000000..3e3390f --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/runners.nix @@ -0,0 +1,45 @@ +{ + pkgs, + lib, + ... +}: { + config = { + environment.systemPackages = [pkgs.appimage-run]; + + # run appimages with appimage-run + boot.binfmt.registrations = lib.genAttrs ["appimage" "AppImage"] (_: { + wrapInterpreterInShell = false; + interpreter = "${pkgs.appimage-run}/bin/appimage-run"; + recognitionType = "magic"; + offset = 0; + mask = "\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x00\\xff\\xff\\xff"; + magicOrExtension = "\\x7fELF....AI\\x02"; + }); + + # run unpatched linux binaries with nix-ld + programs.nix-ld = { + enable = true; + libraries = with pkgs; [ + stdenv.cc.cc + openssl + curl + glib + util-linux + glibc + icu + libunwind + libuuid + zlib + libsecret + # graphical + freetype + libglvnd + libnotify + SDL2 + vulkan-loader + gdk-pixbuf + xorg.libX11 + ]; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/systemd.nix b/nyx/modules/core/roles/workstation/system/services/systemd.nix new file mode 100644 index 0000000..10cc249 --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/systemd.nix @@ -0,0 +1,21 @@ +{ + systemd = let + extraConfig = '' + DefaultTimeoutStartSec=15s + DefaultTimeoutStopSec=15s + DefaultTimeoutAbortSec=15s + DefaultDeviceTimeoutSec=15s + ''; + in { + inherit extraConfig; + user = {inherit extraConfig;}; + services = { + "getty@tty1".enable = false; + "autovt@tty1".enable = false; + "getty@tty7".enable = false; + "autovt@tty7".enable = false; + "kmsconvt@tty1".enable = false; + "kmsconvt@tty7".enable = false; + }; + }; +} diff --git a/nyx/modules/core/roles/workstation/system/services/zswap.nix b/nyx/modules/core/roles/workstation/system/services/zswap.nix new file mode 100644 index 0000000..65cdecd --- /dev/null +++ b/nyx/modules/core/roles/workstation/system/services/zswap.nix @@ -0,0 +1,24 @@ +{ + # compress memory and store in RAM before swapping to disk + boot.kernelParams = ["zswap.enabled=1"]; + + # use lz4 and z3fold for zswap + boot.kernelModules = [ + "lz4" + "z3fold" + ]; + + systemd.services.config-zswap = { + description = ""; + + after = ["systemd-modules-load.service"]; + wantedBy = ["multi-user.target"]; + + serviceConfig.Type = "oneshot"; + + script = '' + echo lz4 > /sys/module/zswap/parameters/compressor + echo z3fold > /sys/module/zswap/parameters/zpool + ''; + }; +} diff --git a/nyx/modules/extra/exported/onedev/default.nix b/nyx/modules/extra/exported/onedev/default.nix new file mode 100644 index 0000000..4f8f260 --- /dev/null +++ b/nyx/modules/extra/exported/onedev/default.nix @@ -0,0 +1,59 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkIf mkEnableOption mkDefault mkOption types; + cfg = config.services.onedev; + + onedev-package = pkgs.fetchurl { + url = "https://code.onedev.io/~downloads/projects/160/builds/3835/artifacts/onedev-8.4.2.tar.gz"; + sha256 = "01spl71zdl0ywh5hf83p5d2pxqb9zqhi0akijxv04j3jzkgv2dm6"; + }; +in { + options = { + services.onedev = { + enable = mkEnableOption "Onedev server"; + package = mkOption { + default = onedev-package; + type = types.raw; + }; + + javaPackage = mkOption { + default = pkgs.jdk11_headless; + type = types.package; + }; + + user = mkOption { + default = "onedev"; + type = with types; nullOr str; + }; + }; + }; + + config = let + user = + if cfg.user == null + then "onedev" + else "${cfg.user}"; + in + mkIf cfg.enable { + systemd.user.services."onedev-agent-${toString user}" = { + enable = true; + unitConfig = { + ConditionUser = "${toString user}"; + }; + wantedBy = ["default.target"]; + after = ["network.target"]; + description = "onedev-agent-${toString user}"; + path = [config.system.path]; + serviceConfig = let + java = "${lib.getExe cfg.javaPackage}"; + in { + ExecStart = "${java} -cp '${cfg.package}/lib/1.8.21/*' io.onedev.agent.Agent"; + Type = "simple"; + }; + }; + }; +} diff --git a/nyx/modules/extra/shared/default.nix b/nyx/modules/extra/shared/default.nix new file mode 100644 index 0000000..8e403db --- /dev/null +++ b/nyx/modules/extra/shared/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./nixos + ./home-manager + ]; +} diff --git a/nyx/modules/extra/shared/home-manager/default.nix b/nyx/modules/extra/shared/home-manager/default.nix new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/nyx/modules/extra/shared/home-manager/default.nix @@ -0,0 +1 @@ +{} diff --git a/nyx/modules/extra/shared/home-manager/gtklock/default.nix b/nyx/modules/extra/shared/home-manager/gtklock/default.nix new file mode 100644 index 0000000..f453ce0 --- /dev/null +++ b/nyx/modules/extra/shared/home-manager/gtklock/default.nix @@ -0,0 +1,101 @@ +{ + config, + lib, + pkgs, + ... +}: +with builtins; let + cfg = config.programs.gtklock; + + inherit (lib) types mkIf mkOption mkEnableOption mkPackageOptionMD literalExpression optionals optionalString; + inherit (lib.generators) toINI; + + # the main config includes two very niche options: style (which takes a path) and modules, which takes a list of module paths + # concatted by ";" + # for type checking purposes, I prefer templating the main section of the config and let the user safely choose options + # extraConfig takes an attrset, and converts it to the correct INI format - it's mostly just strings and integers, so that's fine + baseConfig = '' + [main] + ${optionalString (cfg.config.gtk-theme != "") "gtk-theme=${cfg.config.gtk-theme}"} + ${optionalString (cfg.config.style != "") "style=${cfg.config.style}"} + ${optionalString (cfg.config.modules != []) "modules=${concatStringsSep ";" cfg.config.modules}"} + ''; + + finalConfig = baseConfig + optionals (cfg.extraConfig != null) (toINI {} cfg.extraConfig); +in { + meta.maintainers = [maintainers.NotAShelf]; + options.programs.gtklock = { + enable = mkEnableOption "GTK-based lockscreen for Wayland"; + package = mkPackageOptionMD pkgs "gtklock" {}; + + config = { + gtk-theme = mkOption { + type = types.str; + default = ""; + description = '' + GTK theme to use for gtklock. + ''; + example = "Adwaita-dark"; + }; + + style = mkOption { + type = with types; oneOf [str path]; + default = ""; + description = '' + The css file to be used for gtklock. + ''; + example = literalExpression '' + pkgs.writeText "gtklock-style.css" ''' + window { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + } + ''' + ''; + }; + + modules = mkOption { + type = with types; listOf (either package str); + default = []; + description = '' + A list of gtklock modulesto use. Can either be packages, absolute paths, or strings. + ''; + example = literalExpression '' + [ + "${pkgs.gtklock-powerbar-module.outPath}/lib/gtklock/powerbar-module.so" + "${pkgs.gtklock-playerctl-module.outPath}/lib/gtklock/playerctl-module.so" + ]; + ''; + }; + }; + + extraConfig = mkOption { + type = with types; nullOr attrs; + default = { + countdown = { + countdown-position = "top-right"; + justify = "right"; + countdown = 20; + }; + }; + description = '' + Extra configuration to append to gtklock configuration file. + Mostly used for appending module configurations. + ''; + example = literalExpression '' + countdown = { + countdown-position = "top-right"; + justify = "right"; + countdown = 20; + } + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = [cfg.package]; + + xdg.configFile."gtklock/config.ini".source = pkgs.writeText "gtklock-config.ini" finalConfig; + }; +} diff --git a/nyx/modules/extra/shared/home-manager/transience/default.nix b/nyx/modules/extra/shared/home-manager/transience/default.nix new file mode 100644 index 0000000..15b5c0d --- /dev/null +++ b/nyx/modules/extra/shared/home-manager/transience/default.nix @@ -0,0 +1,76 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkOption mkEnableOption types; + + cfg = config.services.transience; +in { + meta.maintainers = [lib.maintainers.NotAShelf]; + options.services.transience = { + enable = mkEnableOption "transience"; + + user = mkOption { + type = with types; nullOr string; + default = null; + description = "The user that the directories will be relative to"; + }; + + days = mkOption { + type = types.int; + default = 30; + description = "Number of days after which files are deleted"; + }; + + directories = mkOption { + type = with types; listOf path; + default = []; + description = '' + A list of directories that will be cleaned. + + Must be relative to the user's home directory. + ''; + }; + }; + + config = { + assertions = [ + { + assertion = cfg.enable -> cfg.user == null; + message = '' + You have enabled services.transience, but have not specified your user. You must specify a "main user" + for your system for Transience to work properly. + ''; + } + { + assertion = cfg.directories == []; + message = '' + You have enabled services.transience, but have not specified any directories to clean up. Please specify + at least one folder. This option defaults to an empty list, but you must specify a list of directories for + Transience to work properly. + ''; + } + ]; + + systemd.user.services.transience = let + dirs = + map ( + x: + config.home-manager.users.${cfg.user}.home.homeDirectory + "/" + x + ) + cfg.directories; + in { + Install.wantedBy = ["default.target"]; + Service.ExecStart = '' + ${builtins.concatStringsSep "\n" (map (x: "find ${ + lib.escapeShellArg x + } -mtime +${cfg.days} -exec rm -rv {} + -depth;") + dirs)} + ''; + + Unit.Description = "Clean up transient directories"; + }; + }; +} diff --git a/nyx/modules/extra/shared/home-manager/vifm/default.nix b/nyx/modules/extra/shared/home-manager/vifm/default.nix new file mode 100644 index 0000000..17ac519 --- /dev/null +++ b/nyx/modules/extra/shared/home-manager/vifm/default.nix @@ -0,0 +1,50 @@ +{ + config, + lib, + pkgs, + ... +}: +with builtins; let + inherit (lib) types mkIf mkOption mkEnableOption mkPackageOptionMD literalExpression; + + cfg = config.programs.vifm; +in { + meta.maintainers = [maintainers.NotAShelf]; + options.programs.vifm = { + enable = mkEnableOption "vifm, file manager with curses interface, which provides Vim-like environment for managing objects within file systems"; + + package = mkPackageOptionMD pkgs "vifm" {}; + + config = mkOption { + type = types.lines; + default = ""; + description = "Vifm configuration to be written in vifmrc"; + + example = literalExpression '' + " vim:ft=vifm + set vicmd="nvim" + set runexec + ''; + }; + + extraConfigFiles = mkOption { + type = with types; listOf str; + default = []; + example = ["~/.config/vifm/vifmrc.local"]; + description = '' + Extra vifm configuration files to be sourced in vifmrc + + Can be an absolute path, or a path relative to `$XDG_CONFIG_HOME/vifm` + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = [cfg.package]; + + xdg.configFile."vifm/vifmrc".source = pkgs.writeText "vifmrc" ( + (lib.concatLines (lib.forEach cfg.extraConfigFiles (x: "source ${x}"))) + + cfg.config + ); + }; +} diff --git a/nyx/modules/extra/shared/home-manager/xplr/default.nix b/nyx/modules/extra/shared/home-manager/xplr/default.nix new file mode 100644 index 0000000..8b0ab21 --- /dev/null +++ b/nyx/modules/extra/shared/home-manager/xplr/default.nix @@ -0,0 +1,61 @@ +{ + config, + lib, + pkgs, + ... +}: +with builtins; let + inherit (lib) types mkIf mkOption mkEnableOption mkPackageOptionMD literalExpression; + + cfg = config.programs.xplr; + initialConfig = '' + version = '${cfg.package.version}' + ''; + # we provide a default version line within the configuration file, which is obtained from the package's attributes + # merge the initial configFile, a mapped list of plugins and then the user defined configuration to obtain the final configuration + pluginPath = + if cfg.plugins != [] + then ("package.path=\n" + (concatStringsSep " ..\n" (map (p: ''"${p}/init.lua;"'') cfg.plugins)) + " ..\npackage.path\n") + else "\n"; + configFile = initialConfig + pluginPath + cfg.config; +in { + meta.maintainers = [maintainers.NotAShelf]; + options.programs.xplr = { + enable = mkEnableOption "xplr, terminal UI based file explorer" // {default = true;}; + + package = mkPackageOptionMD pkgs "xplr" {}; + + plugins = mkOption { + type = with types; nullOr (listOf (either package str)); + default = []; + defaultText = literalExpression "[]"; + description = '' + Plugins to be added to your configuration file. Must be a package, an absolute plugin path, or string + to be recognized by xplr. Paths will be relative to $XDG_CONFIG_HOME/xplr/init.lua unless they are absolute. + ''; + }; + + # TODO: rename, this is the main configuration + config = mkOption { + type = types.lines; + default = ""; + description = '' + Extra xplr configuration. + ''; + + example = literalExpression '' + require("wl-clipboard").setup { + copy_command = "wl-copy -t text/uri-list", + paste_command = "wl-paste", + keep_selection = true, + } + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = [cfg.package]; + + xdg.configFile."xplr/init.lua".source = pkgs.writeText "init.lua" configFile; + }; +} diff --git a/nyx/modules/extra/shared/nixos/comma/default.nix b/nyx/modules/extra/shared/nixos/comma/default.nix new file mode 100644 index 0000000..1cdd516 --- /dev/null +++ b/nyx/modules/extra/shared/nixos/comma/default.nix @@ -0,0 +1,31 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkOption mkEnableOption types literalExpression; + + cfg = config.programs.comma; +in { + options.programs.comma = { + enable = mkEnableOption "comma, a wrapper to run software without installing it"; + + package = mkOption { + type = types.package; + default = pkgs.comma.override {nix-index-unwrapped = config.programs.nix-index.package;}; + defaultText = literalExpression "pkgs.comma.override { nix-index-unwrapped = config.programs.nix-index.package; }"; + description = "Package providing the `comma` tool."; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [cfg.package]; + + programs = { + command-not-found.enable = lib.mkForce false; + + nix-index.enable = true; + }; + }; +} diff --git a/nyx/modules/extra/shared/nixos/default.nix b/nyx/modules/extra/shared/nixos/default.nix new file mode 100644 index 0000000..03db0dc --- /dev/null +++ b/nyx/modules/extra/shared/nixos/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./comma + ./wakapi + ./reposilite + ]; +} diff --git a/nyx/modules/extra/shared/nixos/reposilite/default.nix b/nyx/modules/extra/shared/nixos/reposilite/default.nix new file mode 100644 index 0000000..9d25711 --- /dev/null +++ b/nyx/modules/extra/shared/nixos/reposilite/default.nix @@ -0,0 +1,242 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkEnableOption mkOption types mkIf getExe; + + writeServiceConfig = config: + lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name}: ${ + ( + if (lib.isBool value) + then (lib.boolToString value) + else (toString value) + ) + }") + config); + + cfg = config.services.reposilite; +in { + options.services.reposilite = { + enable = mkEnableOption "reposilite - maven repository manager"; + + package = mkOption { + type = with types; nullOr package; + default = null; # reposilite is not in nixpkgs + description = "Package to install"; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/reposilite"; + description = "Working directory"; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Open firewall for reposilite"; + }; + + user = mkOption { + type = types.str; + default = "reposilite"; + description = "User to run reposilite as"; + }; + + group = mkOption { + type = types.str; + default = "reposilite"; + description = "Group to run reposilite as"; + }; + + settings = mkOption { + default = {}; + description = "Settings to pass to reposilite"; + type = with types; + submodule { + freeformType = attrs; + options = { + hostname = mkOption { + type = types.str; + default = "0.0.0.0"; + description = "Hostname to listen on"; + }; + + port = mkOption { + type = types.int; + default = 8080; + description = "Port to listen on"; + }; + + database = mkOption { + type = types.str; + default = "sqlite reposilite.db"; + description = '' + Database configuration. Supported storage providers: + - mysql localhost:3306 database user password + - sqlite reposilite.db + - sqlite --temporary + Experimental providers (not covered with tests): + - postgresql localhost:5432 database user password + - h2 reposilite + ''; + }; + + sslEnabled = mkOption { + type = types.bool; + default = false; + example = true; + description = "Support encrypted connections"; + }; + + sslPort = mkOption { + type = types.int; + default = 443; + description = "Port to listen on for SSL connections"; + }; + + keyPath = mkOption { + type = with types; nullOr str; + default = "$${WORKING_DIRECTORY}/cert.pem $${WORKING_DIRECTORY}/key.pem"; + example = "${cfg.dataDir}/cert.pem ${cfg.dataDir}/key.pem"; + description = '' + Key file to use. You can specify absolute path to the given file or use {option}`services.reposilite.dataDir` variable. + If you want to use .pem certificate you need to specify its path next to the key path. + ''; + }; + + keyPassword = mkOption { + type = with types; nullOr str; + default = ""; + example = "reposilite"; + description = "Key password to use"; + }; + + enforceSsl = mkOption { + type = types.bool; + default = false; + description = "Redirect http traffic to https"; + }; + + webThreadPoolSize = mkOption { + type = types.addCheck types.int (x: x >= 5); + default = 16; + description = "Max amount of threads used by core thread pool (min: 5)"; + }; + + ioThreadPool = mkOption { + type = types.addCheck types.int (x: x >= 2); + default = 8; + description = "IO thread pool handles all tasks that may benefit from non-blocking IO (min: 2)"; + }; + + databaseThreadPool = mkOption { + type = types.addCheck types.int (x: x >= 1); + default = 8; + description = "Database thread pool manages open connections to database (min: 1)"; + }; + + compressionStrategy = mkOption { + type = types.enum ["none" "gzip"]; + default = "none"; + description = '' + Select compression strategy used by this instance. + Using 'none' reduces usage of CPU & memory, but ends up with higher transfer usage. + GZIP is better option if you're not limiting resources that much to increase overall request times. + ''; + }; + + idleTimeout = mkOption { + type = types.int; + default = 30000; + description = "Default idle timeout used by Jetty"; + }; + + bypassExternalCache = mkOption { + type = types.bool; + default = true; + description = '' + Bypass external cache and use internal one. + Adds cache bypass headers to each request from `/api/*` scope served by this instance + ''; + }; + + cachedLogSize = mkOption { + type = types.int; + default = 50; + description = "Amount of messages stored in cached logger"; + }; + + defaultFrontend = mkOption { + type = types.bool; + default = true; + description = "Enable default frontend with dashboard"; + }; + + basePath = mkOption { + type = types.str; + default = "/"; + description = '' + Set custom base path for Reposilite instance. + It's not recommended to mount Reposilite under custom base path + and you should always prioritize subdomain over this option. + ''; + }; + + debugEnabled = mkOption { + type = types.bool; + default = false; + description = "Debug mode"; + }; + }; + }; + }; + }; + + config = mkIf cfg.enable { + environment = { + systemPackages = [cfg.package]; + etc."reposilite/configuration.cdn" = mkIf (cfg.settings != {}) { + text = writeServiceConfig cfg.settings; + }; + }; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [cfg.settings.port]; + + users = { + groups.reposilite = { + name = cfg.group; + }; + + users.reposilite = { + group = cfg.user; + home = cfg.dataDir; + + isSystemUser = true; + createHome = true; + }; + }; + + systemd.services."reposilite" = { + description = "Reposilite - Maven repository"; + wantedBy = ["multi-user.target"]; + script = let + inherit (cfg) dataDir; + staticConfig = ''--local-config "/etc/reposilite/configuration.cdn" --local-configuration-mode none''; + in '' + ${getExe cfg.package} --working-directory "${dataDir}" ${staticConfig} + ''; + + serviceConfig = { + inherit (cfg) user group; + + WorkingDirectory = cfg.dataDir; + SuccessExitStatus = 0; + TimeoutStopSec = 10; + Restart = "on-failure"; + RestartSec = 5; + }; + }; + }; +} diff --git a/nyx/modules/extra/shared/nixos/wakapi/default.nix b/nyx/modules/extra/shared/nixos/wakapi/default.nix new file mode 100644 index 0000000..714d1a9 --- /dev/null +++ b/nyx/modules/extra/shared/nixos/wakapi/default.nix @@ -0,0 +1,147 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) concatStrings mapAttrsToList concatMapAttrs optionalAttrs optionalString foldl' stringLength elem substring head lowerChars toUpper isBool isList boolToString types mkIf optional mkOption mkEnableOption; + + cfg = config.services.wakapi; + user = config.users.users.wakapi.name; + group = config.users.groups.wakapi.name; + configFile = pkgs.writeText "wakapi.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv)); + + # Convert name from camel case (e.g. disable2FARemember) to upper case snake case (e.g. DISABLE_2FA_REMEMBER). + nameToEnvVar = name: let + parts = builtins.split "([A-Z0-9]+)" name; + partsToEnvVar = parts: + foldl' (key: x: let + last = stringLength key - 1; + in + if isList x + then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x + else if key != "" && elem (substring 0 1 x) lowerChars + then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ] + substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x + else key + toUpper x) "" + parts; + in + if builtins.match "[A-Z0-9_]+" name != null + then name + else partsToEnvVar parts; + + # Due to the different naming schemes allowed for config keys, + # we can only check for values consistently after converting them to their corresponding environment variable name. + configEnv = let + configEnv = concatMapAttrs (name: value: + optionalAttrs (value != null) { + ${nameToEnvVar name} = + if isBool value + then boolToString value + else toString value; + }) + cfg.config; + in + configEnv; +in { + options.services.wakapi = with types; { + enable = mkEnableOption "wakapi"; + + package = mkOption { + type = package; + default = pkgs.wakapi; + defaultText = literalExpression "pkgs.wakapi"; + description = "wakapi package to use."; + }; + + stateDirectory = mkOption { + type = str; + default = "wakapi"; + defaultText = literalExpression "wakapi"; + description = "The state directory for the systemd service. Will be located in /var/lib"; + }; + + config = mkOption { + type = attrsOf (nullOr (oneOf [bool int str])); + default = { + config = {}; + }; + example = literalExpression '' + { + WAKAPI_LISTEN_IPV4=127.0.0.1 + WAKAPI_LISTEN_IPV6=::1 + WAKAPI_PORT=3000 + } + ''; + description = '' + The configuration of wakatime is done through environment variables, + therefore it is recommended to use upper snake case (e.g. {env}`WAKAPI_DATA_CLEANUP_TIME`). + + However, camel case (e.g. `wakapiDataCleanupTime`) is also supported: + The NixOS module will convert it automatically to + upper case snake case (e.g. {env}`WAKAPI_DATA_CLEANUP_TIME`). + In this conversion digits (0-9) are handled just like upper case characters, + so `foo2` would be converted to {env}`FOO_2`. + Names already in this format remain unchanged, so `FOO2` remains `FOO2` if passed as such, + even though `foo2` would have been converted to {env}`FOO_2`. + This allows working around any potential future conflicting naming conventions. + + Based on the attributes passed to this config option an environment file will be generated + that is passed to wakapi's systemd service. + + The available configuration options can be found in + [self-hostiing guide](https://github.com/muety/wakapi#-configuration-options) to + find about the environment variables you can use. + ''; + }; + + environmentFile = mkOption { + type = with types; nullOr path; + default = null; + example = "/etc/wakapi.env"; + description = '' + Additional environment file as defined in {manpage}`systemd.exec(5)`. + + Sensitive secrets such as {env}`WAKAPI_PASSWORD_SALT` and {env}`WAKAPI_DB_PASSWORD` + may be passed to the service while avoiding potentially making them world-readable in the nix store or + to convert an existing non-nix installation with minimum hassle. + + Note that this file needs to be available on the host on which + `wakapi` is running. + ''; + }; + }; + + config = mkIf cfg.enable { + users.users.wakapi = { + inherit group; + isSystemUser = true; + }; + users.groups.wakapi = {}; + + systemd.services.wakapi = { + after = ["network.target"]; + #path = with pkgs; [openssl]; + serviceConfig = { + User = user; + Group = group; + EnvironmentFile = [configFile] ++ optional (cfg.environmentFile != null) cfg.environmentFile; + ExecStart = "${cfg.package}/bin/wakapi"; + LimitNOFILE = "1048576"; + PrivateTmp = "true"; + PrivateDevices = "true"; + ProtectHome = "true"; + ProtectSystem = "strict"; + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + StateDirectory = "${cfg.stateDirectory}"; + WorkingDirectory = "/var/lib/${cfg.stateDirectory}"; + StateDirectoryMode = "0700"; + Restart = "always"; + }; + wantedBy = ["multi-user.target"]; + }; + systemd.tmpfiles.rules = [ + "D /var/lib/${cfg.stateDirectory}/data 755 ${user} ${group} - -" + ]; + }; +} diff --git a/nyx/modules/options/default.nix b/nyx/modules/options/default.nix new file mode 100644 index 0000000..bdd10e2 --- /dev/null +++ b/nyx/modules/options/default.nix @@ -0,0 +1,14 @@ +{ + imports = [ + ./docs # internal module system documentation and linking + ./device # device-specific declarations, hardware-specific + ./meta # internal read-only system manifests for easy access to system details + ./profiles # profiles allow the system to batch enable programs without hassle + ./system # system-level declarations, software-specific + ./theme # theme packages and configurations + ./usrEnv # user environment, such as main system user or + + ./removed.nix # options that have been fully deprecated + ./renamed.nix # options that have been moved or relocated. Will throw a warning if they are used + ]; +} diff --git a/nyx/modules/options/device/capabilities.nix b/nyx/modules/options/device/capabilities.nix new file mode 100644 index 0000000..a895a86 --- /dev/null +++ b/nyx/modules/options/device/capabilities.nix @@ -0,0 +1,25 @@ +{lib, ...}: let + inherit (lib) mkOption types; +in { + options.modules.device = { + # bluetooth is an insecure protocol if left unchedked, so while this defaults to true + # but the bluetooth.enable option does and should not. + hasBluetooth = mkOption { + type = types.bool; + default = true; + description = "Whether or not the system has bluetooth support"; + }; + + hasSound = mkOption { + type = types.bool; + default = true; + description = "Whether the system has sound support (usually true except for servers)"; + }; + + hasTPM = mkOption { + type = types.bool; + default = false; + description = "Whether the system has tpm support"; + }; + }; +} diff --git a/nyx/modules/options/device/default.nix b/nyx/modules/options/device/default.nix new file mode 100644 index 0000000..aa3fbd6 --- /dev/null +++ b/nyx/modules/options/device/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./capabilities.nix + ./hardware.nix + ]; +} diff --git a/nyx/modules/options/device/hardware.nix b/nyx/modules/options/device/hardware.nix new file mode 100644 index 0000000..4c75774 --- /dev/null +++ b/nyx/modules/options/device/hardware.nix @@ -0,0 +1,82 @@ +{lib, ...}: let + inherit (lib) mkOption mkEnableOption types; +in { + options.modules.device = { + type = mkOption { + type = types.enum ["laptop" "desktop" "server" "hybrid" "lite" "vm"]; + default = ""; + description = '' + The type/purpose of the device that will be used within the rest of the configuration. + - laptop: portable devices with batter optimizations + - desktop: stationary devices configured for maximum performance + - server: server and infrastructure + - hybrid: provide both desktop and server functionality + - lite: a lite device, such as a raspberry pi + - vm: a virtual machine + ''; + }; + + # the type of cpu your system has - vm and regular cpus currently do not differ + # as I do not work with vms, but they have been added for forward-compatibility + # TODO: make this a list - apparently more than one cpu on a device is still doable + cpu = { + type = mkOption { + type = with types; nullOr (enum ["pi" "intel" "vm-intel" "amd" "vm-amd"]); + default = null; + description = '' + The manifaturer/type of the primary system CPU. + + Determines which ucode services will be enabled and provides additional kernel packages + ''; + }; + + amd = { + pstate.enable = mkEnableOption "AMD P-State Driver"; + zenpower = { + enable = mkEnableOption "AMD Zenpower Driver"; + args = mkOption { + type = types.str; + default = "-p 0 -v 3C -f A0"; # Pstate 0, 1.175 voltage, 4000 clock speed + description = '' + The percentage of the maximum clock speed that the CPU will be limited to. + + This is useful for reducing power consumption and heat generation on laptops + and desktops + ''; + }; + }; + }; + }; + + gpu = { + type = mkOption { + type = with types; nullOr (enum ["pi" "amd" "intel" "nvidia" "hybrid-nv" "hybrid-amd"]); + default = null; + description = '' + The manifaturer/type of the primary system GPU. Allows the correct GPU + drivers to be loaded, potentially optimizing video output performance + ''; + }; + }; + + monitors = mkOption { + type = with types; listOf str; + default = []; + description = '' + A list of monitors connected to the system. + + This does not affect any drivers and such, it is only necessary for + declaring things like monitors in window manager configurations. + It is not necessary to declare this, but wallpaper and workspace + configurations will be affected by the monitors list + + ::: {.tip} + Monitors should be listed from left to right in the order they are placed + assuming the leftmost (first element) is the primary one. This is not a + solution to the possibility of a monitor being placed above or below another + but it currently works. + ::: + ''; + }; + }; +} diff --git a/nyx/modules/options/docs/assets/default-style.scss b/nyx/modules/options/docs/assets/default-style.scss new file mode 100644 index 0000000..0a3d1bb --- /dev/null +++ b/nyx/modules/options/docs/assets/default-style.scss @@ -0,0 +1,449 @@ +// Define variables for commonly used colors and font sizes +$primary-color: #8dc8f4; +$secondary-color: #7fb3dc; +$link-hover-color: #6ac7da; +$link-active-color: #6ac7da; +$text-color: #afbded; +$background-color: #1e1e2e; + +$heading-color: #8cc6f2; +$blockquote-color: #afbded; +$table-header-bg: #afbded; +$table-border-color: #2e2e46; + +$font-family: Roboto, Georgia, Palatino, Times, "Times New Roman", Lexend, serif; +$monospace-font: monospace; +$base-font-size: 14px; + +// Define mixins for commonly used styles +@mixin heading-styles { + color: $heading-color; + line-height: 125%; + margin-top: 2em; + font-weight: normal; +} + +@mixin media-query($breakpoint) { + @media only screen and (min-width: $breakpoint) { + @content; + } +} + +@keyframes bounce { + 0%, + 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-5px); + } +} + +// Begin SCSS stylesheet +html { + font-size: 100%; + overflow-y: scroll; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + color: $text-color; + font-family: $font-family; + font-size: $base-font-size; + line-height: 1.7; + padding: 1em; + margin: auto; + max-width: 42em; + background: $background-color; + + @include media-query(480px) { + font-size: 14px; + } + + @include media-query(768px) { + font-size: 16px; + } +} + +a { + color: $primary-color; + text-decoration: none; + + &:visited { + color: $secondary-color; + } + + &:hover { + color: $link-hover-color; + } + + &:active { + color: $link-active-color; + } + + &:focus { + outline: thin dotted; + } + + &::-moz-selection { + background: rgba($primary-color, 0.3); + color: $text-color; + } + + &::selection { + background: rgba($primary-color, 0.3); + color: $text-color; + } + + &::-moz-selection { + background: rgba($primary-color, 0.3); + color: $primary-color; + } + + &::selection { + background: rgba($primary-color, 0.3); + color: $primary-color; + } +} + +p { + margin: 1em 0; +} + +img { + max-width: 100%; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + @include heading-styles; + + h4, + h5, + h6 { + font-weight: bold; + } + + h1 { + font-size: 2.5em; + } + + h2 { + font-size: 2em; + } + + h3 { + font-size: 1.5em; + } + + h4 { + font-size: 1.2em; + } + + h5 { + font-size: 1em; + } + + h6 { + font-size: 0.9em; + } +} + +blockquote { + color: $blockquote-color; + margin: 0; + padding-left: 3em; + border-left: 0.5em $background-color solid; +} + +hr { + display: block; + height: 2px; + border: 0; + border-top: 1px solid $table-border-color; + border-bottom: 1px solid $background-color; + margin: 1em 0; + padding: 0; +} + +pre, +code, +kbd, +samp { + color: $text-color; + font-family: $monospace-font; + _font-family: "courier new", monospace; + font-size: 0.98em; +} + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +b, +strong { + font-weight: bold; +} + +dfn { + font-style: italic; +} + +ins { + background: $primary-color; + color: $text-color; + text-decoration: none; +} + +mark { + background: $primary-color; + color: $text-color; + font-style: italic; + font-weight: bold; +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + + sup { + top: -0.5em; + } + + sub { + bottom: -0.25em; + } +} + +ul, +ol { + margin: 1em 0; + padding: 0 0 0 2em; + + ul ul, + ol ol { + margin: 0.3em 0; + } +} + +dl { + margin-bottom: 1em; +} + +dt { + font-weight: bold; + margin-bottom: 0.8em; +} + +dd { + margin: 0 0 0.8em 2em; + + &:last-child { + margin-bottom: 0; + } +} + +img { + border: 0; + -ms-interpolation-mode: bicubic; + vertical-align: middle; +} + +figure { + display: block; + text-align: center; + margin: 1em 0; + + img { + border: none; + margin: 0 auto; + } + + figcaption { + font-size: 0.8em; + font-style: italic; + margin: 0 0 0.8em; + } +} + +table { + margin-bottom: 2em; + border-bottom: 1px solid $table-border-color; + border-right: 1px solid $table-border-color; + border-spacing: 0; + border-collapse: collapse; + + th { + padding: 0.2em 1em; + background-color: $table-header-bg; + border-top: 1px solid $table-border-color; + border-left: 1px solid $table-border-color; + } + + td { + padding: 0.2em 1em; + border-top: 1px solid $table-border-color; + border-left: 1px solid $table-border-color; + vertical-align: top; + } +} + +.author { + font-size: 1.2em; + text-align: center; +} + +@media print { + * { + background: transparent !important; + color: $text-color !important; + filter: none !important; + -ms-filter: none !important; + } + + body { + font-size: 12pt; + max-width: 100%; + } + + a, + a:visited { + text-decoration: underline; + } + + hr { + height: 1px; + border: 0; + border-bottom: 1px solid $text-color; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid $text-color; + padding-right: 1em; + page-break-inside: avoid; + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + @page :left { + margin: 15mm 20mm 15mm 10mm; + } + + @page :right { + margin: 15mm 10mm 15mm 20mm; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} + +// Sidebar style, contains the ToC with clickable links +.sidebar { + position: fixed; + top: 0; + left: -1000px; // Initially hidden by being yoten offscreen + height: 100%; + width: 490px; // Static content width. FIXME: ugh + background-color: darken($background-color, 2%); + overflow-x: hidden; // Horizontal scrollbar + overflow-y: auto; // Vertical scrollbar if needed + transition: left 0.3s; // "Smooth" slide animation + padding: 10px; + z-index: 1000; // Ensure sidebar is above content +} + +.sidebar.show { + left: 0; // Show sidebar when toggled + border: 1px solid darken($background-color, 5%); +} + +// Togglee sidebar +.toggle-btn { + position: fixed; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + color: lighten($text-color, 2%); + font-size: 16px; + transition: left 0.3s; + + &:hover { + color: lighten($text-color, 4%); + } +} + +.toggle-btn.left { + left: 20px; +} + +.toggle-btn.right { + left: 520px; +} + +// Go back button +.go-back-btn { + position: fixed; + bottom: 20px; + right: 20px; + width: 50px; + height: 50px; + background-color: lighten($background-color, 4%); + color: $text-color; + border-radius: 10px; + cursor: pointer; + z-index: 9999; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.3s ease; + + &:hover { + color: lighten($background-color, 4%); + background-color: lighten($background-color, 8%); + } + + i { + font-size: 20px; + } +} diff --git a/nyx/modules/options/docs/assets/default-template.html b/nyx/modules/options/docs/assets/default-template.html new file mode 100644 index 0000000..9a871e6 --- /dev/null +++ b/nyx/modules/options/docs/assets/default-template.html @@ -0,0 +1,117 @@ + + + + + + + $for(author-meta)$ + + $endfor$ $if(date-meta)$ + + $endif$ $if(keywords)$ + + $endif$ $if(description-meta)$ + + $endif$ + $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ + + $for(css)$ + + $endfor$ $for(header-includes)$ $header-includes$ $endfor$ $if(math)$ + $if(mathjax)$ + + $endif$ $math$ $endif$ + + + + + + $for(include-before)$ $include-before$ $endfor$ $if(title)$ +

+

$title$

+ $if(subtitle)$ +

$subtitle$

+ $endif$ $for(author)$ +

$author$

+ $endfor$ $if(date)$ +

$date$

+ $endif$ $if(abstract)$ +
+
$abstract-title$
+ $abstract$ +
+ $endif$ +
+ $endif$ + + +
+ +
+ + + + + +
$body$
+ + +
+ +
+ + + + $for(include-after)$ $include-after$ $endfor$ + + diff --git a/nyx/modules/options/docs/assets/syntax.json b/nyx/modules/options/docs/assets/syntax.json new file mode 100644 index 0000000..fd4e224 --- /dev/null +++ b/nyx/modules/options/docs/assets/syntax.json @@ -0,0 +1,211 @@ +{ + "text-color": null, + "background-color": null, + "line-number-color": "#aaaaaa", + "line-number-background-color": null, + "text-styles": { + "Alert": { + "text-color": "#ff0000", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Annotation": { + "text-color": "#60a0b0", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "Attribute": { + "text-color": "#7d9029", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "BaseN": { + "text-color": "#40a070", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "BuiltIn": { + "text-color": "#008000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Char": { + "text-color": "#4070a0", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Comment": { + "text-color": "#60a0b0", + "background-color": null, + "bold": false, + "italic": true, + "underline": false + }, + "CommentVar": { + "text-color": "#60a0b0", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "Constant": { + "text-color": "#880000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "ControlFlow": { + "text-color": "#007020", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "DataType": { + "text-color": "#902000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "DecVal": { + "text-color": "#40a070", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Documentation": { + "text-color": "#ba2121", + "background-color": null, + "bold": false, + "italic": true, + "underline": false + }, + "Error": { + "text-color": "#ff0000", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Extension": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Float": { + "text-color": "#40a070", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Function": { + "text-color": "#06287e", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Import": { + "text-color": "#008000", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Information": { + "text-color": "#60a0b0", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "Keyword": { + "text-color": "#007020", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Operator": { + "text-color": "#666666", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Other": { + "text-color": "#007020", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Preprocessor": { + "text-color": "#bc7a00", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "SpecialChar": { + "text-color": "#4070a0", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "SpecialString": { + "text-color": "#bb6688", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "String": { + "text-color": "#4070a0", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Variable": { + "text-color": "#19177c", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "VerbatimString": { + "text-color": "#4070a0", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Warning": { + "text-color": "#60a0b0", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + } + } +} diff --git a/nyx/modules/options/docs/default.nix b/nyx/modules/options/docs/default.nix new file mode 100644 index 0000000..a4b76de --- /dev/null +++ b/nyx/modules/options/docs/default.nix @@ -0,0 +1,101 @@ +{ + options, + config, + pkgs, + lib, + ... +}: let + inherit (lib.options) mkEnableOption mkOption literalExpression; + inherit (lib.types) nullOr path str package; + inherit (lib.strings) optionalString; + + cfg = config.modules.documentation; + + configMD = + (pkgs.nixosOptionsDoc { + options = options.modules; + documentType = "appendix"; + inherit (cfg) warningsAreErrors; + }) + .optionsCommonMark; + + compileCss = pkgs.runCommandLocal "compile-css" {} '' + mkdir -p $out + ${cfg.scssExecutable} -t expanded ${cfg.scss} > $out/sys-docs-style.css + ''; + + docs-html = pkgs.runCommand "nyxos-docs" {nativeBuildInputs = [pkgs.pandoc];} ( + '' + # convert to pandoc markdown instead of using commonmark directly, + # as the former automatically generates heading ids and TOC links. + pandoc \ + --from commonmark \ + --to markdown \ + ${configMD} | + + + # convert pandoc markdown to html using our own template and css files + # where available. --sandbox is passed for extra security. + pandoc \ + --sandbox \ + --from markdown \ + --to html \ + --metadata title="NyxOS Docs" \ + --toc \ + --standalone \ + '' + + optionalString (cfg.templatePath != null) ''--template ${cfg.templatePath} \'' + + optionalString (cfg.scss != null) ''--css=${compileCss.outPath}/sys-docs-style.css \'' + + "-o $out" + ); +in { + options.modules.documentation = { + enable = mkEnableOption '' + generation of internal module documentation for my system configuration. If enabled + the module options will be rendered with pandoc and linked to `/etc/nyxos` + ''; + + warningsAreErrors = mkEnableOption '' + enforcing build failure on missing option descriptions. While disabled, warnings will be + displayed, but will not cause the build to fail. + ''; + + scss = mkOption { + default = ./assets/default-style.scss; + type = nullOr path; + description = "CSS to apply to the docs"; + }; + + scssExecutable = mkOption { + default = lib.getExe' pkgs.sass "scss"; + example = literalExpression "${pkgs.dart-sass}/bin/sass"; + type = nullOr str; + description = "Path to the sass executable"; + }; + + templatePath = mkOption { + default = ./assets/default-template.html; + type = nullOr path; + description = "The template to use for the docs"; + }; + + # the following are exposed as module options for us to be able to build them in isolation + # i.e. without building the rest of the system + markdownPackage = mkOption { + default = configMD; + type = nullOr package; + readOnly = true; + description = "The package containing generated markdown"; + }; + + htmlPackage = mkOption { + default = docs-html; + type = nullOr package; + readOnly = true; + description = "The package containing generated HTML"; + }; + + # TODO: custom syntax highlighting via syntax.json path OR attrset to json + # we love json. yaml is json. we should use yaml. yes. + }; +} diff --git a/nyx/modules/options/meta/default.nix b/nyx/modules/options/meta/default.nix new file mode 100644 index 0000000..cedfdfa --- /dev/null +++ b/nyx/modules/options/meta/default.nix @@ -0,0 +1,52 @@ +{ + config, + lib, + ... +}: let + inherit (lib) types; + inherit (lib.options) mkOption; + + env = config.modules.usrEnv; +in { + options.meta = { + hostname = mkOption { + type = types.str; + default = config.networking.hostName; + readOnly = true; + description = '' + The canonical hostname of the machine. + + Is usually used to identify - i.e name machines internally + or on the same Headscale network. This option must be declared + in `hosts.nix` alongside host system. + ''; + }; + + system = mkOption { + type = types.str; + default = config.system.build.toplevel.system; + readOnly = true; + description = '' + The architecture of the machine. + ''; + }; + + isWayland = mkOption { + type = types.bool; + # TODO: there must be a better way to do this + default = with env.desktops; (sway.enable || hyprland.enable); + # readOnly = true; # TODO + description = '' + Whether to enable Wayland exclusive modules, this contains a wariety + of packages, modules, overlays, XDG portals and so on. + + Generally includes: + - Wayland nixpkgs overlay + - Wayland only services + - Wayland only programs + - Wayland compatible versions of packages as opposed + to the defaults + ''; + }; + }; +} diff --git a/nyx/modules/options/profiles/default.nix b/nyx/modules/options/profiles/default.nix new file mode 100644 index 0000000..f2c374a --- /dev/null +++ b/nyx/modules/options/profiles/default.nix @@ -0,0 +1,20 @@ +{lib, ...}: let + inherit (lib) mkEnableOption; +in { + options.modules.profiles = { + workstation.enable = mkEnableOption '' + the Desktop profile + + This profile is intended for systems that are workstations: i.e + systems that must contain a suite of applications tailored for + daily usage, mainly for working, studying or programming. + ''; + + gaming.enable = mkEnableOption '' + the Gaming profile + + This profile contains basic platforms and utilities that can be + used for gaming, such as but not limited to Steam and Lutris. + ''; + }; +} diff --git a/nyx/modules/options/removed.nix b/nyx/modules/options/removed.nix new file mode 100644 index 0000000..6adb674 --- /dev/null +++ b/nyx/modules/options/removed.nix @@ -0,0 +1,22 @@ +{lib, ...}: let + inherit (lib) mkRemovedOptionModule; +in { + imports = [ + (mkRemovedOptionModule ["modules" "services" "override"] '' + service overrides have been removed in favor of the new `modules.services..enable` syntax + '') + + (mkRemovedOptionModule ["modules" "usrEnv" "noiseSuppressor"] '' + `modules.usrEnv.noiseSuppressor` has been removed as programs managed by the module + are better enabled manually and individually under `modules.system.programs..enable` + '') + + /* + (mkRemovedOptionModule ["modules" "usrEnv" "isWayland"] '' + `isWayland` has been moved to the meta module as a read-only option that will be set internally + based on the desktop environments the host is running, and can no longer be set manually. Please + move to using `modules.usrEnv.desktop` and `modules.usrEnv.dektops..enable` instead. + '') + */ + ]; +} diff --git a/nyx/modules/options/renamed.nix b/nyx/modules/options/renamed.nix new file mode 100644 index 0000000..db076c7 --- /dev/null +++ b/nyx/modules/options/renamed.nix @@ -0,0 +1,30 @@ +{lib, ...}: let + inherit (lib) mkRenamedOptionModule; +in { + imports = [ + # renamed modules for the device module + (mkRenamedOptionModule ["modules" "device" "yubikeySupport"] ["modules" "system" "yubikeySupport"]) + + # renamed modules for the userEnv module + (mkRenamedOptionModule ["modules" "usrEnv" "autologin"] ["modules" "system" "autoLogin"]) + (mkRenamedOptionModule ["modules" "usrEnv" "isWayland"] ["meta" "isWayland"]) + + # renamed options for the system module + (mkRenamedOptionModule ["modules" "system" "networking" "wirelessBackend"] ["modules" "system" "networking" "wireless" "backend"]) + (mkRenamedOptionModule ["modules" "system" "networking" "useTailscale"] ["modules" "system" "networking" "tailscale" "client" "enable"]) + (mkRenamedOptionModule ["modules" "system" "networking" "tailscale" "defaultFlags"] ["modules" "system" "networking" "tailscale" "flags" "default"]) + (mkRenamedOptionModule ["modules" "system" "networking" "tailscale" "client" "enable"] ["modules" "system" "networking" "tailscale" "isClient"]) + (mkRenamedOptionModule ["modules" "system" "networking" "tailscale" "server" "enable"] ["modules" "system" "networking" "tailscale" "isServer"]) + + (mkRenamedOptionModule ["modules" "system" "services" "atticd" "enable"] ["modules" "system" "services" "bincache" "atticd" "enable"]) + (mkRenamedOptionModule ["modules" "system" "services" "wireguard" "enable"] ["modules" "system" "services" "networking" "wireguard" "enable"]) + (mkRenamedOptionModule ["modules" "system" "services" "headscale" "enable"] ["modules" "system" "services" "networking" "headscale" "enable"]) + + (mkRenamedOptionModule ["modules" "system" "boot" "enableInitrdTweaks"] ["modules" "system" "boot" "initrd" "enableTweaks"]) + (mkRenamedOptionModule ["modules" "system" "security" "secureBoot"] ["modules" "system" "boot" "secureBoot"]) + + (mkRenamedOptionModule ["modules" "system" "services" "gitea" "enable"] ["modules" "system" "services" "forgejo" "enable"]) + (mkRenamedOptionModule ["modules" "system" "services" "mastodon" "enable"] ["modules" "system" "services" "social" "mastodon" "enable"]) + (mkRenamedOptionModule ["modules" "system" "services" "matrix" "enable"] ["modules" "system" "services" "social" "matrix" "enable"]) + ]; +} diff --git a/nyx/modules/options/system/activation.nix b/nyx/modules/options/system/activation.nix new file mode 100644 index 0000000..9364709 --- /dev/null +++ b/nyx/modules/options/system/activation.nix @@ -0,0 +1,7 @@ +{lib, ...}: let + inherit (lib) mkEnableOption; +in { + options.modules.system.activation = { + diffGenerations = mkEnableOption "diff view between rebuilds"; + }; +} diff --git a/nyx/modules/options/system/boot.nix b/nyx/modules/options/system/boot.nix new file mode 100644 index 0000000..4023ef7 --- /dev/null +++ b/nyx/modules/options/system/boot.nix @@ -0,0 +1,133 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) literalExpression mkEnableOption mkOption types; + + cfg = config.modules.system.boot; +in { + # pre-boot and bootloader configurations + options.modules.system.boot = { + enableKernelTweaks = mkEnableOption "security and performance related kernel parameters"; + recommendedLoaderConfig = mkEnableOption "tweaks for common bootloader configs per my liking"; + loadRecommendedModules = mkEnableOption "kernel modules that accommodate for most use cases"; + tmpOnTmpfs = + mkEnableOption '' + `/tmp` living on tmpfs. false means it will be cleared manually on each reboot + + This option defaults to `true` if the host provides patches to the kernel package in + `boot.kernelPatches` + '' + // {default = config.boot.kernelPatches == [];}; + + secureBoot = mkEnableOption '' + secure-boot with the necessary packages. Requires systemd-boot to be disabled + ''; + + silentBoot = + mkEnableOption '' + almost entirely silent boot process through `quiet` kernel parameter + '' + // {default = config.modules.system.boot.plymouth.enable;}; + + initrd = { + enableTweaks = mkEnableOption "quality of life tweaks for the initrd stage"; + optimizeCompressor = mkEnableOption '' + initrd compression algorithm optimizations for size. + + Enabling this option will force initrd to use zstd (default) with + level 19 and -T0 (STDIN). This will reduce the initrd size greatly + at the cost of compression speed. + + Not recommended for low-end hardware. + ''; + }; + + kernel = mkOption { + type = with types; nullOr raw; + default = pkgs.linuxPackages_latest; + example = literalExpression "pkgs.linuxPackages_latest"; + description = "The kernel to use for the system."; + }; + + extraModprobeConfig = mkOption { + type = types.str; + default = ''options hid_apple fnmode=1''; + description = "Extra modprobe config that will be passed to system modprobe config."; + }; + + extraKernelParams = mkOption { + type = with types; listOf str; + default = []; + description = "Extra kernel parameters to be added to the kernel command line."; + }; + + extraModulePackages = mkOption { + type = with types; listOf package; + default = []; + example = literalExpression ''with config.boot.kernelPackages; [acpi_call]''; + description = "Extra kernel modules to be loaded."; + }; + + loader = mkOption { + type = types.enum ["none" "grub" "systemd-boot"]; + default = "none"; + description = "The bootloader that should be used for the device."; + }; + + grub = { + device = mkOption { + type = with types; nullOr str; + default = "nodev"; + description = "The device to install the bootloader to."; + }; + }; + + plymouth = { + enable = mkEnableOption "Plymouth boot splash"; + withThemes = mkEnableOption '' + Whether or not themes from https://github.com/adi1090x/plymouth-themes + should be enabled and configured + ''; + + pack = mkOption { + type = types.enum [1 2 3 4]; + default = 3; + description = "The pack number for the theme to be selected from."; + }; + + theme = mkOption { + type = types.str; + default = "hud_3"; + description = "The theme name from the selected theme pack"; + }; + }; + + memtest = { + enable = mkEnableOption "memtest86+"; + package = mkOption { + type = types.package; + default = pkgs.memtest86plus; + description = "The memtest package to use."; + }; + }; + }; + + config = { + assertions = [ + { + assertion = cfg.kernel != null; + message = '' + Your system does not specify a kernel package. This is intended behaviour + and is to avoid specifying default kernels that are not compatible with + active hardware. + + To supress this error, you must set `config.modules.system.boot.kernel` + to a valid kernel package. + ''; + } + ]; + }; +} diff --git a/nyx/modules/options/system/containers.nix b/nyx/modules/options/system/containers.nix new file mode 100644 index 0000000..ce53c77 --- /dev/null +++ b/nyx/modules/options/system/containers.nix @@ -0,0 +1,45 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkEnableOption mkOption types literalExpression; + + cfg = config.modules.system.containers; +in { + options.modules.system.containers = { + enable = mkEnableOption "systemd-nspawn containers"; + + availableContainers = mkOption { + type = with types; listOf str; + default = ["alpha" "beta" "gamma"]; + readOnly = true; + internal = true; + description = '' + Containers that are made available to the host system, and can freely be enabled using + the {option}`enabledContainers` option. + + Do keep in mind that nspawn-containers not yet provide host isolation, and elevated privileges + inside the container can be used to escape the container and gain access to the host system. + + Only enable containers that you know are properly sandboxed. + ''; + }; + + enabledContainers = mkOption { + type = with types; listOf (enum cfg.availableContainers); + default = []; + example = literalExpression ''["alpha" "beta"]''; + description = '' + A list of enabled containers selected from the list of available containers. + + Enabling a container may not always mean it will start automatically, and must + done so with care. + + Container Specialization: + - alpha: Sandboxed playground for testing software, networking and builds. + - beta: Minimal container for running an ephemeral PostgreSQL database. + ''; + }; + }; +} diff --git a/nyx/modules/options/system/default.nix b/nyx/modules/options/system/default.nix new file mode 100644 index 0000000..0a6fd01 --- /dev/null +++ b/nyx/modules/options/system/default.nix @@ -0,0 +1,128 @@ +{ + config, + lib, + ... +}: let + inherit (lib) optionals mkEnableOption mkOption types; +in { + imports = [ + # configuration options for nixos activation scripts + ./activation.nix + + # boot/impermanence mounts + ./boot.nix + ./impermanence.nix + + # network and overall hardening + ./networking + ./security.nix + ./encryption.nix + + # emulation and virtualization + ./emulation.nix + ./virtualization.nix + + # package and program related options + ./services + ./programs + + # systemd-nspawn containers + ./containers.nix + ]; + config = { + warnings = + (optionals (config.modules.system.fs == []) [ + '' + You have not added any filesystems to be supported by your system. You may end up with an unbootable system! + + Consider setting {option}`config.modules.system.fs` in your configuration + '' + ]) + ++ (optionals (config.modules.system.users == []) [ + '' + You have not added any users to be supported by your system. You may end up with an unbootable system! + + Consider setting {option}`config.modules.system.users` in your configuration + '' + ]); + }; + + options.modules.system = { + mainUser = mkOption { + type = types.enum config.modules.system.users; + default = builtins.elemAt config.modules.system.users 0; + description = '' + The username of the main user for your system. + + In case of a multiple systems, this will be the user with priority in ordered lists and enabled options. + ''; + }; + + users = mkOption { + type = with types; listOf str; + default = ["notashelf"]; + description = "A list of home-manager users on the system."; + }; + + autoLogin = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable passwordless login. This is generally useful on systems with + FDE (Full Disk Encryption) enabled. It is a security risk for systems without FDE. + ''; + }; + + fs = mkOption { + type = with types; listOf str; + default = ["vfat" "ext4" "btrfs"]; # TODO: zfs, ntfs + description = '' + A list of filesystems available supported by the system + it will enable services based on what strings are found in the list. + + It would be a good idea to keep vfat and ext4 so you can mount common external storage. + ''; + }; + + yubikeySupport = { + enable = mkEnableOption "yubikey support"; + deviceType = mkOption { + type = with types; nullOr (enum ["NFC5" "nano"]); + default = null; + description = "A list of device models to enable Yubikey support for"; + }; + }; + + sound = { + enable = mkEnableOption "sound related programs and audio-dependent programs"; + }; + + video = { + enable = mkEnableOption "video drivers and programs that require a graphical user interface"; + }; + + bluetooth = { + enable = mkEnableOption "bluetooth modules, drivers and configuration program(s)"; + }; + + # should the device enable printing module and try to load common printer modules + # you might need to add more drivers to the printing module for your printer to work + printing = { + enable = mkEnableOption "printing"; + extraDrivers = mkOption { + type = with types; listOf str; + default = []; + description = "A list of extra drivers to enable for printing"; + }; + + "3d" = { + enable = mkEnableOption "3D printing suite"; + extraPrograms = mkOption { + type = with types; listOf package; + default = []; + description = "A list of extra programs to enable for 3D printing"; + }; + }; + }; + }; +} diff --git a/nyx/modules/options/system/emulation.nix b/nyx/modules/options/system/emulation.nix new file mode 100644 index 0000000..348c16f --- /dev/null +++ b/nyx/modules/options/system/emulation.nix @@ -0,0 +1,29 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib) mkEnableOption mkOption types; +in { + options.modules.system.emulation = { + # should we enable emulation for additional architechtures? + # enabling this option will make it so that you can build for, e.g. + # aarch64 on x86_&4 and vice verse - not recommended on weaker machines + enable = mkEnableOption '' + emulation of additional arcitechtures via binfmt. Enabling this option will make it so that the system can build for + addiitonal systems such as aarc64 on x86_64 and vice versa. + ''; + + systems = mkOption { + type = with types; listOf str; + # default = ["x86_64-linux" "aarch64-linux" "i686-linux"]; + default = builtins.filter (system: system != pkgs.system) ["aarch64-linux" "i686-linux"]; + description = '' + Systems that will be emulated by the host system. + + If overriding the default, you must make sure that the list of systems does not contain the same system as the host + in order to avoid an unbootable machine. + ''; + }; + }; +} diff --git a/nyx/modules/options/system/encryption.nix b/nyx/modules/options/system/encryption.nix new file mode 100644 index 0000000..0ddd4ce --- /dev/null +++ b/nyx/modules/options/system/encryption.nix @@ -0,0 +1,57 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkEnableOption mkOption types mkIf; +in { + config = mkIf config.modules.system.encryption.enable { + warnings = + if config.modules.system.encryption.device == "" + then [ + '' + You have enabled LUKS encryption, but have not selected a device, you may not be able to decrypt your disk on boot. + '' + ] + else []; + }; + options.modules.system.encryption = { + enable = mkEnableOption "LUKS encryption"; + + device = mkOption { + type = types.str; # this should actually be a list + default = ""; + description = '' + The LUKS label for the device that will be decrypted on boot. + Currently does not support multiple devices at once. + ''; + }; + + keyFile = mkOption { + type = with types; nullOr str; + default = null; + description = '' + The path to the keyfile that will be used to decrypt the device. + Needs to be an absolute path, and the file must exist. Set to `null` + to disable. + ''; + }; + + keySize = mkOption { + type = types.int; + default = 4096; + description = '' + The size of the keyfile in bytes. + ''; + }; + + fallbackToPassword = mkOption { + type = types.bool; + default = !config.boot.initrd.systemd.enable; + description = '' + Whether or not to fallback to password authentication if the keyfile + is not present. + ''; + }; + }; +} diff --git a/nyx/modules/options/system/impermanence.nix b/nyx/modules/options/system/impermanence.nix new file mode 100644 index 0000000..ee1ac2d --- /dev/null +++ b/nyx/modules/options/system/impermanence.nix @@ -0,0 +1,87 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkEnableOption mkOption literalExpression; + + cfg = config.modules.system.impermanence; +in { + options.modules.system.impermanence = { + enable = mkOption { + default = cfg.root.enable || cfg.home.enable; + readOnly = true; + description = '' + Internal option for deciding if Impermanence module is enabled + based on the values of `modules.system.impermanence.root.enable` + and `modules.system.impermanence.home.enable`. + ''; + }; + + root = { + enable = mkEnableOption '' + the Impermanence module for persisting important state directories. + By default, Impermanence will not touch user's $HOME, which is not + ephemeral unlike root. + ''; + + extraFiles = mkOption { + default = []; + example = literalExpression ''["/etc/nix/id_rsa"]''; + description = '' + Additional files in the root to link to persistent storage. + ''; + }; + + extraDirectories = mkOption { + default = []; + example = literalExpression ''["/var/lib/libvirt"]''; + description = '' + Additional directories in the root to link to persistent + storage. + ''; + }; + }; + + home = { + enable = mkEnableOption '' + the Impermanence module for persisting important state directories. + This option will also make user's home ephemeral, on top of the root subvolume + ''; + + mountDotfiles = mkOption { + default = true; + description = '' + Whether the repository with my configuration flake should be bound to a location + in $HOME after a rebuild. It will symlink ''${self} to ~/.config/nyx where I + usually put my configuration files + ''; + }; + + extraFiles = mkOption { + default = []; + example = literalExpression '' + [ + ".gnupg/pubring.kbx" + ".gnupg/sshcontrol" + ".gnupg/trustdb.gpg" + ".gnupg/random_seed" + ] + ''; + description = '' + Additional files in the home directory to link to persistent + storage. + ''; + }; + + extraDirectories = mkOption { + default = []; + example = literalExpression ''[".config/gsconnect"]''; + description = '' + Additional directories in the home directory to link to + persistent storage. + ''; + }; + }; + }; +} diff --git a/nyx/modules/options/system/networking/default.nix b/nyx/modules/options/system/networking/default.nix new file mode 100644 index 0000000..fea66a3 --- /dev/null +++ b/nyx/modules/options/system/networking/default.nix @@ -0,0 +1,36 @@ +{lib, ...}: let + inherit (lib) mkEnableOption mkOption types; +in { + imports = [ + ./nftables.nix + ./tailscale.nix + ]; + options.modules.system.networking = { + nftables.enable = mkEnableOption "nftables firewall"; + tarpit.enable = mkEnableOption "endlessh-go tarpit"; + optimizeTcp = mkEnableOption "TCP optimizations"; + + wireless = { + allowImperative = mkEnableOption '' + imperative networking via wpa_cli. + + Enabling this option will make it so that users in the wheel group will + be able to manage networking via wpa_cli. + ''; + + backend = mkOption { + type = types.enum ["iwd" "wpa_supplicant"]; + default = "wpa_supplicant"; + description = '' + Backend that will be used for wireless connections using either + `networking.wireless` or `networking.networkmanager.wifi.backend` + + Defaults to wpa_supplicant until iwd is stable. + ''; + }; + }; + + # TODO: optionally use encrypted DNS + # encryptDns = mkOption {}; + }; +} diff --git a/nyx/modules/options/system/networking/nftables.nix b/nyx/modules/options/system/networking/nftables.nix new file mode 100644 index 0000000..c84e604 --- /dev/null +++ b/nyx/modules/options/system/networking/nftables.nix @@ -0,0 +1,82 @@ +{lib, ...}: let + inherit (lib) mkTable mkPrerouteChain mkForwardChain mkOutputChain mkInputChain mkPostrouteChain mkIngressChain; +in { + options.networking.nftables.rules = { + # man nft(8) + netdev = mkTable "netdev address family netfilter table" { + filter.ingress = mkIngressChain "netdev"; + }; + + bridge = mkTable "bridge address family netfilter table" { + filter = { + prerouting = mkPrerouteChain "bridge"; + input = mkInputChain "bridge"; + forward = mkForwardChain "bridge"; + output = mkOutputChain "bridge"; + postrouting = mkPostrouteChain "bridge"; + }; + }; + + inet = mkTable "internet (IPv4/IPv6) address family netfilter table" { + filter = { + prerouting = mkPrerouteChain "inet"; + input = mkInputChain "inet"; + forward = mkForwardChain "inet"; + output = mkOutputChain "inet"; + postrouting = mkPostrouteChain "inet"; + }; + + nat = { + prerouting = mkPrerouteChain "inet"; + input = mkInputChain "inet"; + output = mkOutputChain "inet"; + postrouting = mkPostrouteChain "inet"; + }; + }; + + arp = mkTable "ARP (IPv4) address family netfilter table" { + filter = { + input = mkInputChain "arp"; + output = mkOutputChain "arp"; + }; + }; + + ip = mkTable "internet (IPv4) address family netfilter table" { + filter = { + prerouting = mkPrerouteChain "ip"; + input = mkInputChain "ip"; + forward = mkForwardChain "ip"; + output = mkOutputChain "ip"; + postrouting = mkPostrouteChain "ip"; + }; + + nat = { + prerouting = mkPrerouteChain "ip"; + input = mkInputChain "ip"; + output = mkOutputChain "ip"; + postrouting = mkPostrouteChain "ip"; + }; + + route.output = mkForwardChain "ip"; + }; + + ip6 = mkTable "internet (IPv6) address family netfilter table" { + filter = { + prerouting = mkPrerouteChain "ip6"; + input = mkInputChain "ip6"; + forward = mkForwardChain "ip6"; + output = mkOutputChain "ip6"; + postrouting = mkPostrouteChain "ip6"; + }; + + nat = { + prerouting = mkPrerouteChain "ip6"; + input = mkInputChain "ip6"; + output = mkOutputChain "ip6"; + postrouting = mkPostrouteChain "ip6"; + }; + + route.output = mkForwardChain "ip6"; + }; + }; +} diff --git a/nyx/modules/options/system/networking/tailscale.nix b/nyx/modules/options/system/networking/tailscale.nix new file mode 100644 index 0000000..1e25a69 --- /dev/null +++ b/nyx/modules/options/system/networking/tailscale.nix @@ -0,0 +1,76 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkEnableOption mkOption types; + + sys = config.modules.system; + cfg = sys.networking.tailscale; +in { + options.modules.system.networking.tailscale = { + enable = mkEnableOption "Tailscale VPN"; + autoLogin = mkEnableOption '' + systemd-service for bootstrapping a Tailscale connection automatically + ''; + + endpoint = mkOption { + type = types.str; + default = "https://hs.notashelf.dev"; + description = '' + The URL of the Tailscale control server to use. In case you + would like to use a self-hosted Headscale server, such as + the default value, you may change this value accordingly. + ''; + }; + + operator = mkOption { + type = types.str; + default = sys.mainUser; + description = '' + The name of the Tailscale operator to use. This is used to + avoid using sudo in command-line operations and if set, will + run the auto-authentication service as the specified user. + ''; + }; + + flags = { + default = mkOption { + type = with types; listOf str; + default = ["--ssh"]; + description = '' + A list of command-line flags that will be passed to the Tailscale + daemon automatically when it is started, using + {option}`config.services.tailscale.extraUpFlags` + + If `isServer` is set to true, the server-specific values will be + appended to the list defined in this option. + ''; + }; + }; + + isClient = mkOption { + type = types.bool; + default = cfg.enable; + example = true; + description = '' + Whether the target host should utilize Tailscale client features"; + + This option is mutually exlusive with {option}`tailscale.isServer` + as they both configure Taiscale, but with different flags + ''; + }; + + isServer = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Whether the target host should utilize Tailscale server features. + + This option is mutually exlusive with {option}`tailscale.isClient` + as they both configure Taiscale, but with different flags + ''; + }; + }; +} diff --git a/nyx/modules/options/system/programs/default.nix b/nyx/modules/options/system/programs/default.nix new file mode 100644 index 0000000..be35381 --- /dev/null +++ b/nyx/modules/options/system/programs/default.nix @@ -0,0 +1,94 @@ +{lib, ...}: let + inherit (lib) mkEnableOption mkOption types; +in { + imports = [ + ./gaming.nix + ]; + + options.modules.system.programs = { + gui.enable = mkEnableOption "GUI package sets" // {default = true;}; + cli.enable = mkEnableOption "CLI package sets" // {default = true;}; + dev.enable = mkEnableOption "development related package sets"; + + libreoffice.enable = mkEnableOption "LibreOffice suite"; + discord.enable = mkEnableOption "Discord messenger"; + element.enable = mkEnableOption "Element Matrix client"; + obs.enable = mkEnableOption "OBS Studio"; + spotify.enable = mkEnableOption "Spotify music player"; + thunderbird.enable = mkEnableOption "Thunderbird mail client"; + vscode.enable = mkEnableOption "Visual Studio Code"; + steam.enable = mkEnableOption "Steam game client"; + kdeconnect.enable = mkEnableOption "KDE Connect utility"; + webcord.enable = mkEnableOption "Webcord Discord client"; + zathura.enable = mkEnableOption "Zathura document viewer"; + nextcloud.enable = mkEnableOption "Nextcloud sync client"; + rnnoise.enable = mkEnableOption "RNNoise noise suppression plugin"; + noisetorch.enable = mkEnableOption "NoiseTorch noise suppression plugin"; + + chromium = { + enable = mkEnableOption "Chromium browser"; + ungoogle = mkOption { + type = types.bool; + default = true; + description = "Enable ungoogled-chromium features"; + }; + }; + + firefox = { + enable = mkEnableOption "Firefox browser"; + schizofox.enable = mkOption { + type = types.bool; + default = true; + description = "Enable Schizofox Firefox Tweaks"; + }; + }; + + editors = { + neovim.enable = mkEnableOption "Neovim text editor"; + helix.enable = mkEnableOption "Helix text editor"; + }; + + terminals = { + kitty.enable = mkEnableOption "Kitty terminal emulator"; + wezterm.enable = mkEnableOption "WezTerm terminal emulator"; + foot.enable = mkEnableOption "Foot terminal emulator"; + }; + + git = { + signingKey = mkOption { + type = types.str; + default = ""; + description = "The default gpg key used for signing commits"; + }; + }; + + # default program options + default = { + # what program should be used as the default terminal + terminal = mkOption { + type = types.enum ["foot" "kitty" "wezterm"]; + default = "kitty"; + }; + + fileManager = mkOption { + type = types.enum ["thunar" "dolphin" "nemo"]; + default = "dolphin"; + }; + + browser = mkOption { + type = types.enum ["firefox" "librewolf" "chromium"]; + default = "firefox"; + }; + + editor = mkOption { + type = types.enum ["neovim" "helix" "emacs"]; + default = "neovim"; + }; + + launcher = mkOption { + type = types.enum ["rofi" "wofi" "anyrun"]; + default = "rofi"; + }; + }; + }; +} diff --git a/nyx/modules/options/system/programs/gaming.nix b/nyx/modules/options/system/programs/gaming.nix new file mode 100644 index 0000000..53eaa35 --- /dev/null +++ b/nyx/modules/options/system/programs/gaming.nix @@ -0,0 +1,24 @@ +{ + config, + lib, + ... +}: let + inherit (lib.options) mkEnableOption; + inherit (config) modules; + + prg = modules.system.programs; +in { + options.modules.system.programs.gaming = { + enable = mkEnableOption '' + packages, services and warappers required for the device to be gaming-ready. + + Setting this option to true will also enable certain other options with + the option to disable them explicitly. + ''; + + steam.enable = mkEnableOption "Steam client" // {default = prg.gaming.enable;}; + gamemode.enable = mkEnableOption "Feral-Interactive's Gamemode with userspace optimizations" // {default = prg.gaming.enable;}; + gamescope.enable = mkEnableOption "Gamescope compositing manager" // {default = prg.gaming.enable;}; + mangohud.enable = mkEnableOption "MangoHud overlay" // {default = prg.gaming.enable;}; + }; +} diff --git a/nyx/modules/options/system/security.nix b/nyx/modules/options/system/security.nix new file mode 100644 index 0000000..04f8dff --- /dev/null +++ b/nyx/modules/options/system/security.nix @@ -0,0 +1,138 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib) mkOption mkEnableOption types; +in { + options.modules.system.security = { + fixWebcam = mkEnableOption "the purposefully disabled webcam by un-blacklisting the related kernel module."; + fprint.enable = mkEnableOption "Fingerprint reader service"; + tor.enable = mkEnableOption "Tor daemon"; + usbguard.enable = mkEnableOption "USBGuard service for blocking unauthorized USB devices"; + lockModules = mkEnableOption '' + kernel module locking to prevent kernel modules that are not specified in the config from being loaded + + This is a highly breaking option, and will break many things including virtualization + and firewall if the required modules are not explicitly loaded in your kernel configuration. + ''; + + mitigations = { + disable = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Whether to disable spectre and meltdown mitigations in the kernel. This is rather a sandbox + option than something you should consider on a production/mission critical system. Unless + you know what *exactly* you are doing, do not enable this. + ''; + }; + + acceptRisk = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + You are either really stupid, or very knowledable. In either case, + this must be explicitly true in order to ensure users know what they are doing + when they disable security mitigations. + ''; + }; + }; + + selinux = { + enable = mkEnableOption "system SELinux support + kernel patches"; + state = mkOption { + type = with types; enum ["enforcing" "permissive" "disabled"]; + default = "enforcing"; + description = '' + SELinux state to boot with. The default is enforcing. + ''; + }; + + type = mkOption { + type = with types; enum ["targeted" "minimum" "mls"]; + default = "targeted"; + description = '' + SELinux policy type to boot with. The default is targeted. + ''; + }; + }; + + auditd = { + enable = mkEnableOption "the audit daemon."; + autoPrune = { + enable = mkEnableOption "auto-pruning of old audit logs."; + + size = mkOption { + type = types.int; + default = 524288000; # roughly 500 megabytes + description = "The maximum size of the audit log in bytes. The default is 500MBs"; + }; + + dates = mkOption { + type = types.str; + default = "daily"; + example = "weekly"; + description = "How often cleaning is triggered. Passed to systemd.time"; + }; + }; + }; + + clamav = { + enable = mkEnableOption "ClamAV daemon."; + daemon = { + settings = mkOption { + type = with types; attrsOf (oneOf [bool int str (listOf str)]); + default = { + LogFile = "/var/log/clamd.log"; + LogTime = true; + DetectPUA = true; + VirusEvent = lib.escapeShellArgs [ + "${pkgs.libnotify}/bin/notify-send" + "--" + "ClamAV Virus Scan" + "Found virus: %v" + ]; + }; + + description = '' + ClamAV configuration. Refer to , + for details on supported values. + ''; + }; + }; + + updater = { + enable = mkEnableOption "ClamAV freshclam updater"; + + frequency = mkOption { + type = types.int; + default = 12; + description = '' + Number of database checks per day. + ''; + }; + + interval = mkOption { + type = types.str; + default = "hourly"; + description = '' + How often freshclam is invoked. See systemd.time(7) for more + information about the format. + ''; + }; + + settings = mkOption { + type = with types; attrsOf (oneOf [bool int str (listOf str)]); + default = {}; + description = '' + freshclam configuration. Refer to , + for details on supported values. + ''; + }; + }; + }; + }; +} diff --git a/nyx/modules/options/system/services/bincache.nix b/nyx/modules/options/system/services/bincache.nix new file mode 100644 index 0000000..0d21ae4 --- /dev/null +++ b/nyx/modules/options/system/services/bincache.nix @@ -0,0 +1,21 @@ +{lib, ...}: let + inherit (lib) mkModule; +in { + options.modules.system.services = { + # binary cache backends + bincache = { + harmonia = mkModule { + name = "Harmonia"; + type = "binary cache"; + host = "[::]"; + port = 5000; + }; + + atticd = mkModule { + name = "Atticd"; + type = "binary cache"; + port = 8100; + }; + }; + }; +} diff --git a/nyx/modules/options/system/services/databases.nix b/nyx/modules/options/system/services/databases.nix new file mode 100644 index 0000000..6a9deb3 --- /dev/null +++ b/nyx/modules/options/system/services/databases.nix @@ -0,0 +1,38 @@ +{lib, ...}: let + inherit (lib) mkModule; +in { + options.modules.system.services = { + # database backends + database = { + mysql = mkModule { + name = "MySQL"; + type = "database"; + port = 3306; + }; + + mongodb = mkModule { + name = "MongoDB"; + type = "database"; + port = 27017; + }; + + redis = mkModule { + name = "Redis"; + type = "database"; + port = 6379; + }; + + postgresql = mkModule { + name = "PostgreSQL"; + type = "database"; + port = 5432; + }; + + garage = mkModule { + name = "Garage"; + type = "S3 storage"; + port = 5432; + }; + }; + }; +} diff --git a/nyx/modules/options/system/services/default.nix b/nyx/modules/options/system/services/default.nix new file mode 100644 index 0000000..088bb18 --- /dev/null +++ b/nyx/modules/options/system/services/default.nix @@ -0,0 +1,79 @@ +{lib, ...}: let + inherit (lib) mkEnableOption mkModule; +in { + imports = [ + ./bincache.nix + ./databases.nix + ./monitoring.nix + ./networking.nix + ./social.nix + ]; + + options.modules.system = { + services = { + mailserver.enable = mkEnableOption "nixos-mailserver service"; + mkm.enable = mkEnableOption "mkm-ticketing service"; + + nextcloud = mkModule { + name = "Nextcloud"; + type = "cloud storage"; + }; + + nginx = mkModule { + name = "Nginx"; + type = "webserver"; + }; + + vaultwarden = mkModule { + name = "Vaultwarden"; + type = "password manager"; + port = 8222; + host = "127.0.0.1"; + }; + + forgejo = mkModule { + name = "Forgejo"; + type = "forge"; + port = 7000; + }; + + quassel = mkModule { + name = "Quassel"; + type = "IRC"; + port = 4242; + }; + + jellyfin = mkModule { + name = "Jellyfin"; + type = "media"; + port = 8096; + }; + + searxng = mkModule { + name = "Searxng"; + type = "meta search engine"; + port = 8888; + }; + + miniflux = mkModule { + name = "Miniflux"; + type = "RSS reader"; + }; + + reposilite = mkModule { + name = "Reposilite"; + port = 8084; + }; + + elasticsearch = mkModule { + name = "Elasticsearch"; + port = 9200; + }; + + kanidm = mkModule { + name = "Kanidm"; + port = 8443; + }; + }; + }; +} diff --git a/nyx/modules/options/system/services/monitoring.nix b/nyx/modules/options/system/services/monitoring.nix new file mode 100644 index 0000000..551fd86 --- /dev/null +++ b/nyx/modules/options/system/services/monitoring.nix @@ -0,0 +1,26 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkEnableOption; + + sys = config.modules.system; + cfg = sys.services; + + # mkEnableOption is the same as mkEnableOption but with the default value being equal to cfg.monitoring.enable + mkEnableOption' = desc: mkEnableOption "${desc}" // {default = cfg.monitoring.enable;}; +in { + options.modules.system.services = { + # monitoring tools + # TODO: how do I mkModule those? they feature multiple host-specific parts + # that need to be adressed + monitoring = { + enable = mkEnableOption "system monitoring stack"; + prometheus.enable = mkEnableOption' "Prometheus monitoring service"; + grafana.enable = mkEnableOption' "Grafana monitoring service"; + loki.enable = mkEnableOption' "Loki monitoring service"; + uptime-kuma.enable = mkEnableOption' "Uptime Kuma monitoring service"; + }; + }; +} diff --git a/nyx/modules/options/system/services/networking.nix b/nyx/modules/options/system/services/networking.nix new file mode 100644 index 0000000..c2ab542 --- /dev/null +++ b/nyx/modules/options/system/services/networking.nix @@ -0,0 +1,25 @@ +{lib, ...}: let + inherit (lib) mkEnableOption mkModule; + inherit (lib.types) str; +in { + options.modules.system.services = { + # networking + networking = { + wireguard.enable = mkEnableOption "Wireguard service"; + headscale = mkModule { + name = "Headscale"; + type = "networking"; + port = 8085; + /* + extraOptions = { + domain = mkOption { + type = str; + example = "headscale.example.com"; + description = "The domain name to use for headscale"; + }; + }; + */ + }; + }; + }; +} diff --git a/nyx/modules/options/system/services/social.nix b/nyx/modules/options/system/services/social.nix new file mode 100644 index 0000000..f985f57 --- /dev/null +++ b/nyx/modules/options/system/services/social.nix @@ -0,0 +1,18 @@ +{lib, ...}: let + inherit (lib) mkModule; +in { + options.modules.system.services = { + # self-hosted/decentralized social networks + social = { + mastodon = mkModule { + name = "Mastodon"; + type = "social"; + }; + matrix = mkModule { + name = "Matrix"; + type = "social"; + port = 8008; + }; + }; + }; +} diff --git a/nyx/modules/options/system/virtualization.nix b/nyx/modules/options/system/virtualization.nix new file mode 100644 index 0000000..9f4460a --- /dev/null +++ b/nyx/modules/options/system/virtualization.nix @@ -0,0 +1,13 @@ +{lib, ...}: let + inherit (lib) mkEnableOption; +in { + options.modules.system.virtualization = { + enable = mkEnableOption "virtualization"; + libvirt = {enable = mkEnableOption "libvirt";}; + docker = {enable = mkEnableOption "docker";}; + podman = {enable = mkEnableOption "podman";}; + qemu = {enable = mkEnableOption "qemu";}; + waydroid = {enable = mkEnableOption "waydroid";}; + distrobox = {enable = mkEnableOption "distrobox";}; + }; +} diff --git a/nyx/modules/options/theme/colors.nix b/nyx/modules/options/theme/colors.nix new file mode 100644 index 0000000..48a685c --- /dev/null +++ b/nyx/modules/options/theme/colors.nix @@ -0,0 +1,98 @@ +{ + config, + lib, + ... +}: let + inherit (lib.options) mkOption literalExpression; + inherit (lib.types) str nullOr enum mkOptionType attrsOf coercedTo; + inherit (lib.strings) removePrefix hasPrefix isString; + inherit (lib) serializeTheme; + + cfg = config.modules.style; + + hexColorType = mkOptionType { + name = "hex-color"; + descriptionClass = "noun"; + description = "RGB color in hex format"; + check = x: isString x && !(hasPrefix "#" x); + }; + colorType = attrsOf (coercedTo str (removePrefix "#") hexColorType); + + getPaletteFromScheme = slug: + if builtins.pathExists ./palettes/${slug}.nix + then (import ./palettes/${slug}.nix).colorscheme.palette + else throw "The following colorscheme was imported but not found: ${slug}"; +in { + options.modules.style = { + # choose a colorscheme + colorScheme = { + # "Name Of The Scheme" + name = mkOption { + type = nullOr (enum ["Catppuccin Mocha" "Tokyonight Storm" "Oxocarbon Dark"]); + description = "The colorscheme that should be used globally to theme your system."; + default = "Catppuccin Mocha"; + }; + + # "name-of-the-scheme" + slug = mkOption { + type = str; + default = serializeTheme "${toString cfg.colorScheme.name}"; # toString to avoid type errors if null, returns "" + description = '' + The serialized slug for the colorScheme you are using. + + Defaults to a lowercased version of the theme name with spaces + replaced with hyphens. + + Must only be changed if the slug is expected to be different than + the serialized theme name." + ''; + }; + + # this module option is taken from nix-colors by Misterio77 + # and is adapted for my personal use. Main difference is that + # certain additional options (e.g. author or palette) have been + # removed as they are handled by the rest of the style module. + # + colors = mkOption { + type = colorType; + default = getPaletteFromScheme cfg.colorScheme.slug; + description = '' + An attribute set containing active colors of the system. Follows base16 + scheme by default but can be expanded to base24 or anything "above" as + seen fit as the module option is actually not checked in any way + ''; + example = literalExpression '' + { + base00 = "#002635"; + base01 = "#00384d"; + base02 = "#517F8D"; + base03 = "#6C8B91"; + base04 = "#869696"; + base05 = "#a1a19a"; + base06 = "#e6e6dc"; + base07 = "#fafaf8"; + base08 = "#ff5a67"; + base09 = "#f08e48"; + base0A = "#ffcc1b"; + base0B = "#7fc06e"; + base0C = "#14747e"; + base0D = "#5dd7b9"; + base0E = "#9a70a4"; + base0F = "#c43060"; + } + ''; + }; + + variant = mkOption { + type = enum ["dark" "light"]; + default = + if builtins.substring 0 1 cfg.colorScheme.colors.base00 < "5" + then "dark" + else "light"; + description = '' + Whether the scheme is dark or light + ''; + }; + }; + }; +} diff --git a/nyx/modules/options/theme/default.nix b/nyx/modules/options/theme/default.nix new file mode 100644 index 0000000..31574b7 --- /dev/null +++ b/nyx/modules/options/theme/default.nix @@ -0,0 +1,44 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib) mkOption mkEnableOption types; +in { + imports = [ + ./gtk.nix + ./qt.nix + ./colors.nix + ]; + + options.modules.style = { + forceGtk = mkEnableOption "Force GTK applications to use the GTK theme"; + useKvantum = mkEnableOption "Use Kvantum to theme QT applications"; + + pointerCursor = { + package = mkOption { + type = types.package; + description = "The package providing the cursors"; + default = pkgs.catppuccin-cursors.mochaDark; + }; + + name = mkOption { + type = types.str; + description = "The name of the cursor inside the package"; + default = "Catppuccin-Mocha-Dark-Cursors"; + }; + + size = mkOption { + type = types.int; + description = "The size of the cursor"; + default = 24; + }; + }; + + wallpapers = mkOption { + type = with types; either str (listOf str); + description = "Wallpaper or wallpapers to use"; + default = []; + }; + }; +} diff --git a/nyx/modules/options/theme/gtk.nix b/nyx/modules/options/theme/gtk.nix new file mode 100644 index 0000000..15b0d92 --- /dev/null +++ b/nyx/modules/options/theme/gtk.nix @@ -0,0 +1,70 @@ +{ + lib, + pkgs, + ... +}: let + inherit (lib) mkOption mkEnableOption types; +in { + options = { + modules = { + style = { + # gtk specific options + gtk = { + enable = mkEnableOption "GTK theming optionss"; + usePortal = mkEnableOption "native desktop portal use for filepickers"; + + theme = { + name = mkOption { + type = types.str; + default = "Catppuccin-Mocha-Standard-Blue-dark"; + description = "The name for the GTK theme package"; + }; + + package = mkOption { + type = types.package; + description = "The theme package to be used for GTK programs"; + default = pkgs.catppuccin-gtk.override { + size = "standard"; + accents = ["blue"]; + variant = "mocha"; + tweaks = ["normal"]; + }; + }; + }; + + iconTheme = { + name = mkOption { + type = types.str; + description = "The name for the icon theme that will be used for GTK programs"; + + default = "Papirus-Dark"; + }; + + package = mkOption { + type = types.package; + description = "The GTK icon theme to be used"; + default = pkgs.catppuccin-papirus-folders.override { + accent = "blue"; + flavor = "mocha"; + }; + }; + }; + + font = { + name = mkOption { + type = types.str; + description = "The name of the font that will be used for GTK applications"; + default = "Lexend"; + }; + + size = mkOption { + type = types.int; + description = "The size of the font"; + default = 14; + }; + }; + }; + }; + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/angel-light.nix b/nyx/modules/options/theme/palettes/angel-light.nix new file mode 100644 index 0000000..8766497 --- /dev/null +++ b/nyx/modules/options/theme/palettes/angel-light.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "angel-light"; + name = "Angel"; + variant = "light"; + palette = { + base00 = "#140e10"; + base01 = "#8E7C86"; + base02 = "#C47E81"; + base03 = "#988791"; + base04 = "#AB9196"; + base05 = "#B39BA8"; + base06 = "#CEA6A9"; + base07 = "#e2d4d8"; + base08 = "#9e9497"; + base09 = "#8E7C86"; + base0A = "#C47E81"; + base0B = "#988791"; + base0C = "#AB9196"; + base0D = "#B39BA8"; + base0E = "#CEA6A9"; + base0F = "#e2d4d8"; + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/black-metal.nix b/nyx/modules/options/theme/palettes/black-metal.nix new file mode 100644 index 0000000..a55ed55 --- /dev/null +++ b/nyx/modules/options/theme/palettes/black-metal.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "black-metal"; + name = "Black Metal"; + variant = "dark"; + palette = { + base00 = "#000000"; + base01 = "#121212"; + base02 = "#222222"; + base03 = "#333333"; + base04 = "#999999"; + base05 = "#c1c1c1"; + base06 = "#999999"; + base07 = "#c1c1c1"; + base08 = "#5f8787"; + base09 = "#aaaaaa"; + base0A = "#a06666"; + base0B = "#dd9999"; + base0C = "#aaaaaa"; + base0D = "#888888"; + base0E = "#999999"; + base0F = "#444444"; + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/carbon-dark.nix b/nyx/modules/options/theme/palettes/carbon-dark.nix new file mode 100644 index 0000000..9847a25 --- /dev/null +++ b/nyx/modules/options/theme/palettes/carbon-dark.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "carbon-dark"; + name = "Carbon Dark"; + variant = "dark"; + valette = { + base00 = "#161616"; + base01 = "#262626"; + base02 = "#393939"; + base03 = "#525252"; + base04 = "#6F6F6F"; + base05 = "#FAFAFA"; + base06 = "#FAFAFA"; + base07 = "#FFFFFF"; + base08 = "#be95ff"; + base09 = "#3ddbd9"; + base0A = "#0043ce"; + base0B = "#33b1ff"; + base0C = "#ff7eb6"; + base0D = "#42be65"; + base0E = "#be95ff"; + base0F = "#3ddbd9"; + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/catppuccin-frappe.nix b/nyx/modules/options/theme/palettes/catppuccin-frappe.nix new file mode 100644 index 0000000..f66b683 --- /dev/null +++ b/nyx/modules/options/theme/palettes/catppuccin-frappe.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "catppuccin-frappe"; + name = "Catppuccin Frappe"; + variant = "dark"; + palette = { + base00 = "#303446"; # Base + base01 = "#292c3c"; # Mantle + base02 = "#414559"; # Surface0 + base03 = "#51576d"; # Surface1 + base04 = "#626880"; # Surface2 + base05 = "#c6d0f5"; # Text + base06 = "#f2d5cf"; # Rosewater + base07 = "#babbf1"; # Lavender + base08 = "#e78284"; # Red + base09 = "#ef9f76"; # Peach + base0A = "#e5c890"; # Yellow + base0B = "#a6d189"; # Green + base0C = "#81c8be"; # Teal + base0D = "#8caaee"; # Blue + base0E = "#ca9ee6"; # Mauve + base0F = "#eebebe"; # Flamingo + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/catppuccin-macchiato.nix b/nyx/modules/options/theme/palettes/catppuccin-macchiato.nix new file mode 100644 index 0000000..8eac087 --- /dev/null +++ b/nyx/modules/options/theme/palettes/catppuccin-macchiato.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "catppuccin-mocha"; + name = "Catppuccin Mocha"; + variant = "dark"; + palette = { + base00 = "#24273a"; # Base + base01 = "#1e2030"; # Mantle + base02 = "#363a4f"; # Surface0 + base03 = "#494d64"; # Surface1 + base04 = "#5b6078"; # Surface2 + base05 = "#cad3f5"; # Text + base06 = "#f4dbd6"; # Rosewater + base07 = "#b7bdf8"; # Lavender + base08 = "#ed8796"; # Red + base09 = "#f5a97f"; # Peach + base0A = "#eed49f"; # Yellow + base0B = "#a6da95"; # Green + base0C = "#8bd5ca"; # Teal + base0D = "#8aadf4"; # Blue + base0E = "#c5a0f6"; # Mauve + base0F = "#f0c6c6"; # Flamingo + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/catppuccin-mocha.nix b/nyx/modules/options/theme/palettes/catppuccin-mocha.nix new file mode 100644 index 0000000..814e1b1 --- /dev/null +++ b/nyx/modules/options/theme/palettes/catppuccin-mocha.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "catppuccin-mocha"; + name = "Catppuccin Mocha"; + variant = "dark"; + palette = { + base00 = "#1e1e2e"; # Base + base01 = "#181825"; # Mantle + base02 = "#313244"; # Surface0 + base03 = "#45475a"; # Surface1 + base04 = "#585b70"; # Surface2 + base05 = "#cdd6f4"; # text + base06 = "#f5e0dc"; # rosewater + base07 = "#b4befe"; # lavender + base08 = "#f38ba8"; # red + base09 = "#fab387"; # peach + base0A = "#a6e3a1"; # yellow + base0B = "#94e2d5"; # green + base0C = "#94e2d5"; # teal + base0D = "#89b4fa"; # blue + base0E = "#cba6f7"; # mauve + base0F = "#f2cdcd"; # flamingo + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/decay-dark.nix b/nyx/modules/options/theme/palettes/decay-dark.nix new file mode 100644 index 0000000..61cd049 --- /dev/null +++ b/nyx/modules/options/theme/palettes/decay-dark.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "decay-dark"; + name = "Decay Dark"; + variant = "dark"; + palette = { + base00 = "#10101a"; # Base + base01 = "#12121c"; # Mantle + base02 = "#171721"; # Surface0 + base03 = "#1c1c26"; # Surface1 + base04 = "#2b2b35"; # Surface2 + base05 = "#c3cddb"; # text + base06 = "#c3cddb"; # " + base07 = "#c8d2e0"; # white + base08 = "#c8d2e0"; # " + base09 = "#fa9a9a"; # red + base0A = "#f8e7b7"; # yellow + base0B = "#b0e2ae"; # green + base0C = "#93cff7"; # teal + base0D = "#8cbef7"; # blue + base0E = "#bfa6fa"; # magenta + base0F = "#fa9a9a"; # red again + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/default-dark.nix b/nyx/modules/options/theme/palettes/default-dark.nix new file mode 100644 index 0000000..993eac3 --- /dev/null +++ b/nyx/modules/options/theme/palettes/default-dark.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "default-dark"; + name = "Default Dark"; + variant = "dark"; + palette = { + base00 = "#181818"; + base01 = "#282828"; + base02 = "#383838"; + base03 = "#585858"; + base04 = "#b8b8b8"; + base05 = "#d8d8d8"; + base06 = "#e8e8e8"; + base07 = "#f8f8f8"; + base08 = "#ab4642"; + base09 = "#dc9656"; + base0A = "#f7ca88"; + base0B = "#a1b56c"; + base0C = "#86c1b9"; + base0D = "#7cafc2"; + base0E = "#ba8baf"; + base0F = "#a16946"; + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/monochrome.nix b/nyx/modules/options/theme/palettes/monochrome.nix new file mode 100644 index 0000000..6225d5b --- /dev/null +++ b/nyx/modules/options/theme/palettes/monochrome.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "monochrome"; + name = "monochrome"; + variant = "dark"; + palette = { + base00 = "#121517"; # Base + base01 = "#2e3338"; # Mantle + base02 = "#4a5159"; # Surface0 + base03 = "#6c757d"; # Surface1 + base04 = "#6c757d"; # Surface2 + base05 = "#e9ecef"; # text + base06 = "#e9ecef"; # " + base07 = "#f8f9fa"; # white + base08 = "#f8f9fa"; # white + base09 = "#f8f9fa"; # white + base0A = "#f8f9fa"; # white + base0B = "#f8f9fa"; # white + base0C = "#f8f9fa"; # white + base0D = "#f8f9fa"; # white + base0E = "#f8f9fa"; # white + base0F = "#f8f9fa"; # white + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/noelle.nix b/nyx/modules/options/theme/palettes/noelle.nix new file mode 100644 index 0000000..ebbca26 --- /dev/null +++ b/nyx/modules/options/theme/palettes/noelle.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "noelle"; + name = "noelle"; + variant = "dark"; + palette = { + base00 = "#111111"; # Base + base01 = "#282a2e"; # Mantle + base02 = "#373b41"; # Surface0 + base03 = "#373b41"; # Surface1 + base04 = "#626880"; # Surface2 + base05 = "#eae7ee"; # Text + base06 = "#c5c8c6"; # Rosewater + base07 = "#c6c8c6"; # Lavender + base08 = "#922b3c"; # Red + base09 = "#a84757"; # Peach + base0A = "#bd8964"; # Yellow + base0B = "#a3ad64"; # Green + base0C = "#922b3c"; # Teal + base0D = "#a84757"; # Blue + base0E = "#9876a4"; # Magenta + base0F = "#ae93b7"; # Flamingo + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/oxocarbon-dark.nix b/nyx/modules/options/theme/palettes/oxocarbon-dark.nix new file mode 100644 index 0000000..3184106 --- /dev/null +++ b/nyx/modules/options/theme/palettes/oxocarbon-dark.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "oxocarbon-dark"; + name = "Oxocarbon Dark"; + variant = "dark"; + palette = { + base00 = "#161616"; + base01 = "#262626"; + base02 = "#393939"; + base03 = "#525252"; + base04 = "#dde1e6"; + base05 = "#f2f4f8"; + base06 = "#ffffff"; + base07 = "#08bdba"; + base08 = "#3ddbd9"; + base09 = "#78a9ff"; + base0A = "#ee5396"; + base0B = "#33b1ff"; + base0C = "#ff7eb6"; + base0D = "#42be65"; + base0E = "#be95ff"; + base0F = "#82cfff"; + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/tokyo-night.nix b/nyx/modules/options/theme/palettes/tokyo-night.nix new file mode 100644 index 0000000..b622cdd --- /dev/null +++ b/nyx/modules/options/theme/palettes/tokyo-night.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "tokyo-night"; + name = "Tokyo Night"; + variant = "dark"; # bet + palette = { + base00 = "#24283b"; + base01 = "#1f2335"; + base02 = "#292e42"; + base03 = "#565f89"; + base04 = "#a9b1d6"; + base05 = "#c0caf5"; + base06 = "#c0caf5"; + base07 = "#c0caf5"; + base08 = "#c0caf5"; + base09 = "#f7768e"; + base0A = "#e0af68"; + base0B = "#9ece6a"; + base0C = "#1abc9c"; + base0D = "#41a6b5"; + base0E = "#bb9af7"; + base0F = "#ff007c"; + }; + }; +} diff --git a/nyx/modules/options/theme/palettes/varda-theme.nix b/nyx/modules/options/theme/palettes/varda-theme.nix new file mode 100644 index 0000000..40f9858 --- /dev/null +++ b/nyx/modules/options/theme/palettes/varda-theme.nix @@ -0,0 +1,25 @@ +{ + colorscheme = { + slug = "varda-theme"; + name = "Varda Theme"; + variant = "dark"; + palette = { + base00 = "#0C0E11"; # Base + base01 = "#141619"; # Mantle + base02 = "#2E3436"; # Surface0 + base03 = "#3b4444"; # Surface1 + base04 = "#3b4444"; # Surface2 + base05 = "#D0EBEE"; # text + base06 = "#D0EBEE"; # " + base07 = "#E5FFFF"; # white + base08 = "#E5FFFF"; # " + base09 = "#733447"; # red + base0A = "#C78C56"; # yellow + base0B = "#257B76"; # green + base0C = "#52677C"; # teal + base0D = "#52677C"; # blue + base0E = "#604575"; # magenta + base0F = "#733447"; # red again + }; + }; +} diff --git a/nyx/modules/options/theme/qt.nix b/nyx/modules/options/theme/qt.nix new file mode 100644 index 0000000..b63da3e --- /dev/null +++ b/nyx/modules/options/theme/qt.nix @@ -0,0 +1,43 @@ +{ + lib, + pkgs, + config, + ... +}: let + inherit (lib) mkOption types mkEnableOption; + cfg = config.modules.style; +in { + options = { + modules = { + style = { + qt = { + enable = mkEnableOption "QT Style Module"; + + theme = { + package = mkOption { + type = types.package; + default = pkgs.catppuccin-kde.override { + flavour = ["mocha"]; + accents = ["blue"]; + winDecStyles = ["modern"]; + }; + description = "The theme package to be used for QT programs"; + }; + + name = mkOption { + type = types.str; + default = "Catppuccin-Mocha-Dark"; + description = "The name for the QT theme package"; + }; + }; + + kdeglobals.source = mkOption { + type = types.path; + default = "${cfg.qt.theme.package}/share/color-schemes/CatppuccinMochaBlue.colors"; + description = "The source file for the kdeglobals file. Usually provided by the qt theme package"; + }; + }; + }; + }; + }; +} diff --git a/nyx/modules/options/usrEnv/brightness.nix b/nyx/modules/options/usrEnv/brightness.nix new file mode 100644 index 0000000..42ccc49 --- /dev/null +++ b/nyx/modules/options/usrEnv/brightness.nix @@ -0,0 +1,58 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.options) mkOption; + inherit (lib.types) ints bool enum package; + + cfg = config.modules.usrEnv.brightness; +in { + options.modules.usrEnv.brightness = { + enable = mkOption { + type = bool; + default = false; + description = '' + Enable brightness management with systemd. + ''; + }; + + package = mkOption { + type = package; + default = pkgs.writeShellApplication { + name = "set-system-brightness"; + runtimeInputs = with pkgs; [brightnessctl]; + text = "brightnessctl set ${cfg.value}"; + }; + }; + + value = mkOption { + type = ints.between 0 100; + default = 85; # try to save some battery on laptops + description = '' + The screen brightness that will be set once the graphical target is reached. + ''; + }; + + service = { + type = mkOption { + type = enum ["oneshot" "simple"]; + default = "oneshot"; + description = '' + The type of the service to be used for setting brightness on graphical session start. + ''; + }; + + target = mkOption { + type = enum ["graphical-session.target" "multi-user.target"]; + default = "graphical-session.target"; + description = '' + The target that the systemd-brightnessd service will be bound to. + + This effectively sets the `after` attribute in the serviceConfig + ''; + }; + }; + }; +} diff --git a/nyx/modules/options/usrEnv/default.nix b/nyx/modules/options/usrEnv/default.nix new file mode 100644 index 0000000..8a87406 --- /dev/null +++ b/nyx/modules/options/usrEnv/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./programs + ./services + + ./brightness.nix + ./desktop.nix + ]; +} diff --git a/nyx/modules/options/usrEnv/desktop.nix b/nyx/modules/options/usrEnv/desktop.nix new file mode 100644 index 0000000..339a486 --- /dev/null +++ b/nyx/modules/options/usrEnv/desktop.nix @@ -0,0 +1,85 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkOption types; + + cfg = config.modules.usrEnv; + sys = config.modules.system; +in { + options.modules.usrEnv = { + desktop = mkOption { + type = types.enum ["none" "Hyprland" "sway" "awesomewm" "i3"]; + default = "none"; + description = '' + The desktop environment to be used. + ''; + }; + + desktops = { + hyprland.enable = mkOption { + type = types.bool; + default = cfg.desktop == "Hyprland"; + description = '' + Whether to enable Hyprland wayland compositor. + + Will be enabled automatically when `modules.usrEnv.desktop` is set to "Hyprland". + + ''; + }; + + sway.enable = mkOption { + type = types.bool; + default = cfg.desktop == "sway"; + description = '' + Whether to enable Sway wayland compositor. + + Will be enabled automatically when `modules.usrEnv.desktop` is set to "sway". + ''; + }; + + awesomwm.enable = mkOption { + type = types.bool; + default = cfg.desktop == "awesomewm"; + description = '' + Whether to enable Awesome window manager + + Will be enabled automatically when `modules.usrEnv.desktop` is set to "awesomewm". + ''; + }; + + i3.enable = mkOption { + type = types.bool; + default = cfg.desktop == "i3"; + description = '' + Whether to enable i3 window manager + + Will be enabled automatically when `modules.usrEnv.desktop` is set to "i3". + ''; + }; + }; + + useHomeManager = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable the usage of home-manager for user home management. Maps the list + of users to their home directories inside the `homes/` directory in the repository + root. + + Username via `modules.system.mainUser` must be set if this option is enabled. + ''; + }; + }; + + config = { + assertions = [ + { + assertion = cfg.useHomeManager -> sys.mainUser != null; + message = "modules.system.mainUser must be set while modules.usrEnv.useHomeManager is enabled"; + } + ]; + }; +} diff --git a/nyx/modules/options/usrEnv/programs/default.nix b/nyx/modules/options/usrEnv/programs/default.nix new file mode 100644 index 0000000..4fa5790 --- /dev/null +++ b/nyx/modules/options/usrEnv/programs/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./gaming.nix + ./launchers.nix + ./lockers.nix + ./media.nix + ]; +} diff --git a/nyx/modules/options/usrEnv/programs/gaming.nix b/nyx/modules/options/usrEnv/programs/gaming.nix new file mode 100644 index 0000000..9a04b86 --- /dev/null +++ b/nyx/modules/options/usrEnv/programs/gaming.nix @@ -0,0 +1,19 @@ +{ + config, + lib, + ... +}: let + inherit (lib.options) mkEnableOption; + inherit (config) modules; + + sys = modules.system; + prg = sys.programs; +in { + options.modules.usrEnv.programs.gaming = { + enable = mkEnableOption "userspace gaming programs" // {default = prg.gaming.enable;}; + emulation.enable = mkEnableOption "programs required to emulate other platforms" // {default = prg.gaming.enable;}; + minecraft.enable = mkEnableOption "Minecraft launcher & JDKs" // {default = prg.gaming.enable;}; + chess.enable = mkEnableOption "Chess programs and engines" // {default = prg.gaming.enable;}; + mangohud.enable = mkEnableOption "MangoHud overlay" // {default = prg.gaming.enable;}; + }; +} diff --git a/nyx/modules/options/usrEnv/programs/launchers.nix b/nyx/modules/options/usrEnv/programs/launchers.nix new file mode 100644 index 0000000..bb9499c --- /dev/null +++ b/nyx/modules/options/usrEnv/programs/launchers.nix @@ -0,0 +1,9 @@ +{lib, ...}: let + inherit (lib.options) mkEnableOption; +in { + options.modules.usrEnv.programs.launchers = { + anyrun.enable = mkEnableOption "anyrun application launcher"; + rofi.enable = mkEnableOption "rofi application launcher"; + tofi.enable = mkEnableOption "tofi application launcher"; + }; +} diff --git a/nyx/modules/options/usrEnv/programs/lockers.nix b/nyx/modules/options/usrEnv/programs/lockers.nix new file mode 100644 index 0000000..90e1760 --- /dev/null +++ b/nyx/modules/options/usrEnv/programs/lockers.nix @@ -0,0 +1,27 @@ +{ + config, + pkgs, + lib, + ... +}: let + inherit (lib.types) package; + inherit (lib.options) mkEnableOption mkOption; + + cfg = config.modules.usrEnv.programs.screenlock; + pkg = + if cfg.gtklock.enable + then pkgs.gtklock + else pkgs.swaylock-effects; +in { + options.modules.usrEnv.programs.screenlock = { + gtklock.enable = mkEnableOption "gtklock screenlocker"; + swaylock.enable = mkEnableOption "swaylock screenlocker"; + + package = mkOption { + type = package; + default = pkg; + readOnly = true; + description = "The screenlocker package"; + }; + }; +} diff --git a/nyx/modules/options/usrEnv/programs/media.nix b/nyx/modules/options/usrEnv/programs/media.nix new file mode 100644 index 0000000..820c097 --- /dev/null +++ b/nyx/modules/options/usrEnv/programs/media.nix @@ -0,0 +1,63 @@ +{ + inputs', + config, + pkgs, + lib, + ... +}: let + inherit (lib) mkEnableOption mkOption types literalExpression; +in { + options.modules.usrEnv.programs.media = { + addDefaultPackages = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable the default list of media-related packages ranging from audio taggers + to video editors. + ''; + }; + + extraPackages = mkOption { + type = with types; listOf package; + default = []; + description = '' + Additional packages that will be appended to media related packages. + ''; + }; + + ncmpcpp.enable = mkEnableOption "ncmpcpp TUI music player"; + + beets.enable = + mkEnableOption '' + beets media library system. + + + Will be enabled automatically if {option}`config.modules.usrEnv.services.mpd.enabled` + is set to true + '' + // {default = config.modules.usrEnv.services.media.mpd.enable;}; + + mpv = { + enable = mkEnableOption "mpv media player"; + scripts = mkOption { + type = with types; listOf package; + description = "A list of MPV scripts that will be enabled"; + example = literalExpression ''[ pkgs.mpvScripts.cutter ]''; + default = with pkgs.mpvScripts; [ + # from nixpkgs + cutter # cut and automatically concat videos + mpris # MPRIS plugin + thumbnail # OSC seekbar thumbnails + thumbfast # on-the-fly thumbnailer + sponsorblock # skip sponsored segments + uosc # proximity UI + quality-menu # ytdl-format quality menu + seekTo # seek to spefici pos. + + # from nyxpkgs + inputs'.nyxpkgs.packages.mpv-history # save a history of played files with timestamps + ]; + }; + }; + }; +} diff --git a/nyx/modules/options/usrEnv/services/default.nix b/nyx/modules/options/usrEnv/services/default.nix new file mode 100644 index 0000000..c04e592 --- /dev/null +++ b/nyx/modules/options/usrEnv/services/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./media.nix + ]; +} diff --git a/nyx/modules/options/usrEnv/services/media.nix b/nyx/modules/options/usrEnv/services/media.nix new file mode 100644 index 0000000..3480e00 --- /dev/null +++ b/nyx/modules/options/usrEnv/services/media.nix @@ -0,0 +1,7 @@ +{lib, ...}: let + inherit (lib.options) mkEnableOption; +in { + options.modules.usrEnv.services.media = { + mpd.enable = mkEnableOption "mpd service"; + }; +} diff --git a/nyx/secrets/client-email.age b/nyx/secrets/client-email.age new file mode 100644 index 0000000..c988eba Binary files /dev/null and b/nyx/secrets/client-email.age differ diff --git a/nyx/secrets/client-spotify.age b/nyx/secrets/client-spotify.age new file mode 100644 index 0000000..4c4e1f3 Binary files /dev/null and b/nyx/secrets/client-spotify.age differ diff --git a/nyx/secrets/client-tailscale.age b/nyx/secrets/client-tailscale.age new file mode 100644 index 0000000..e128d88 --- /dev/null +++ b/nyx/secrets/client-tailscale.age @@ -0,0 +1,27 @@ +age-encryption.org/v1 +-> ssh-ed25519 2+cNmQ 0bRU6X3NZafby7hv5XNFayflbKz4XkvzdLPIKPb/1To +n7IZYrR/rJGI7nXAUodAJbYCPtR4U+s0j6vIayitUVU +-> ssh-ed25519 likgDA eQ6aw72/BWR7eJ0odg8OgqmA9PAsXeH/Xx4V4Bqz1GI +f0i79VGJf3BCWlIbqITPtZLuhAZt8UonqDx1uY2mJSE +-> ssh-ed25519 OuDDzg ZLIq2ydi1xqPkh6BxAp6wS+ezS1JgFE1NbtR+pegM2w +ki1W9CtXr8W874ezkR5/IONBTAzhaJ6cb/o45g1pnxc +-> ssh-ed25519 Y9/f4A G97mAgXwp5S7+evjkjoh0WSNJ5E/sgBh/KTZ6Tdu7xA +XiFazgvtOMGYsYMGZJHilZGRyyyycVJgfrwHfuPbJWw +-> ssh-ed25519 OuDDzg 0jfXW6dFWZPqTm+xUj8d4z9cVsj4dRwiE0Ym5lwyEV4 +jXZ/8KPlO3tjGjGCuw2yZ7Ka9IjNV0M9TJUzsekBdB8 +-> ssh-rsa VTMo4w +U+SyaknOgNUveXkRUpXSCQ+E0eRBTTqNb+FL9ufkubPQVoNICAz/EGqERHGj8cmT +FWODefIxLhWVAQ4dDIV29rXrBawgbzU43OVda42Y2bHE0jH/fQvH7mLTZALbESqX +G8YsDhqP+eJTiyg/J+nouXJSO39+Yuu9wJuELeHnxzxFe2vwCD9ZqAazS41ULteL +Btzbz3KlpcKOa3FlS6ZyHOn/3aZvrfpABvgRM7UgEOYoTDnIcnI/bnajTQaZma5L +K50Ze6FK+YfZuSA6sF7UBwqYE1Gb7eMzkOG78tx86Siy3N0gwUG5e1a59bSi7pw9 +EXIAhr+k3Zr/LAF+1yq/RScFurKhmli6OykZr7O+uBQt4GeMeKyEC4GJo1FjMdSE +yKT0txsWD+aMlEM9VA0OrriwYQb9Lxl2jqGIUbjqLGUSiK5MpDN4iKE6zPkUemmL +/5fd2tuj555l8DuHUeoSuGVlhEVknXPRPnz9K9jlgq1aObd07eEBRYMp8nP2tn6M +FcOXFQWao7aFCctSMNOyZq8QYe3yIoCoJ1+eaTemp5Nlf28Hn89yZCRwXRA0hmmS +e9lOeogvFLFBV2ixnMPJEo3UwD/0POPGJgOh7/gTluyUJIqF1Jl6E6Rrqfb6ILMm +ZJQj1ZUuKVUKYziAS9IgHLz6rX25M18DOa+bBgVgcGY +-> ssh-ed25519 uK3CeQ 2cUQ9TmGJNk3ptxW6F0jiCC44nLRCy31/3UNvIVnPT4 ++y4MPRD4f46jGg0uWu/cqBC0hXtoV+O1odmyikMcOJI +--- 7fpFnJFq9PqBUAD3ve3tm94MFr38KbhL/jOj6DEGb8k +QhNŊ9DҕX\gn5(vM oMN,D;`sLHFs˧L$<&m& \ No newline at end of file diff --git a/nyx/secrets/client-wg.age b/nyx/secrets/client-wg.age new file mode 100644 index 0000000..34ca13d --- /dev/null +++ b/nyx/secrets/client-wg.age @@ -0,0 +1,27 @@ +age-encryption.org/v1 +-> ssh-ed25519 2+cNmQ cxiOqojtSFhOWOe3VJwfQAQxRnNqykHVYkp82SfXh3o +eyXdYEwULk13Gd+agSxg/ijnkijDvab0RkXMn4PuiMA +-> ssh-ed25519 likgDA Q2+vCFYCPl86MCVY4v1t1om56QRw4B+W23lUg5sjUUg +bSoA1VWB2haP6XEQEQyUxsjkpz3bve+alWMMotRq68o +-> ssh-ed25519 OuDDzg 2zvWhfSlWZ3NCnwK3Gmg+F9o/cq1/98QKRGwIyFwdWQ +s/POdThENGPLnf5xGNLph7LnzzOHbYFPMG+agImdkE0 +-> ssh-ed25519 Y9/f4A ZLAVOECskrNiKgwk8r3puzJ0mD/qEOx0DhwyEV3cnAo +DGEDvJhM5HgcX/pIBkzE7jYPix7EseoaCZbHWwr7FHc +-> ssh-ed25519 OuDDzg Dq8EZhraoWz4Uu1WFGZW21YdrkLaD7LfhUrhFpxk5Ck +12yvvUQvumTwwLlRCpIKFDq0fK0LyRBw5VgARzua1Xk +-> ssh-rsa VTMo4w +HJv9sBAOt+LFK2xxOVe8KuoX/Rr1YcPLFTIotW/cFGLUZtIQ42JcZiRJesFx5/rE +09VTmaB6jeJmbPzXsD21tZSNDD1nszzcZgHkNbm+r8IiV7OXqjBCxQrwi1TCBFCJ +/IvtdmfiUXaTESMWcR7wrVrzUWb+6LaCk8jTEcoDFgNzi4pwySUKc9ne4BRbnVuO +jUq+sblMqynpsVzRWYA4FMgXnXLeRdttccliJ7FS/Q9y0F3WgYs0TbhaMC4th5Ed +Q26jAfxHeeepQ5+F9ciCRqTRRBhqP561+3JEB7VwSgBU5ySfEykNwR4RMzD9kL/p +0PiS5icopR7yHrKqVROXttgEd1wKox4JwUfJ6fJCnc7aA0M35OA6fb1vF3dFkUmv +Ud21eWEEQACY44RpOjaZ5dBdoCBavWSsTkUjsKwGAyLfxNidHsEH6avreY0uBeJY +lWCwSTvOHWtlf3ATX43FOOgAnMFJ5kzUDkHasZcfNFHQ2Bq3OitttdHTn9Xd0fQp +ujyQ2E8qbwOz1FsMrrUp+g6FwV+nbo77PGPJ+px0ZU2e9gOuq9mmH14iAzreUY0/ +vV0VO7gq9rLOz7GgBysMncQDznM/lVNjXkRT4E5Zb2LCGO1f/7rfff/rB+7yoVhm +ekmfsVWqDRJ8jiIZhMN4BB7F3CJ7GhGNLiApz67il5c +-> ssh-ed25519 uK3CeQ iYLw8ZwuYr6+cfSdgsKp5s2tjO+4203Yei7ewG5nvgc +WukQVllP7bG2JwViQd6jQby4zG9SOmzlp+K+d3kJm6c +--- 3biyp/zqE1P1S200HByrlL8Ezw/K7HuNd2cxVyU379Q +ZrVʯC<6Y6am1Y"CA{t1^=`n)J1voH^9K.)RZ \ No newline at end of file diff --git a/nyx/secrets/common-nix-builder.age b/nyx/secrets/common-nix-builder.age new file mode 100644 index 0000000..7092e16 Binary files /dev/null and b/nyx/secrets/common-nix-builder.age differ diff --git a/nyx/secrets/db-garage.age b/nyx/secrets/db-garage.age new file mode 100644 index 0000000..115dc7d --- /dev/null +++ b/nyx/secrets/db-garage.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A kNr2RW+psAhA08EJW80DqhlMw+io280smESE4Wh4bB0 ++M4Zqzs1o45N42hOSJMekQXck9BMtpuQnXjWDn4Uf70 +-> ssh-ed25519 OuDDzg rvjvbmp81dSfBkENCq7ZMUsbc5dZyLyfgMXve6593XA +6BiaGPdIH8uG0sAuBDvsX4lyo3YsV8cChG0cR1p4wnI +-> ssh-rsa VTMo4w +NSj7BxX7maR7t9tGEZL/CTmVlysNxWM/G7AfWP6aARh8F+418VYG+sRKbBzP0Fo7 +aj2VTaeaHfCBkglPhIIfSbbzaUxp/oCW8WTsI0+OtELzAlBW7F/OxRSvlZqvfReQ +yaKFDk52wCHW21M1usK1mVa7nVo4V97Rf1mYbAvqzsegUtzX/QulejInAxaAClEw +FATLLJMksHUluIeu+rfdP2PBVaHCQ8Io05IQLY8/giJEMIkJfBO2rrK8DvjO0vq5 +AgG/9r5BeNM93dzLhXx2eLCLxu4E2tYzRJnzubVfc7wfZo6cOHFvj6H2yv1gQb3K +zMRBOPNBw79WPcWsbutB3fXrQaiVu07JbuQqvmzh7XP7fMmFkR5Qi2+6eV8rcZGf +tX1PSbtTVI8lGl//NrXj7YsgDRt6Pa3Nef5tkdKogn/EcfFYVsJd9Ts0ZqjQxqLP +caIAbcYr3u8AcHoM5rf/4Fq/llQzD9SmDU119O1no5EmMz/TYKyyUlNNq/ezZ7kT +Dkp6HXIj268lhOvY05f/VGtw41ru2hkuHswjRPSeMBi/myMmXzXWvzqIm863BVuv +V//xxy7GdLgAwu4ynzOQEhLpBKbjbwuYZKlRlsyeY//8sKL3hekoq6rldopP3dxQ +YEtINR8qxsy3Zpfo4Y4rat3CEwnPhWZjU5WFdaglBxU +-> ssh-ed25519 uK3CeQ 8iw0H2ORTVqe2t/5AWmbPG3NYhW/UjxPXgsrBid9fBs +ydL9B747tXX7d6S1OqO/vZtXVT+B2+TlNxrDyvdDcUE +--- 6hrofeCzJZgmva820/WKuSgQOBFibJXU7lazzkHg7E0 +{1Pw_t}\ޒ-cҗOVxZjM V]Sۘ&g+!@M9n)qe6c"ƣ u \ No newline at end of file diff --git a/nyx/secrets/db-mongodb.age b/nyx/secrets/db-mongodb.age new file mode 100644 index 0000000..b28dce9 --- /dev/null +++ b/nyx/secrets/db-mongodb.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A leLhoG6vgItPkcr33RFzCC17EX/dUeKiwOed+jqmOX8 +N7mdIQl5t1teN1Sss59s4P4fWdV5FWKkO39coOh5WiQ +-> ssh-ed25519 OuDDzg fXD9MCThBUNqa000lJOBtuNNHJwGpE2gx6YvOzM+gyg +Cht4AKcaU8np1n/v98evQduaZVgVjfbCK6bLnw1PWRA +-> ssh-rsa VTMo4w +DW16rKnhRfz/kkKK4sGVKs5o+f9hepUYwoTri21m2rjj2B1/4NidVARze2n9zuGd +GmUGfDLFa7PZLnuylrlbBhUfxdLMhu23DuXP88Mbc8LFC12CzHcRfTE2BBW86blM +VTVPEPgz2ZCZjKs/BNINmgsxVqHz8PDl0nU2U1Eq9STXHxOHy0rHKClq8cQSsB90 +igr2oU1uaBMA8rVzNm6zCDpWqOhHPQ6JRMC+UrlMIBQ8m+FKCieePe1G/e4rr5W4 +bCIAbIzrOix9wOwzyLjHaJwFsmrkifNa0JMjgZSS/lSUlmoKdWqXHFawYEVFYjSJ +0gStWok3sUjYwKhShusXVjwCsbLSABcfIjGR+CDFom8wbJFwDb1aPDCHyvugDgf6 +WR/vjfw0IhIQ1yuIQDs189rlnTIN7P3FOtXW/ZdJwvsHBKFQC6vXbrMeBI2dSASq +A+0JJXMxkfA/gZMpVWkn0Ij6F+MdisEmnDECeZRIt1dhQwj2DC2f/BipYKxLaGh4 +8Q168Nx4VVrizqHUPHYZ2A/Rs19dYF0bfayXA+XihN4P+kSrLJ3Kvahea3BnmTJs +40TsRuR9L/bvko9F4ES+hWe3FuTlKH0WU5ut/ehs2hp5eAkPiUwvrbDg6VNTq6e4 +azKUlxAdox7p4h6czc0/vcbAyOTZOi7d/NHKDsYODEE +-> ssh-ed25519 uK3CeQ YCuD2qj/Xu9XBrGSg1pUSArQKKuTLr5KYmXPOV6BDTU +75x3Vv/Kv24d4+ok551lOdEdZwSKFegYddheBdmf2vQ +--- HdqhlLLi8pPd68vCFdqewcbZtxte71qUdwtLyx1Gl6M +W0௣Bja|nA ssh-ed25519 Y9/f4A LjFOd4/80NCBddfGjVI2TcPvQwaDPe/47bVAP1F4GR8 +lKdpWG+Od+1opNi8sz1sqnCcjPcYf7gaminddzwQv00 +-> ssh-ed25519 OuDDzg 8PQcu1lQL6JWtFPoX+U3I/i1KUnAnuJy3yeNeIC2Ti8 +diGkpXfE2jn0TjqVz6GzLFlzbJ+B0FcNioFvYwJRwdM +-> ssh-rsa VTMo4w +XSG2NZNLpcDAAWwS2VX+lLmGnEoO4p9TD0C8loe08XKzIBwSeVTnBzq++elAFWUk +AjvZ8YO3v1Dx/uHbyzXNCaAbADs17sGQvxCNoenwl2aZUhfkLwEk0RJ3PQRSKMDM +YEC31cUS1PAZoD1JqBZjWfNTZP4yps+luQgRv3ZjUBdQPjtJWSCMWo5joXFZlrIq +PZ/52qHDV8s4Du5W7VLyVYvEDZdJy5XugJcSxtJoHPRQDcimd+XVS/kJUZ2I7nG6 +fhDErlocMR2KhxTYe+pvw+CvIgj+ADK4OH3SbqCRFyTQVvWcVdZKHumIkzA5hM/p +rwF63LcB09NWIQoq5fQyXofA/QNOErZMKBxCWL54/jzvePCFB8EN64st9sa7Smar +cbQM6i+W477CHRhayjh6ZGqJcctKyJ8lEMR4kTkkfn4/m3cmWQXBHnKjarA19hYe +Nqhf9O53x+IIHUveb3nWDLZ6eOrLTz0PQ/ZDw3J80tRRTuLJEICUOt92lJt6MU5x +QRop6uKCp8b83l4J0rhcaXxsj2qzRfZhEqkXhMH2qFGVyEqD2pv09rXxqwGYlo02 +zdMbLXWDU3M7Gm81x9h0RZ4nwUrQ/9qAM1DFEe2JhUa99bnqNfCWdZnfR7t9nm4r +KwCYplfl1Xfj5Nh9IO5il0n/OilOOzaDydDnauroYFM +-> ssh-ed25519 uK3CeQ uFqTZEjPvd1uzZ8w+bcBmX8ygaer/gol4XYDkmiSGCo +hn7iLORu6x8hZjTbPStan3g+LNismFuqO5jPIX/5OT0 +--- lmfQokwyVVVnwMCsb0cRkKbxC47Jg/Fn9S2Fvtd71t0 +l*AOPVLGւq1ڥPh +Z@^YsoÜܻ. 2KÝvX؊Rȋ1%$XGxi3 \ No newline at end of file diff --git a/nyx/secrets/mailserver-noreply.age b/nyx/secrets/mailserver-noreply.age new file mode 100644 index 0000000..a1e1934 Binary files /dev/null and b/nyx/secrets/mailserver-noreply.age differ diff --git a/nyx/secrets/mailserver-postmaster.age b/nyx/secrets/mailserver-postmaster.age new file mode 100644 index 0000000..1c2794a Binary files /dev/null and b/nyx/secrets/mailserver-postmaster.age differ diff --git a/nyx/secrets/mailserver-vaultwarden.age b/nyx/secrets/mailserver-vaultwarden.age new file mode 100644 index 0000000..2a16b19 --- /dev/null +++ b/nyx/secrets/mailserver-vaultwarden.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A BYgXCUBoCzzo4nXl3jfHIZGwbh8TzM8nBiJ1l0Sx2QY +0ooP9B1RuZxra1H1spU1vriHk9Ib7Y7rFk9OieEWZq8 +-> ssh-ed25519 OuDDzg uZn8DC+s9mSza8tqZ4cxdTMlqJK1JZwe/wYs4JYK+Xg +gxgdcPZL/OvaPqTg0UJs7AHUCRP3oVgzidDfnsMaMic +-> ssh-rsa VTMo4w +cqbtt3IcS1u5f/z9qLhgEA1TjpaZ9/j4xGStiHGx9sNyM3fKcskUSOlHjgbt5Bf7 +DWNvUPjcCD37y8Pb88Gn1LRKMExU9jBAmfcTwUCpYGVc1HcX3GddNDJbJjxMqAte +Ctzl4tbhsgSbzbW/2+VvRGW17eQQ3mIGThamTr3y/z6Rkm8ouo+9jzpAfUC3NHsu +0Fc14ziIGgFS4x7+OBRfunRKtkdAdsm16hM1FHWQH1XP2nL+gfGQ6OwuaCs3VQgt +uCb+A+8qvqkz4ZDSk2JZOwb9KW41IPg4cs5pCx/g+Gz3LePPqAWX5usD44VKiREj +jfICD6u+B0FkRfzGscvfxg0mvqFG0sCwS3Qad4G5Xc5dlZQ1jFyxjiPeyVY1wg6w +UOpUt2lSqUbn07Lt1K5T944zHIUxNALZtHjjkOTtUAcu7LPSeAFilh+fXtdYTmiU +lTS2oWoy3PQjQ9J1WDAGb2yk7hwGs2OMRsQZMqKDTc1F263OcFqkgLjBEiPSnmOG ++vVe3HuyOQkPA+mCY2GRP8cNaseqxl4I328zU8WWzJ17B0AjzQMVoMcn/Z7jK55N +vp02ICp2Bm/O3GY1T01/Q4xvaENpoEY7OzfjHAS7uX+k2BDRGxEshLvVX6tlRC/x +FKU/dHDL9Clam86IDUkD4tshIr5oTbbE59YVTytQk3c +-> ssh-ed25519 uK3CeQ CRJIZVlEITID7SKTxMSY5kTC7Kgu+TlY2qBpVs6C/iE +Gj8hyVUAnC6Z1tKJAXmLdOZfbGz0Dyk5W8k5MXaEkX8 +--- 5cvDssCjcIvo+Sr1irj53LT/Di+oWo3RFrY9cBtYt6I +qL޵m?;k~=wx)}&jUQx{9{^(1xW h+7-/9 \ No newline at end of file diff --git a/nyx/secrets/secrets.nix b/nyx/secrets/secrets.nix new file mode 100644 index 0000000..7995abc --- /dev/null +++ b/nyx/secrets/secrets.nix @@ -0,0 +1,48 @@ +let + # users + notashelf = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIABG2T60uEoq4qTZtAZfSBPtlqWs2b4V4O+EptQ6S/ru"; + + # hosts + helios = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB8XojSEerAwKwXUPIZASZ5sXPPT7v/26ONQcH9zIFK+"; + enyo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKAYCaA6JEnTt2BI6MJn8t2Qc3E45ARZua1VWhQpSPQi"; + hermes = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEPShBrtrNRNaYUtIWhn0RHDr759mMcfZjqjJRAfCnWU"; + icarus = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHWh3pRk2edQkELicwkYFVGKy90sFlluECfTasjCQr1m"; + leto = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvw6R8RS6e1tpf5rnFMv+xWQsNk082wRlwTaaFKmIrx0iotP1nE5Tux+uKhx1u71se3LwtzvxvaAcZgqnowq1tZWCeqDWcz7uanDogsmjc+vS54P//gmhWAeAX9ClHIdFBpZSc1+R+aKws9KjJQBOUZi9/07f77AjmxbSDMVeCv5mMF++WjKlE8oJKaa2lLyhxeF5mr2GoNfCkF7FknTrX+mZ6EqW3g0FHHbhqCim4fdTZUberja/W4m2UwWXewgfTUVNowONB8035/BWbBwnxK8i2f2cqdXqF1SVN5SK14Bq7etIc0lJVmLcPz+R6kZPWu6NBF0D92eGBozdzCuJWy/NO/Y6G5Y2tSdFAkkTlpJPM4PA4pQP2XHuohgYOceMtDb4N75ZC10uNiDR/DnwVIa1dzjFQ1ZMfgZ94EwGd9Vy0oklQGrbkAXHA+DPFnc3PTuRUyMgOavI2RxIgYT8LQYWpxc0wGRiBXY/CqbaKSWERxxSlu4Js/0MfRq0GVyxAqE1Lg6C4oodXB4a6j/0/nF4jWLMxVTx3LH4hljV9o1JKbf3sApv9gUoF4Kwv3dv19iJhjcQLF9gKV8qCeIRC5Dp6cV0XI/IhmAMp5rCOVBqIUxYPWJBZYCatxS3gwVGqQPo/X6OLx35C5N5IVRVYd+D59s1crKTDvkZpGH1zOw=="; + + # aliases + servers = [helios icarus leto]; + workstations = [enyo hermes icarus]; + + # helpers + mkSecrets = list: list ++ [notashelf]; +in { + # core system secrets + "client-spotify.age".publicKeys = mkSecrets workstations; + "common-nix-builder.age".publicKeys = mkSecrets (workstations ++ servers); + "client-wg.age".publicKeys = mkSecrets (workstations ++ servers); + "client-tailscale.age".publicKeys = mkSecrets (workstations ++ servers); + "client-email.age".publicKeys = mkSecrets (workstations ++ servers); + + # service specific secrets + "service-matrix.age".publicKeys = mkSecrets servers; + "service-nextcloud.age".publicKeys = mkSecrets servers; + "service-mkm-web.age".publicKeys = mkSecrets servers; + "service-vaultwarden.age".publicKeys = mkSecrets servers; + "service-wg.age".publicKeys = mkSecrets servers; + "service-searx.age".publicKeys = mkSecrets servers; + "service-forgejo-runner-token.age".publicKeys = mkSecrets servers; + "service-forgejo-runner-config.age".publicKeys = mkSecrets servers; + "service-harmonia.age".publicKeys = mkSecrets servers; + "service-attic.age".publicKeys = mkSecrets servers; + + "db-mongodb.age".publicKeys = mkSecrets servers; + "db-garage.age".publicKeys = mkSecrets servers; + + # secrets for specific mailserver accounts + "mailserver-cloud.age".publicKeys = mkSecrets servers; + "mailserver-forgejo.age".publicKeys = mkSecrets servers; + "mailserver-matrix.age".publicKeys = mkSecrets servers; + "mailserver-noreply.age".publicKeys = mkSecrets servers; + "mailserver-postmaster.age".publicKeys = mkSecrets servers; + "mailserver-vaultwarden.age".publicKeys = mkSecrets servers; +} diff --git a/nyx/secrets/service-attic.age b/nyx/secrets/service-attic.age new file mode 100644 index 0000000..3b98e00 --- /dev/null +++ b/nyx/secrets/service-attic.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A 06NhCok5nGNk/iCsdZ412ovWbhMX4alTrS8f91eYglw +24mK7mtVm3Si0gIXXNYuKmNHeuM+P9paIKL7bZXx38U +-> ssh-ed25519 OuDDzg vvyfKzHWTABVmMF67CwQUnru9iIAVi76VUkU3O0pGS8 +hizBbWMvRHX2Yv9UUgiyEXDxwnjX3BZXvFQ3ANBxSSs +-> ssh-rsa VTMo4w +eb168LFPItoVKDKwyarnxWwANH6+suZuebmbJyr+7bT76pkbKg0jJxr+IIIMNGIU +SbdJyszyUCb7l6NphiDwgvYVHgferSKn1L86LN9604HqhigC0yNhHrF/xEl8DhBs +D+EGUPbPdlrNsf9Fi9qW385pfAdcpkosUlsIL/GxkkSwN1R8Hdv3ehpDQsuKYEBA +/m+eCpMFGy48gavt+UuFulo8wtgkn8WlkEcaRipa7XnUOyYKsjHvI0FC6BFwi6gG +fxN7MerZvyd8FTSG1BTHJjZaqsawdCtPJVLd/w+IMfMyWjSIVxVsf+OoEVwg0QBq +7o5Sar7m9anQUg6zhhbiNJz+IzMny8FJ5oX7h++70iOOEsdittFZSy6Xwlvy0AwN +9/Qq9oJ/GVofQHJ4DWXaqV8/bP0bciQBcG6raRz0ylygcFC9WQM3Bx9t3WcLBSoq +Ox8mRUY7lGg+yjEjSAv2SuNgSLtcNSMdLHzoyjQoMQl+48WLvT/67lEWtvtJ0/Bd +rlr1K2JK6n3apwCVWYNte7kaDT4xaXNj5OjbxWk2ivztenCr2xWq7DZeAx4q8VuN +QAsTYsB2HlHqOQgxvUylM3hmfqROWXdbhJix41AW1xMKtRpYNpbUlvU7uQz5RIDt +AB8b1qbFoPrPqPRXMHxlJKIrwvy25n3rb0ugdz/8/tk +-> ssh-ed25519 uK3CeQ 3DCJzir/OxaF5AdQpJPkps2gDeNdqzpK3ZaM1/ZUBUw +LOp9OntC8YX1hMY5zcwyTCFhl+sxfc3dHANioILuOLY +--- uNB0jMv3fS7tABm1x+7ozrybjxI9whoilkmDkSrwVdE +>!cw~$oLU "< >%<c&):"1)hHjQhɟzV3rUMkƘ=!_E@tyN^:YGI vǣMv'9MZ3P wRFl= \ No newline at end of file diff --git a/nyx/secrets/service-forgejo-runner-config.age b/nyx/secrets/service-forgejo-runner-config.age new file mode 100644 index 0000000..9fc27d9 --- /dev/null +++ b/nyx/secrets/service-forgejo-runner-config.age @@ -0,0 +1,25 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A kRMLXEKoRVXiGVzBHf0dIjpg5jo0Ny8KpJmWzOZfGxA +U2D+rEoh52IbPiNz6Vdygoxb5fGkhNEYftXzIEB46v0 +-> ssh-ed25519 OuDDzg Vfvu6xG4CBwd7aGRQ6aHz7KIipaG/7u7ofccc6r4bAc +kUE0zgCxW7qe/oNI7NmGw0t1jDRqM3EkeoMbThKe9Lo +-> ssh-rsa VTMo4w +GNLArPzdmDVPF67Vh3ca9W6u7F7/ozaiteOqSR/ryhtL/+ztH/gaifiYUDzSroVO +AQUJhyUfFhJSY6eVzOw9VjEb9VOyRQNfTBxZDA8Hk2lF8fsYPCM2rsw/pTl4yFiK +4zxO0xdsT1fvlAIuZj34uoWeR9Vk9WpIrhJuXR2dLkLnxZ+DRam6OF8C0NsDbhYi +Qtl9D+iFPqx3mU/fdXxE+20v7SIbQNwQUnLtQaYY2rA4pcWapQfIaofKd/9f20ZF +u6MAaNqCw6xOBfeshxLAfDycB+ui3RybFPdDBt15FUp17kSACKjHnULDQjTVOSSM +r3GWpXaqHiPLQW/F7nb+ic/u7m203hIEXSakM/Vl1Yz4etIccAtswjQ2jRdqH3gm +6++acrl2AV39XzUBRp+6XffY4Wecw8GwqgV+HpqgUNO7b5OMxX9Cx8ba8JWUoruD +SAJ7EnTa9QEmSP2TrQwE0SV/D4RsqnLwdWxTwppFXehho92RJpOevdKrz9StGlEh +01CymtFkBJXJMvaStjQRixJrw4VdVJCNDx90rYzf6AgVs4a7acjmeX4q7rSA+HLw +7I8FRyBNTpRSAsE7rvQQVXlAuM5uiuNRfRCHsCdIqsf4hyrA+JUSLA2KQVtU2NXm +eZRsOEQWc/ZwZ7MoArcIB4GhbIR2DJnkKWePhib3lBM +-> ssh-ed25519 uK3CeQ OTyNUCr3sQ7k7Z/+QlXVfiCg17C7+wZ5aA/f3JY5Jjs +z6Ae9YXXYxb9odit8TreNcyzJ2q2SaPx3TsQfEYnGZ4 +--- RoF2jNf26B2DBn3uoBu1+5lP5ShQk7VmhuT+BhtGoHQ +=[1GޤVSk9Gw?H~53^1`bqds]'9( +z0XZ{lcX{1$ TK-}aFj?s}OXwخѵ0\~-]9ܰ>Hg +zT^xRgy^T% 6nmb| ssh-ed25519 Y9/f4A jUfxlbNl8yTpNFWLskLJQkZP4jyjltZgLgC8dkt3M2w +oA7q1Z7amNaWo15tnp/6AtejT2lwC+zStNqo9s7j4iM +-> ssh-ed25519 OuDDzg 1SNHOs4GIbUGEULFmQKN32io13J/6h5oJQ9J+HJZjjM +bUmcXeAoqSiKu31wKdhVlcW8Jz1+R9BsPwTi2P/KHCg +-> ssh-rsa VTMo4w +ZJNPbDoQDVEu7ILgojq/Rhg5FtuNnVVkwuK8s60N4U/N5hTe7Iq/URKe5Y0ICUqR +3jRU3pTm2U0CsqhhVSKiMfHTm2Mw2hg1Nr9WM00sM31N3EsG8sHIJ6iYwPA7QnXH +ICQQ+j/FyBARixBFHlMhOKb7HAP7U/DBmfURK6YRg7kZLgMVds3eJL6Bb+IR2Tau +BmHjLVaZL2EcixDMpUxIar2TG7IWSyE0yrYUWD1OVEBjsgRKph3HQrQce357kTfX +ryILAfJcMb+2ln4pa1O7NCKGwrb+WUNPSIaByUE2wFOeBlF84osig3dKfl4dxjAY +NqQpi7v6q2yH6L+GcWY5ThFlsp7lpSyZFX4iB7Lpp6OLdnKMt4TsYlh7NlV/u2Cx +HcNcx165xKVEKB1jj0JA8n+AUge9+vMRHADTwGqhd/X+J0MzMtcB570SctcAFvfB +D6xPQgZwDyvdU8nIayIvGufWYJe/6r5RueGjKFcZ9ItsmQIMj9TuzE0SOXL3qcAl +phyaYmT2qQd6PsCimu57+fHvT7eQaWivJEGuBxjbOCfrcVjgGi+HXa80KVh0Lrdv +itMZcobDuxQ/2C3jUf75VScK/+8N90ZuY/fOy/3cSpmcbbB+A20NOycQUsUAupGu +LVAwdrx/3syihEC9wkFSupLWn95XefkjNNiqupYfvbk +-> ssh-ed25519 uK3CeQ 0oUJGkZU7EhQwQuWZN3LSfByV5hagyuSuXpXoXXzoAw +R+vN1+5Kc3U3SmbqOdidhyamhvmjJNEO9UEMjHqBAx0 +--- 5NhXR9TkEiTm4cPRDiQr7cFHD/2BLA/ZRh8Z5W3xja0 +, W̥K4-D53{RsZ`eG5 HQtxJalǫ \ No newline at end of file diff --git a/nyx/secrets/service-harmonia.age b/nyx/secrets/service-harmonia.age new file mode 100644 index 0000000..d1b4ba9 --- /dev/null +++ b/nyx/secrets/service-harmonia.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A mTyxXr2kX3XQkrTsGbbYwcCtd2ZqWj3fJgYv5rXs2nU +hNFt7weKbbnKh+M8x8HR/j//zDd7ndl7FRXHw2wJmrk +-> ssh-ed25519 OuDDzg lzuswwyLrHec4PVnMNjoqjMsLV7yA8IyLMvJgffM6n8 +mK7M8yBvpbeBFSG3d2GMs5d3HYrO8HkchY8vEzifRHw +-> ssh-rsa VTMo4w +jPamWrXByApsBgV73lf0kHawS3h6R1BgjHVh+rQj6B8BJZElLoOQ9GqZy0lWIIYc +78VHF6qivffBT1BUQpC8+fBwUNZ2jl8WmfZckC2Y75Qsv/d43rZZT8HsG5jULID2 +DOM3S/D9xtJORQi2JHHvsaQdnSFVjYggVLeKIvcy1FpcnUoVlHyuRXD4sVjI3pKl +tpl45949JFuCQGQDMWR8jQb8eZPSnzZUylGoqS8p9uRHpbxhR4Xxuaz99F8zvfUl +FxwREZqiIlyNd3vdaCLbnf6cAmGeNFQOkYgkwhnj4nXqiEdKCUHSAOgRAjUFqV5k +JHm9zzA957G79vrTv6dtj69NfZdU4v34LXcMQvHaRvIJxL8B5sWtPdfDI3TWUNPk +H+7c+/xHrOrXSeVVjf0GF0AMcRGvltJHF1PpTitvi8c0yWS1IwCL9rqxsoBQMi6E +fRKjYycBHmn29gGjXqapCst7FKR7prZHMe4NpSYCpyJ2ftN3QEnY9Ns1m4lseicw +ZymKTVqnvAkHEIhu79F/MEBEu/WvnUFBpPCdPEu5GfNtKzq5v5K+GYnrJSvDuKS8 +DIqwJgTXSk/omFrhTXQYrecBzk2scdypvY/FTcmWGYWgCxp4mbaPObrFnI7M6l1E +qVG4vt7MRlQCeYlGE2p/pstNghHcQvt3SLv22NWcho8 +-> ssh-ed25519 uK3CeQ sThPrV/uzCch6VDK2zBUXTTrPWr9k2q4eSect5L/tkA +gsoP3EPpx8TYmcZjGhKkbqyy36AcCG1cswD88z0X96o +--- JExgjORF2QQva4n4KUxXMirOcxyiqosUu5LZZy9KEW4 +7 ~'mc;,68O\ X:ۨcBpDwV+d:Tc!7SQI |4]Y}p p&4M!T7W`W2#kQOpnn얳=WK@v \ No newline at end of file diff --git a/nyx/secrets/service-matrix.age b/nyx/secrets/service-matrix.age new file mode 100644 index 0000000..b0ab0fb Binary files /dev/null and b/nyx/secrets/service-matrix.age differ diff --git a/nyx/secrets/service-mkm-web.age b/nyx/secrets/service-mkm-web.age new file mode 100644 index 0000000..6f5ff7e --- /dev/null +++ b/nyx/secrets/service-mkm-web.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A /xdWyTjz8FvMyglI0tv00cLJMXS4mCnU9+aU3KNa4BQ +g+I6VOcQeqRtQ4tyLjBHxxN+YtNG1q3LvQI2PTwNADo +-> ssh-ed25519 OuDDzg U/+0vBjmA925+68/MxCwpb3NNcAP2Xq5ohcrx5S0xzc +rfXry21ZBIi3187i1RDIYvbcpAfQ5OoAWduzaeCtz3k +-> ssh-rsa VTMo4w +mNeRSe819PD1tDZqv0idRxu9IEKj50E7QqtxhhsUa3D89gVcwpmL+Z7Q/IWmTGM+ +cdIZk7GBv2O9EasC8F0IZvdi+NCRlU79gzlOEfjC5hAtcI3fK4BhcZkNZ++4nV9D +uZmbroW3QmxSa5iFBSKiUTm24KkWcUjWCNqIjgmTsWeOq5fxImhLsCBOmEmDUSwa +oGDU2dYG2mNULB3GOhnef1OtPMAHmRtW3g5kZTJF/IK0BmgbkK08JppCq/Gx41RC +beUBJ9JU7OqHKlf1wAzGwJG32QJP8ifkTLDwB7YFE6bL38olU9iM9hl9V9ItJrGV +i9Nn0be7ZXK2OmRHNnQ3pwpRRgIm7rOdKScn0Dz2N9dKu8a7Ogk9y4FIrONXiUuA +1oWQJR8hCADYZ/TKii491pmEoX9Ua9J+HYcvumzwk+hYSqKO3WplCvK+y3Wiyein +4BGACrcxYcIhWXg9kJWBYx/ij3ScuTnnRKtk87lRLILxXuG9IO1I/7QVXFHJYnVt +PPe9wGpQmapsRwgNWrlods2oYq5+DXjttlGrdv2x8u331VpsLtKTI8orADm3988E +q50OhcHrLevR14yWRGhnfuvPRp7F3+KqcTlmlnkTIrzzTrnsHxK4AzBprQRcotip +AEDqSxLM6siJQQAZyvBL1NouLacHkMq+GLYApDizIvY +-> ssh-ed25519 uK3CeQ P6YNSem6zTsIuIPkAJfWHBUP5YXBzkgckTUnza0GR3w +42J5Zaofdu44Khq33QJ6ILtU/EFzS6Aa7vgs3vyijVo +--- IhDwjcGxOYEVEGzx2YThQNSeuOHuHeq8WtCV7xkA4ug +B䍺nЊડTQ :X5+pi[1ʼuf}jz_aR 5`#>)=zE3e`LX?BaMR`+'vn' Yxd.,:?enK*TiT xi?!ds b GXݾ2 +dFXIs[ diff --git a/nyx/secrets/service-nextcloud.age b/nyx/secrets/service-nextcloud.age new file mode 100644 index 0000000..cd20430 --- /dev/null +++ b/nyx/secrets/service-nextcloud.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A jOOzcBtNBF2ILWQksxCAVZSJN1Kj/p27P7E/jUqXzg8 +fWWRK2qLEqckeGMdOFt831BIxwF4Ct6wsp9qb9u6thU +-> ssh-ed25519 OuDDzg 2LEH9uoNmx3gpgBa0eNfgwGYDavfEEbKbjUPcSoKBzk +3ZXvMWPUG4w8s/trQTl7UOFA/u0M/F1rpIIm65xHrpI +-> ssh-rsa VTMo4w +bks3wQadOYwcUWz1udf8wmf7FzHP1edEhkUr3tMzI0U00uH31dSsJH3gP+t0L34g +SpZ2FbstUalMx7Q0DlMQts5py53t2agoplxVmxNryjzr1AOFTlL2cDfxjUdjgdlN +b+f3bRW04dO/C9F1K3H2MdnGBZ2hsrKAI7NLH6pKGmrS2ZCNQwtdMDoluabLWBcD +rXo08kxcGRmN6SNVF6tsG+fwGkXUd5ynarFJIqCB7mS2R125d0EkV47GVlzxmMYv +ORelNctaicBJ+dT5oZYNTG2+M+Qoz9sdRUDF9hSdpFYxJtacLyDnn3WrBBSOuGQ9 +C2YgR++lH/0623sb8aPRrWYtScKatgyB5GlsDyc2ET9hiE9bOBIt3e08RHuPfOvo +q8N8V4CbB5TdhQfb4FQq9n/XBTOBbHqJuPODXFMYWaHDqkQdJGots7ULZ0BN/MzY +3PRU7HUQoYjJpIT/EyxSr8j+YZwM2I+uah7uAIhfXng7F+VNEGC9k8gL7pq4iDZF +KJKQGnJEVcFdKB6mGatLB1j2g9vAup7fjF2t5kx0R7P8iIX/igPHys3NePwxEU2y +1GWAQTYIwSzP9enVpyEQUpZIltMhebf6Hj4aU/EDuUR2NayoDXrINFrPx2pisX/6 +KVSxU+DppBlBHwn+KtDRds9JcaXpklsR3UFoPBGNGRM +-> ssh-ed25519 uK3CeQ Y0DL2H7rHoRKqiDw3t6YPWEj3xYt/suga/tMVEEwhmo +8+OemivbGwWuwK/Du2WKA/bWPXyX3O6RCfBLRIhLceA +--- 0hrTl+JNBDjXVCE6iwUcqUB6nnnxfr0KopFGVo9Blbo + +T$`"R]߻8Z@Dp]r:r iq7v2 \ No newline at end of file diff --git a/nyx/secrets/service-searx.age b/nyx/secrets/service-searx.age new file mode 100644 index 0000000..0351be8 --- /dev/null +++ b/nyx/secrets/service-searx.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A JHuOuHcWtNuWqp50MTzzLfsWe8f/8plamw3Hu3MR/j8 +2hyxCa9MaLnOZlR8q1sqP5cJNwMTY3NtzzX3U0rk254 +-> ssh-ed25519 OuDDzg /H2vWqOhzUVMHTNvR71t5rGGkfdN/kky0yBmn2TxwU0 +Mik1zbW4wYUMMIHtijyjagrfyD20GNTCFJTrdVDLe5s +-> ssh-rsa VTMo4w +fDp7bPfxeHtkVY5PlkMlc4l05VNZc4qtKC62yat4WSLFjZSsPHIk0iP7kLzqveSr +PP2pov4O541OX7dRcgFS4Vbyr/C+6ETnfEgmHk9l92g1TA18+MGDMWECTaEGgWHA +rk13VUMxmzIOSgC9FkZy1rEGf6y/bGM8cmwSYv/5W23UXKFeXBr6P5MmGex4qB4V +Sf5nPi35rVYifI7QoKPi/IH0+iqHwvv4zfjyLw75t8qVy4VlFgrUfsvau6pXOh07 +NunAmEFK6lKFZLylNqBl/p5MOOIh9Uk8reQ9yzmYNjJP6DugXk4H8YN7XmHVzgi5 +cpGPA4FiBvWxgksGepepzFnOy0yQO/znUJ11A3f5yw90AWBcJROdr+ERPSJG5IpD +mlOLZcJXieb4FjAoAXiVE7s0Mh/uBJuSj6Nof3RLnIAuR7chCTinsPwEZSgCqFVp +0334yWSfHdcRmgVoZVfC4EZhzgzRI9rlvV1tMiwJQCZXwSdLWpX5ygf5NFwATy7/ +c4VtRuJVcJyLasBdmYKwFj1QA7C8fEGUEE/gsLW5Ju5Np+9hiUgTns3EQf46ISUW +G4UpnhfqnSjLmFNozsaLeXBh472LbFgS8MZd345ZaDJe3Kenm8AzzqZ8TBa0G21p +nUeF1vp/PUDXfsqd+dBBQv5hSBsvPP8+ui3x+Lt5q+8 +-> ssh-ed25519 uK3CeQ puUap3885geNATmqb816B44ndnSmuBjSV6lT1B2gtDU +SwjCHP/askKGFLel9JGDh9ZOSCOuwkDtoA8RgMUaizc +--- vEJCNu6KvrPX01AdBGGIFKGki4jYfW/FpRjuM6To6q8 +R4d׃X3:lF.Gu-#p aM[#" i6puHlf;I>x#u \ No newline at end of file diff --git a/nyx/secrets/service-vaultwarden.age b/nyx/secrets/service-vaultwarden.age new file mode 100644 index 0000000..4b08d66 Binary files /dev/null and b/nyx/secrets/service-vaultwarden.age differ diff --git a/nyx/secrets/service-wg.age b/nyx/secrets/service-wg.age new file mode 100644 index 0000000..f6b4962 --- /dev/null +++ b/nyx/secrets/service-wg.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 Y9/f4A gYq1T8DPSDEIIHUPbnLJ0HbNGcc38i/rQG6DVBbPPUE +OVQedgw8oTMis1zD9FtHrdCrXFdIRgQa9ZHUJRLGo5g +-> ssh-ed25519 OuDDzg KQXtMRYhUWdYRrJZ2BfOzyFIe8r5CxcdawKQ3WW1/wg +3rdk4J4Y7TDPEvb6jD9RHY463SzHnImTJgDsgS4D454 +-> ssh-rsa VTMo4w +rvHwh2kERI5APX/jW93Jf99WB2dmvNBtKuKv3l7OIDSVRfO6xMMxAqnWp2rY9AgX +s5plLvN0hOTt6mTg/HD//FjaUXdhUu3u+EISFEXB6MPDma6NndUmFWocBcpAY9KO +J5exKixwizfvSm+yXTURvOqQSoLvPUX+OhcRYvv47muThmFGvL6/yNJIBUs9m4g3 +bKD99+WTRMkfhwEZHXautGTl/vzIJ8qFuAe5OUtNtIWttkBiWIrLLRoUY6aO5Q9p +WMmQO2TSc/5/LkxicmFwBhJ6duC742Z98fKmP2yjFVwvWzhO9Tkc4zSGMDSwXT3X +FlPHCwenCT3AhQjmpHdCjNkqpe9S2qhEYsSPwX3XZncagcbBXWrZSLCS1WRBYvX3 +1so/tEPDBAU+bO/GWXanmqLva2ydeueEwAwjNwU4DdG8f1+XkfbunNQiof0HOSqp +fGnPOpp93TVzrHJFv1aR5VDolsD+1zTFYB/bMdqjgfsuvIzAoRkxjazrZiwUz767 +ZPlJnkT+NMzZiCMERIVX51uNz3kIwYDXWN34QXqKXNCSr1+qUMXot8BPOI/mPcvc +gMMhSZSD9wTGloK2bKRqWjRGjNBrn9UVkVIEtAeRwU/t9BenYSHf76yNcHggJA6T +TJRChcDunU1bWfkNTTfG57W5co85oY1JXhqCKdTVRqc +-> ssh-ed25519 uK3CeQ hOtyjzAoPTCmv7c3v7wzGd5QXTkwITXiMAby++kKaz8 +Y9190uO5b464ApA6cN02zSZMJ3bHpFQNiuEu/UoKqZs +--- S8oCGc7/r3MuIwcnkyFlxvtkbETRglDFDT+7V0U4n0A +s]nK:yI|I)jz)[Lnج֡`;q2$Z'Q.4D{Cm^ \ No newline at end of file diff --git a/nyx/stylua.toml b/nyx/stylua.toml new file mode 100644 index 0000000..5e3c178 --- /dev/null +++ b/nyx/stylua.toml @@ -0,0 +1,6 @@ +column_width = 100 +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 4 +quote_style = "AutoPreferSingle" +call_parentheses = "Always"