feat: display config system, table/compact toggle
- modules/display.module.sh: display config loader - .wgctl/config/display.json: per-view style configuration - ctx::display: points to .wgctl/config/display.json - json_helper: display_load() reads view styles - list: display::render dispatcher, _render_table with dynamic widths/colors - ui::peer::_row_color/status_color: shared by both table and compact - table layout: aligned columns, colored status/rows, dynamic separator
This commit is contained in:
parent
dda8e408e8
commit
7a544f9019
7 changed files with 149 additions and 15 deletions
|
|
@ -226,8 +226,11 @@ function cmd::list::run() {
|
||||||
|
|
||||||
case "$style" in
|
case "$style" in
|
||||||
table) cmd::list::_render_table ;;
|
table) cmd::list::_render_table ;;
|
||||||
compact) cmd::list::_render_compact "$collected_rows" ;;
|
compact) display::render "peer_list" "$collected_rows" \
|
||||||
*) cmd::list::_render_compact "$collected_rows" ;;
|
"cmd::list::_render_compact" "cmd::list::_render_table" ;;
|
||||||
|
|
||||||
|
*) display::render "peer_list" "$collected_rows" \
|
||||||
|
"cmd::list::_render_compact" "cmd::list::_render_table" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -346,19 +349,59 @@ function cmd::list::_render_compact() {
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
function cmd::list::_render_table() {
|
function cmd::list::_render_table() {
|
||||||
declare -A rule_counts=() group_counts=()
|
local rows="${1:-}"
|
||||||
_list_header_printed=false
|
[[ -z "$rows" ]] && log::wg_warning "No results found" && return 0
|
||||||
|
|
||||||
cmd::list::_iter_confs_table
|
# Measure column widths from data (same as compact)
|
||||||
|
local w_name=16 w_ip=13 w_type=8 w_rule=10 w_group=10 w_status=10 w_last=20
|
||||||
|
while IFS='|' read -r name ip type rule group status last_seen is_blocked is_restricted; do
|
||||||
|
[[ -z "$name" ]] && continue
|
||||||
|
(( ${#name} > w_name )) && w_name=${#name}
|
||||||
|
(( ${#ip} > w_ip )) && w_ip=${#ip}
|
||||||
|
(( ${#type} > w_type )) && w_type=${#type}
|
||||||
|
(( ${#rule} > w_rule )) && w_rule=${#rule}
|
||||||
|
(( ${#group} > w_group )) && w_group=${#group}
|
||||||
|
(( ${#last_seen} > w_last )) && w_last=${#last_seen}
|
||||||
|
local cs
|
||||||
|
cs=$(printf "%s" "$status" | sed 's/\x1b\[[0-9;]*m//g')
|
||||||
|
(( ${#cs} > w_status )) && w_status=${#cs}
|
||||||
|
echo "DEBUG cs='$cs' name='$name'" >&2
|
||||||
|
done <<< "$rows"
|
||||||
|
(( w_name += 2 )); (( w_ip += 2 ))
|
||||||
|
(( w_type += 2 )); (( w_rule += 2 ))
|
||||||
|
(( w_group += 2 )); (( w_last += 2 ))
|
||||||
|
|
||||||
if [[ "$_list_header_printed" == "true" ]]; then
|
# Header
|
||||||
cmd::list::_render_footer $has_groups
|
printf "\n %-${w_name}s %-${w_ip}s %-${w_type}s %-${w_rule}s %-${w_group}s %-${w_status}s %s\n" \
|
||||||
local group_summary=""
|
"NAME" "IP" "TYPE" "RULE" "GROUP" "STATUS" "LAST SEEN"
|
||||||
cmd::list::_build_group_summary
|
printf " %s\n" "$(printf '─%.0s' {1..115})"
|
||||||
printf "\n Showing peers\n\n"
|
|
||||||
|
# Rows
|
||||||
|
while IFS='|' read -r name ip type rule group status last_seen is_blocked is_restricted; do
|
||||||
|
[[ -z "$name" ]] && continue
|
||||||
|
local clean_status
|
||||||
|
clean_status=$(echo "$status" | sed 's/\x1b\[[0-9;]*m//g')
|
||||||
|
local status_pad_n=$(( w_status - ${#clean_status} ))
|
||||||
|
[[ $status_pad_n -lt 0 ]] && status_pad_n=0
|
||||||
|
|
||||||
|
local row_color status_color
|
||||||
|
row_color=$(ui::peer::_row_color "$is_blocked" "$is_restricted" "$clean_status")
|
||||||
|
status_color=$(ui::peer::status_color "$is_blocked" "$is_restricted" "$clean_status")
|
||||||
|
|
||||||
|
local status_colored="${status_color}${clean_status}\033[0m"
|
||||||
|
|
||||||
|
if [[ -n "$row_color" ]]; then
|
||||||
|
printf " %b%-${w_name}s %-${w_ip}s %-${w_type}s %-${w_rule}s %-${w_group}s %-${w_status}s %s\033[0m\n" \
|
||||||
|
"$row_color" "$name" "$ip" "$type" "$rule" "$group" "$clean_status" "$last_seen"
|
||||||
else
|
else
|
||||||
log::wg_warning "No results found"
|
printf " %-${w_name}s %-${w_ip}s %-${w_type}s %-${w_rule}s %-${w_group}s %b%*s\033[0m %s\n" \
|
||||||
|
"$name" "$ip" "$type" "$rule" "$group" \
|
||||||
|
"$status_color${clean_status}" "$status_pad_n" "" "$last_seen"
|
||||||
fi
|
fi
|
||||||
|
done <<< "$rows"
|
||||||
|
|
||||||
|
printf " %s\n" "$(printf '─%.0s' {1..115})"
|
||||||
|
cmd::list::_render_summary_from_rows "$rows"
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmd::list::_iter_confs_table() {
|
function cmd::list::_iter_confs_table() {
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ function ctx::policies() { echo "$_CTX_POLICIES"; }
|
||||||
|
|
||||||
# Config files
|
# Config files
|
||||||
function ctx::config_file() { echo "$_CTX_CONFIG_FILE"; }
|
function ctx::config_file() { echo "$_CTX_CONFIG_FILE"; }
|
||||||
|
function ctx::display() { echo "${_CTX_CONFIG}/display.json"; }
|
||||||
|
|
||||||
# Daemon files
|
# Daemon files
|
||||||
function ctx::events_log() { echo "${_CTX_DAEMON}/events.log"; }
|
function ctx::events_log() { echo "${_CTX_DAEMON}/events.log"; }
|
||||||
|
|
|
||||||
|
|
@ -1611,6 +1611,22 @@ def config_load(file):
|
||||||
print(f"Error: {e}", file=sys.stderr)
|
print(f"Error: {e}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def display_load(file):
|
||||||
|
"""
|
||||||
|
Load display.json and output view=style pairs.
|
||||||
|
Output: view_name=style per line
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(file) as f:
|
||||||
|
d = json.load(f)
|
||||||
|
views = d.get('views', {})
|
||||||
|
for view_name, view_config in views.items():
|
||||||
|
style = view_config.get('style', 'compact')
|
||||||
|
print(f"{view_name}={style}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# ======================================================
|
# ======================================================
|
||||||
|
|
||||||
def _net_read(file):
|
def _net_read(file):
|
||||||
|
|
@ -1981,6 +1997,7 @@ commands = {
|
||||||
'batch_resolve': lambda args: batch_resolve(args[0], args[1], *args[2:]),
|
'batch_resolve': lambda args: batch_resolve(args[0], args[1], *args[2:]),
|
||||||
'peer_history_lookup': lambda args: peer_history_lookup(args[0], args[1]),
|
'peer_history_lookup': lambda args: peer_history_lookup(args[0], args[1]),
|
||||||
'config_load': lambda args: config_load(args[0]),
|
'config_load': lambda args: config_load(args[0]),
|
||||||
|
'display_load': lambda args: display_load(args[0]),
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Main ─────────────────────────────────────────────────────────────────────
|
# ── Main ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"phone-fred": "176.223.61.130",
|
"phone-fred": "176.223.61.130",
|
||||||
"phone-helena": "148.69.46.73",
|
"phone-helena": "148.69.46.73",
|
||||||
"phone-nuno": "148.69.50.62",
|
"phone-nuno": "148.69.48.20",
|
||||||
"tablet-nuno": "148.69.202.5",
|
"tablet-nuno": "148.69.202.5",
|
||||||
"guest-zephyr": "86.120.152.74",
|
"guest-zephyr": "86.120.152.74",
|
||||||
"guest-zephyr-test": "94.63.0.129",
|
"guest-zephyr-test": "94.63.0.129",
|
||||||
"desktop-roboclean": "46.189.215.231",
|
"desktop-roboclean": "46.189.215.231",
|
||||||
"laptop-nuno": "94.63.0.129",
|
"laptop-nuno": "94.63.0.129",
|
||||||
"phone-luis": "176.223.61.15",
|
"phone-luis": "176.223.61.15",
|
||||||
"phone-helena-2": "148.69.203.225",
|
"phone-helena-2": "148.69.202.234",
|
||||||
"desktop-zephyr": "86.120.152.74"
|
"desktop-zephyr": "86.120.152.74"
|
||||||
}
|
}
|
||||||
72
modules/display.module.sh
Normal file
72
modules/display.module.sh
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# modules/display.module.sh
|
||||||
|
# Display configuration — controls layout style per view
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# State — loaded once on first access
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
_DISPLAY_LOADED=false
|
||||||
|
declare -gA _DISPLAY_STYLES=()
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Load display config
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
function display::_load() {
|
||||||
|
$_DISPLAY_LOADED && return 0
|
||||||
|
_DISPLAY_LOADED=true
|
||||||
|
|
||||||
|
local display_file
|
||||||
|
display_file="$(ctx::display)"
|
||||||
|
[[ ! -f "$display_file" ]] && return 0
|
||||||
|
|
||||||
|
# Load styles per view via json_helper
|
||||||
|
local view style
|
||||||
|
while IFS='=' read -r view style; do
|
||||||
|
[[ -n "$view" && -n "$style" ]] && _DISPLAY_STYLES["$view"]="$style"
|
||||||
|
done < <(python3 "$(ctx::json_helper)" display_load "$display_file" 2>/dev/null)
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Accessors
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# display::style <view>
|
||||||
|
# Returns: compact | table | minimal (default: compact)
|
||||||
|
function display::style() {
|
||||||
|
local view="${1:-}"
|
||||||
|
display::_load
|
||||||
|
echo "${_DISPLAY_STYLES[$view]:-compact}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# display::is_compact <view>
|
||||||
|
function display::is_compact() {
|
||||||
|
[[ "$(display::style "$1")" == "compact" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# display::is_table <view>
|
||||||
|
function display::is_table() {
|
||||||
|
[[ "$(display::style "$1")" == "table" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# display::render <view> <data> <compact_fn> <table_fn> [extra_args...]
|
||||||
|
# Generic dispatcher — calls compact or table render function
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
function display::render() {
|
||||||
|
local view="${1:-}" data="${2:-}" compact_fn="${3:-}" table_fn="${4:-}"
|
||||||
|
shift 4 || true
|
||||||
|
|
||||||
|
case "$(display::style "$view")" in
|
||||||
|
table)
|
||||||
|
declare -f "$table_fn" >/dev/null 2>&1 && \
|
||||||
|
"$table_fn" "$data" "$@" || \
|
||||||
|
"$compact_fn" "$data" "$@" # fallback to compact if no table fn
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
"$compact_fn" "$data" "$@"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
1
wgctl
1
wgctl
|
|
@ -11,6 +11,7 @@ LOG_LEVEL=DEBUG
|
||||||
|
|
||||||
load_module ip
|
load_module ip
|
||||||
load_module ui
|
load_module ui
|
||||||
|
load_module display
|
||||||
load_module config
|
load_module config
|
||||||
load_module keys
|
load_module keys
|
||||||
load_module peers
|
load_module peers
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue