feat(menu): VPN setup & management submenu (WireGuard/OpenVPN/Tailscale)
A dedicated System → VPN flow (nomarchy-vpn) past the wifi picker: - NetworkManager VPN/WireGuard connections shown ● active / ○ inactive, toggled up/down on select (networkmanager-group users need no sudo). - Import a *.conf / *.ovpn via the fd picker → nmcli connection import, type chosen by extension. networkmanager-openvpn ships system-side (networking.networkmanager.plugins, mkDefault) so the openvpn type is available; WireGuard is native to NetworkManager. - Tailscale block, self-gated on the CLI (= nomarchy.services.tailscale): read-only status + up/down + exit-node; privileged actions go through a sudo terminal (the snapshot pattern), no operator wiring. Waybar custom/vpn shield (nomarchy-vpn-status): self-hides unless a NM tunnel or Tailscale is up; @good tone; click opens the submenu. Wired into the generated bar and both summer whole-swaps. Decided import-first; creation deferred to nm-connection-editor. ROADMAP marked shipped. Eval + home/system builds green; both scripts pass bash -n. Pending an on-machine check (live nmcli import/connect + Tailscale paths). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,19 @@ let
|
||||
[ -n "$next" ] && powerprofilesctl set "$next"
|
||||
'';
|
||||
|
||||
# VPN indicator — shows a shield when a NetworkManager VPN/WireGuard
|
||||
# connection is active OR Tailscale is up; prints nothing otherwise so the
|
||||
# module self-hides (like nightlight/updates). Click opens the VPN submenu.
|
||||
vpnStatus = pkgs.writeShellScriptBin "nomarchy-vpn-status" ''
|
||||
active=$(nmcli -t -f TYPE connection show --active 2>/dev/null | grep -Exm1 'vpn|wireguard')
|
||||
ts=""
|
||||
if command -v tailscale >/dev/null 2>&1; then
|
||||
[ "$(tailscale status --json 2>/dev/null | jq -r '.BackendState // empty')" = Running ] && ts=1
|
||||
fi
|
||||
[ -n "$active" ] || [ -n "$ts" ] || exit 0
|
||||
printf '{"text":"","tooltip":"VPN active (click to manage)","class":"on"}\n'
|
||||
'';
|
||||
|
||||
# Per-theme override probe.
|
||||
assetDir = config.nomarchy.themesDir + "/${t.slug}";
|
||||
styleOverride = assetDir + "/waybar.css";
|
||||
@@ -77,7 +90,7 @@ let
|
||||
|
||||
modules-left = [ "hyprland/workspaces" "hyprland/window" ];
|
||||
modules-center = [ "clock" ];
|
||||
modules-right = [ "tray" "pulseaudio" "cpu" "memory" "custom/powerprofile" "custom/nightlight" ]
|
||||
modules-right = [ "tray" "custom/vpn" "pulseaudio" "cpu" "memory" "custom/powerprofile" "custom/nightlight" ]
|
||||
++ lib.optional showLanguage "hyprland/language"
|
||||
++ [ "battery" "custom/updates" "custom/notification" ];
|
||||
|
||||
@@ -131,6 +144,15 @@ let
|
||||
on-click = "nomarchy-powerprofile-cycle";
|
||||
};
|
||||
|
||||
# VPN shield — self-hides unless a NM VPN/WireGuard tunnel or Tailscale is
|
||||
# up. Click opens the VPN submenu (nomarchy-vpn). 5s poll like powerprofile.
|
||||
"custom/vpn" = {
|
||||
exec = "nomarchy-vpn-status";
|
||||
return-type = "json";
|
||||
interval = 5;
|
||||
on-click = "nomarchy-vpn";
|
||||
};
|
||||
|
||||
# Night-light (hyprsunset) indicator. Self-gates: the moon shows only while
|
||||
# the schedule runs; otherwise the status helper prints nothing => hidden
|
||||
# (enable / re-enable from the System menu). Click toggles instantly — writes
|
||||
@@ -226,11 +248,14 @@ let
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#tray, #pulseaudio, #cpu, #memory, #custom-powerprofile, #custom-nightlight, #custom-updates, #language, #battery, #custom-notification {
|
||||
#tray, #pulseaudio, #cpu, #memory, #custom-powerprofile, #custom-nightlight, #custom-updates, #custom-vpn, #language, #battery, #custom-notification {
|
||||
color: @subtext;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* VPN active → accent green, reading as "connected / protected". */
|
||||
#custom-vpn.on { color: @good; }
|
||||
|
||||
/* Night-light active → warm tone, matching the filter it represents. */
|
||||
#custom-nightlight.on { color: @warn; }
|
||||
|
||||
@@ -285,5 +310,5 @@ in
|
||||
# The power-profile helpers on PATH, so both the generated bar and the
|
||||
# whole-swap themes' static waybar.jsonc can exec them by name.
|
||||
home.packages = lib.optionals config.nomarchy.waybar.enable
|
||||
[ powerProfileStatus powerProfileCycle ];
|
||||
[ powerProfileStatus powerProfileCycle vpnStatus ];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user