feat(tui): add gum dashboard and read-only workflow
This commit is contained in:
+105
-4
@@ -1433,6 +1433,106 @@ resolve_gum() {
|
||||
optional_command gum || { die "$EXIT_DEPENDENCY" 'Не найден gum для TUI'; return $?; }
|
||||
}
|
||||
|
||||
validate_gum_capabilities() {
|
||||
local gum_path=$1 capability
|
||||
local -a capabilities=(style choose filter input confirm table pager spin)
|
||||
for capability in "${capabilities[@]}"; do
|
||||
"$gum_path" "$capability" --help >/dev/null 2>&1 || {
|
||||
die "$EXIT_DEPENDENCY" "gum не поддерживает команду: ${capability}"
|
||||
return $?
|
||||
}
|
||||
done
|
||||
}
|
||||
gum_command() { local gum_path=${TUI_GUM_PATH:-}; [[ -n $gum_path ]] || gum_path=$(resolve_gum) || return $?; "$gum_path" "$@"; }
|
||||
gum_header() { gum_command style --border double --padding '0 1' "$1"; }
|
||||
gum_choose() { gum_command choose "$@"; }
|
||||
gum_filter() { gum_command filter --placeholder 'Выберите клиента' "$@"; }
|
||||
gum_input() { gum_command input "$@"; }
|
||||
gum_confirm() { gum_command confirm "$@"; }
|
||||
gum_table() { gum_command table "$@"; }
|
||||
gum_pager() { gum_command pager "$@"; }
|
||||
gum_spin() { gum_command spin "$@"; }
|
||||
tui_is_terminal() {
|
||||
if [[ ${WG_MANAGER_TEST_TTY+x} && ${WG_MANAGER_TEST_TTY} == both ]] && transaction_test_hooks_enabled; then return 0; fi
|
||||
[[ -t 0 && -t 1 ]]
|
||||
}
|
||||
tui_page_command() {
|
||||
local command_name=$1 output backend_status pager_status
|
||||
shift
|
||||
if output=$("$command_name" "$@" 2>&1); then backend_status=0; else backend_status=$?; fi
|
||||
if printf '%s' "$output" | gum_pager; then pager_status=0; else pager_status=$?; fi
|
||||
((backend_status != 0)) && return "$backend_status"
|
||||
return "$pager_status"
|
||||
}
|
||||
|
||||
tui_select_client() {
|
||||
local choice index label base previous ordinal duplicate
|
||||
local -a choices=() choice_indices=()
|
||||
tui_page_command print_list || return $?
|
||||
for index in "${!CLIENT_KEYS[@]}"; do
|
||||
base="${CLIENT_NAMES[$index]} — ${CLIENT_KEYS[$index]:0:8}"
|
||||
ordinal=1; duplicate=0
|
||||
for previous in "${!CLIENT_KEYS[@]}"; do
|
||||
[[ $previous -ge $index ]] && break
|
||||
if [[ "${CLIENT_NAMES[$previous]} — ${CLIENT_KEYS[$previous]:0:8}" == "$base" ]]; then
|
||||
((ordinal += 1)); duplicate=1
|
||||
fi
|
||||
done
|
||||
for previous in "${!CLIENT_KEYS[@]}"; do
|
||||
((previous > index)) || continue
|
||||
if [[ "${CLIENT_NAMES[$previous]} — ${CLIENT_KEYS[$previous]:0:8}" == "$base" ]]; then duplicate=1; break; fi
|
||||
done
|
||||
if ((duplicate == 1)); then label="${CLIENT_NAMES[$index]:0:60} — ${CLIENT_KEYS[$index]:0:8} #${ordinal}"; else label=$base; fi
|
||||
choices+=("$label")
|
||||
choice_indices+=("$index")
|
||||
done
|
||||
((${#choices[@]} > 0)) || { printf 'Клиенты отсутствуют\n'; return 0; }
|
||||
choice=$(gum_filter "${choices[@]}") || return 0
|
||||
index=-1
|
||||
for previous in "${!choices[@]}"; do
|
||||
if [[ ${choices[$previous]} == "$choice" ]]; then
|
||||
if ((index >= 0)); then return "$EXIT_VALIDATION"; fi
|
||||
index=${choice_indices[$previous]}
|
||||
fi
|
||||
done
|
||||
((index >= 0)) || return "$EXIT_VALIDATION"
|
||||
tui_page_command print_client_details "${CLIENT_NAMES[$index]}" "$index"
|
||||
}
|
||||
|
||||
tui_screen() {
|
||||
local choice failures=0 index managed_count=0 active_count=0 warning_count=0 runtime_text dashboard status
|
||||
local -a menu_labels=('Состояние' 'Клиенты' 'Диагностика' 'Журнал' 'Резервные копии' 'Добавить' 'Удалить' 'Выход')
|
||||
unset TUI_GUM_PATH
|
||||
tui_is_terminal || { die "$EXIT_USAGE" 'TUI требует интерактивный терминал'; return $?; }
|
||||
if TUI_GUM_PATH=$(resolve_gum); then :; else status=$?; unset TUI_GUM_PATH; return "$status"; fi
|
||||
validate_gum_capabilities "$TUI_GUM_PATH" || { unset TUI_GUM_PATH; return $?; }
|
||||
load_client_model || { unset TUI_GUM_PATH; return $?; }
|
||||
for index in "${!CLIENT_ORIGINS[@]}"; do
|
||||
if [[ ${CLIENT_ORIGINS[$index]} == managed ]]; then ((managed_count += 1)); fi
|
||||
if [[ ${CLIENT_STATES[$index]} == active ]]; then ((active_count += 1)); fi
|
||||
done
|
||||
((RUNTIME_AVAILABLE == 1)) || ((warning_count += 1))
|
||||
if ((RUNTIME_AVAILABLE == 1)); then runtime_text='доступен'; else runtime_text='недоступен'; fi
|
||||
while ((failures < 3)); do
|
||||
printf -v dashboard 'WireGuard Manager — %s\nСостояние: %s\nКлиентов: %d Управляемых: %d\nАктивны недавно: %d Предупреждения: %d' "$WG_INTERFACE" "$runtime_text" "${#CLIENT_KEYS[@]}" "$managed_count" "$active_count" "$warning_count"
|
||||
if gum_header "$dashboard"; then :; else status=$?; unset TUI_GUM_PATH; return "$status"; fi
|
||||
if choice=$(gum_choose "${menu_labels[@]}"); then :; else unset TUI_GUM_PATH; return 0; fi
|
||||
case $choice in
|
||||
Состояние) tui_page_command print_status || ((failures += 1)) ;;
|
||||
Клиенты) tui_select_client || ((failures += 1)) ;;
|
||||
Диагностика) tui_page_command diagnose || ((failures += 1)) ;;
|
||||
Журнал) tui_page_command list_audit || ((failures += 1)) ;;
|
||||
'Резервные копии') tui_page_command list_backups || ((failures += 1)) ;;
|
||||
Добавить|Удалить) printf 'Действие «%s» доступно через CLI в M9; изменения не выполняются.\n' "$choice" ;;
|
||||
Выход|'') unset TUI_GUM_PATH; return 0 ;;
|
||||
*) printf 'Неизвестный пункт TUI\n' >&2; ((failures += 1)) ;;
|
||||
esac
|
||||
done
|
||||
unset TUI_GUM_PATH
|
||||
die "$EXIT_OPERATION" 'TUI завершён после повторных ошибок'
|
||||
return $?
|
||||
}
|
||||
|
||||
print_version() { printf 'WireGuard Manager %s\n' "$WG_MANAGER_VERSION"; }
|
||||
run_placeholder() { load_config || return $?; die "$EXIT_OPERATION" "Команда «$1» пока не реализована"; }
|
||||
manual_backup() {
|
||||
@@ -2262,9 +2362,9 @@ remove_client() {
|
||||
main() {
|
||||
local status
|
||||
if (( $# == 0 )); then
|
||||
if die "$EXIT_USAGE" 'Ожидается команда'; then status=0; else status=$?; fi
|
||||
print_usage >&2
|
||||
return "$status"
|
||||
load_config || return $?
|
||||
tui_screen
|
||||
return $?
|
||||
fi
|
||||
if [[ $1 == add ]]; then
|
||||
shift
|
||||
@@ -2323,7 +2423,8 @@ main() {
|
||||
remove_client "$@" ;;
|
||||
backup) manual_backup ;;
|
||||
backups) list_backups ;;
|
||||
logs|tui) run_placeholder "$1" ;;
|
||||
tui) (($# == 1)) || { die "$EXIT_USAGE" 'Команда tui не принимает аргументы'; return $?; }; load_config || return $?; tui_screen ;;
|
||||
logs) run_placeholder "$1" ;;
|
||||
*)
|
||||
if die "$EXIT_USAGE" "неизвестная команда: $1"; then status=0; else status=$?; fi
|
||||
print_usage >&2
|
||||
|
||||
Reference in New Issue
Block a user