Files
gniza4linux/lib/ui_targets.sh
shuki a956bd9e30 Fix gum file browser returning relative paths
gum file returns paths relative to the start directory.
Prepend / to ensure absolute paths for backup targets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:29:30 +02:00

189 lines
6.1 KiB
Bash

#!/usr/bin/env bash
# gniza4linux/lib/ui_targets.sh — Target management TUI
[[ -n "${_GNIZA4LINUX_UI_TARGETS_LOADED:-}" ]] && return 0
_GNIZA4LINUX_UI_TARGETS_LOADED=1
ui_targets_menu() {
while true; do
local -a items=()
local targets
targets=$(list_targets)
if [[ -n "$targets" ]]; then
while IFS= read -r t; do
items+=("$t" "Target: $t")
done <<< "$targets"
fi
items+=("ADD" "Add new target")
items+=("BACK" "Return to main menu")
local choice
choice=$(ui_menu "Targets" "${items[@]}") || return 0
case "$choice" in
ADD) ui_target_add ;;
BACK) return 0 ;;
*)
local action
action=$(ui_menu "Target: $choice" \
"EDIT" "Edit target" \
"DELETE" "Delete target" \
"BACK" "Back") || continue
case "$action" in
EDIT) ui_target_edit "$choice" ;;
DELETE) ui_target_delete "$choice" ;;
BACK) continue ;;
esac
;;
esac
done
}
ui_target_add() {
local name
name=$(ui_inputbox "Add Target" "Enter target name (letters, digits, _ -):" "") || return 0
[[ -z "$name" ]] && return 0
if ! validate_target_name "$name" 2>/dev/null; then
ui_msgbox "Invalid target name. Must start with a letter and contain only letters, digits, underscore, or hyphen (max 32 chars)."
return 0
fi
if [[ -f "$CONFIG_DIR/targets.d/${name}.conf" ]]; then
ui_msgbox "Target '$name' already exists."
return 0
fi
local folders
folders=$(ui_target_folder_picker) || return 0
[[ -z "$folders" ]] && { ui_msgbox "No folders selected. Target not created."; return 0; }
local exclude
exclude=$(ui_inputbox "Add Target" "Exclude patterns (comma-separated, e.g. *.log,*.tmp):" "") || exclude=""
local remote
remote=$(ui_inputbox "Add Target" "Remote override (leave empty for default):" "") || remote=""
create_target "$name" "$folders" "$exclude" "$remote"
ui_msgbox "Target '$name' created successfully."
}
ui_target_edit() {
local name="$1"
load_target "$name" || { ui_msgbox "Failed to load target '$name'."; return 0; }
while true; do
local choice
choice=$(ui_menu "Edit Target: $name" \
"FOLDERS" "Folders: ${TARGET_FOLDERS}" \
"EXCLUDE" "Exclude: ${TARGET_EXCLUDE:-none}" \
"REMOTE" "Remote: ${TARGET_REMOTE:-default}" \
"ENABLED" "Enabled: ${TARGET_ENABLED}" \
"SAVE" "Save and return" \
"BACK" "Cancel") || return 0
case "$choice" in
FOLDERS)
local folders
folders=$(ui_target_folder_picker "$TARGET_FOLDERS") || continue
[[ -n "$folders" ]] && TARGET_FOLDERS="$folders"
;;
EXCLUDE)
local exclude
exclude=$(ui_inputbox "Edit Exclude" "Exclude patterns (comma-separated):" "$TARGET_EXCLUDE") || continue
TARGET_EXCLUDE="$exclude"
;;
REMOTE)
local remote
remote=$(ui_inputbox "Edit Remote" "Remote override (leave empty for default):" "$TARGET_REMOTE") || continue
TARGET_REMOTE="$remote"
;;
ENABLED)
if ui_yesno "Enable this target?"; then
TARGET_ENABLED="yes"
else
TARGET_ENABLED="no"
fi
;;
SAVE)
create_target "$name" "$TARGET_FOLDERS" "$TARGET_EXCLUDE" "$TARGET_REMOTE" \
"$TARGET_RETENTION" "$TARGET_PRE_HOOK" "$TARGET_POST_HOOK" "$TARGET_ENABLED"
ui_msgbox "Target '$name' saved."
return 0
;;
BACK) return 0 ;;
esac
done
}
ui_target_delete() {
local name="$1"
if ui_yesno "Delete target '$name'? This cannot be undone."; then
delete_target "$name"
ui_msgbox "Target '$name' deleted."
fi
}
ui_target_folder_picker() {
local existing="${1:-}"
local -a folders=()
if [[ -n "$existing" ]]; then
IFS=',' read -ra folders <<< "$existing"
fi
while true; do
local -a items=()
local i=1
for f in "${folders[@]}"; do
items+=("$i" "$f")
((i++))
done
items+=("ADD" "Browse & add folder")
[[ ${#folders[@]} -gt 0 ]] && items+=("REMOVE" "Remove folder")
items+=("DONE" "Finish selection")
local choice
choice=$(ui_menu "Folder Picker (${#folders[@]} selected)" "${items[@]}") || return 1
case "$choice" in
ADD)
local path
path=$(gum file --directory --header "Select folder to back up" \
--cursor.foreground "$_GUM_ACCENT" --height 15 /) || continue
[[ -z "$path" ]] && continue
# gum file returns path relative to start dir — make absolute
[[ "$path" != /* ]] && path="/$path"
# Avoid duplicates
local dup=false
for f in "${folders[@]}"; do
[[ "$f" == "$path" ]] && dup=true
done
if $dup; then
ui_msgbox "Folder '$path' is already selected."
else
folders+=("$path")
fi
;;
REMOVE)
local -a rm_items=()
local j=0
for f in "${folders[@]}"; do
rm_items+=("$j" "$f")
((j++))
done
local idx
idx=$(ui_menu "Remove Folder" "${rm_items[@]}") || continue
unset 'folders[idx]'
folders=("${folders[@]}")
;;
DONE)
local result
result=$(IFS=','; echo "${folders[*]}")
echo "$result"
return 0
;;
esac
done
}