From 28ee56aeffe92c1bbf40758e109360664a314fcf Mon Sep 17 00:00:00 2001 From: Nuno Duque Nunes Date: Sun, 24 May 2026 20:46:02 +0000 Subject: [PATCH] feat: identity show with rule tree, peer dimming, net/group tableless layouts - identity show: peers, rules tree, dim offline peers - ui::rule::identity_block --no-header flag with reduced indentation - ui::identity::device_row: index suffix fix, offline dimming - net list/show: tableless with port display and descriptions - group list/show: tableless with status coloring, stale peer handling - group list_data: filter stale peers via clients_dir - logs: hourly collapse for attempts, --detailed for raw events - hosts resolution in wg_events static view - wg-quick PostDown iptables error fix (2>/dev/null) --- commands/identity.command.sh | 12 +++++-- modules/ui/identity.module.sh | 33 +++++++++++++----- modules/ui/rule.module.sh | 65 ++++++++++++++++++++++++++++------- 3 files changed, 86 insertions(+), 24 deletions(-) diff --git a/commands/identity.command.sh b/commands/identity.command.sh index a56c0ca..9810b4f 100644 --- a/commands/identity.command.sh +++ b/commands/identity.command.sh @@ -140,7 +140,7 @@ function cmd::identity::_show() { data=$(identity::show_data "$name") peer_count=$(echo "$data" | grep '^peer_count|' | cut -d'|' -f2) - # Precompute handshakes once for all peers in this identity + # Precompute handshakes once for all peers declare -A _id_handshakes=() while IFS=$'\t' read -r pk ts; do [[ -n "$pk" ]] && _id_handshakes["$pk"]="$ts" @@ -168,9 +168,17 @@ function cmd::identity::_show() { esac done <<< "$data" + # Rules tree + local identity_rules + identity_rules=$(identity::rules "$name") + if [[ -n "$identity_rules" ]]; then + printf "\n \033[2m── Rules \033[0m%s\n\n" \ + "$(printf '\033[2m─%.0s' {1..38})" + ui::rule::identity_block "$name" "$strict" --no-header + fi + echo "" } - function cmd::identity::_device_status() { local peer_name="${1:-}" diff --git a/modules/ui/identity.module.sh b/modules/ui/identity.module.sh index a4bab5d..2faf201 100644 --- a/modules/ui/identity.module.sh +++ b/modules/ui/identity.module.sh @@ -22,15 +22,6 @@ function ui::identity::detail_name() { echo "" } -function ui::identity::device_row() { - local peer_name="${1:-}" dev_type="${2:-}" \ - dev_index="${3:-1}" status="${4:-}" - local suffix="" - [[ "$dev_index" -gt 1 ]] && suffix=" (#${dev_index})" - printf " · %-24s %-10s%s%s\n" \ - "$peer_name" "$dev_type" "$suffix" "$status" -} - function ui::identity::migrate_create() { local peer_name="${1:-}" identity_name="${2:-}" \ peer_type="${3:-}" index="${4:-}" @@ -78,4 +69,28 @@ function ui::identity::list_row_table() { local types_display="${types//,/, }" [[ -z "$types_display" ]] && types_display="—" printf " %-20s %-7s %s\n" "$name" "$peer_count" "$types_display" +} + +function ui::identity::device_row() { + local peer_name="${1:-}" dev_type="${2:-}" \ + dev_index="${3:-1}" status="${4:-}" + + # Extract connection state for dimming + local is_online=false + [[ "$status" == *"online"* ]] && is_online=true + + # Only show index suffix if peer name doesn't already encode it + local suffix="" + [[ "$dev_index" -gt 1 && "$peer_name" != *"-${dev_index}" ]] && \ + suffix=" (#${dev_index})" + + if $is_online; then + printf " · %-24s %-10s%s%s\n" \ + "$peer_name" "$dev_type" "$suffix" "$status" + else + local clean_status + clean_status=$(echo "$status" | sed 's/\x1b\[[0-9;]*m//g') + printf " · %-24s %-10s%s\033[2m%s\033[0m\n" \ + "$peer_name" "$dev_type" "$suffix" "$clean_status" + fi } \ No newline at end of file diff --git a/modules/ui/rule.module.sh b/modules/ui/rule.module.sh index 73ddf53..ba1f5e9 100644 --- a/modules/ui/rule.module.sh +++ b/modules/ui/rule.module.sh @@ -167,22 +167,50 @@ function ui::rule::tree() { # ui::rule::identity_block # Renders the full identity rule block in inspect. function ui::rule::identity_block() { - local identity_name="${1:-}" strict="${2:-false}" - + local identity_name="${1:-}" strict="${2:-false}" no_header=false + + # Parse optional flags + shift 2 || true + while [[ $# -gt 0 ]]; do + case "$1" in + --no-header) no_header=true; shift ;; + *) shift ;; + esac + done + local rules rules=$(identity::rules "$identity_name") [[ -z "$rules" ]] && return 0 - - printf "\n \033[0;37m· identity:%s\033[0m\n" "$identity_name" - + + if ! $no_header; then + printf "\n \033[0;37m· identity:%s\033[0m\n" "$identity_name" + fi + + # Indentation levels: + # normal: entry=6 label=6 own=10 own_label=8 + # no-header: entry=4 label=4 own=8 own_label=6 + local entry_indent label_indent own_indent own_label_indent + if $no_header; then + entry_indent=4 + label_indent=4 + own_indent=8 + own_label_indent=6 + else + entry_indent=6 + label_indent=6 + own_indent=10 + own_label_indent=8 + fi + local first=true while IFS= read -r rule_name; do [[ -z "$rule_name" ]] && continue $first || printf "\n" first=false - ui::rule::_identity_rule_entry "$rule_name" + ui::rule::_identity_rule_entry "$rule_name" \ + "$entry_indent" "$label_indent" "$own_indent" "$own_label_indent" done <<< "$rules" - + if [[ "$strict" == "true" ]]; then printf "\n \033[2m(strict — peer rule suppressed)\033[0m\n" fi @@ -192,30 +220,41 @@ function ui::rule::identity_block() { # Renders one rule within an identity block. function ui::rule::_identity_rule_entry() { local rule_name="${1:-}" + local entry_indent="${2:-6}" + local label_indent="${3:-6}" + local own_indent="${4:-10}" + local own_label_indent="${5:-8}" + local rule_file rule_file="$(rule::path "$rule_name")" || return 0 - printf " \033[0;37m↳ %s\033[0m\n" "$rule_name" + local label_pad + label_pad=$(printf '%*s' "$label_indent" '') + printf "%s\033[0;37m↳ %s\033[0m\n" "$label_pad" "$rule_name" local extends_raw=() mapfile -t extends_raw < <(json::get "$rule_file" "extends" 2>/dev/null || true) || true if [[ ${#extends_raw[@]} -gt 0 && -n "${extends_raw[0]:-}" ]]; then - ui::rule::_render_bases extends_raw 10 8 + ui::rule::_render_bases extends_raw "$own_indent" "$(( entry_indent + 2 ))" local own_output - own_output=$(ui::rule::own_entries "$rule_name" 10) + own_output=$(ui::rule::own_entries "$rule_name" "$own_indent") if [[ -n "$own_output" ]]; then - printf "\n \033[0;37mOwn:\033[0m\n" + local own_pad + own_pad=$(printf '%*s' "$(( entry_indent + 2 ))" '') + printf "\n%s\033[0;37mOwn:\033[0m\n" "$own_pad" printf "%s\n" "$own_output" fi else local own_output - own_output=$(ui::rule::own_entries "$rule_name" 8) + own_output=$(ui::rule::own_entries "$rule_name" "$entry_indent") if [[ -n "$own_output" ]]; then printf "%s\n" "$own_output" else - printf " \033[2mfull access (no restrictions)\033[0m\n" + local full_pad + full_pad=$(printf '%*s' "$(( entry_indent + 2 ))" '') + printf "%s\033[2mfull access (no restrictions)\033[0m\n" "$full_pad" fi fi }