mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-06-15 04:47:00 +00:00
Update 1.2.2.2 beta
This commit is contained in:
@@ -271,7 +271,7 @@ export function Login({ onLogin }: LoginProps) {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-center text-sm text-muted-foreground">ProxMenux Monitor v1.2.2.1-beta</p>
|
<p className="text-center text-sm text-muted-foreground">ProxMenux Monitor v1.2.2.2-beta</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -836,7 +836,7 @@ export function ProxmoxDashboard() {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<footer className="mt-8 md:mt-12 pt-4 md:pt-6 border-t border-border text-center text-xs md:text-sm text-muted-foreground">
|
<footer className="mt-8 md:mt-12 pt-4 md:pt-6 border-t border-border text-center text-xs md:text-sm text-muted-foreground">
|
||||||
<p className="font-medium mb-2">ProxMenux Monitor v1.2.2.1-beta</p>
|
<p className="font-medium mb-2">ProxMenux Monitor v1.2.2.2-beta</p>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
href="https://ko-fi.com/macrimi"
|
href="https://ko-fi.com/macrimi"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Dialog, DialogContent, DialogTitle } from "./ui/dialog"
|
|||||||
import { X, Sparkles, Thermometer, Activity, HardDrive, Shield, Globe, Cpu, Zap, Sliders, Wrench, RefreshCw, Server, BellOff, Bell } from "lucide-react"
|
import { X, Sparkles, Thermometer, Activity, HardDrive, Shield, Globe, Cpu, Zap, Sliders, Wrench, RefreshCw, Server, BellOff, Bell } from "lucide-react"
|
||||||
import { Checkbox } from "./ui/checkbox"
|
import { Checkbox } from "./ui/checkbox"
|
||||||
|
|
||||||
const APP_VERSION = "1.2.2.1-beta" // Sync with AppImage/package.json
|
const APP_VERSION = "1.2.2.2-beta" // Sync with AppImage/package.json
|
||||||
|
|
||||||
interface ReleaseNote {
|
interface ReleaseNote {
|
||||||
date: string
|
date: string
|
||||||
|
|||||||
@@ -3737,7 +3737,7 @@ ${observationsHtml}
|
|||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<div class="rpt-footer">
|
<div class="rpt-footer">
|
||||||
<div>Report generated by ProxMenux Monitor</div>
|
<div>Report generated by ProxMenux Monitor</div>
|
||||||
<div>ProxMenux Monitor v1.2.2.1-beta</div>
|
<div>ProxMenux Monitor v1.2.2.2-beta</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ _bk_local() {
|
|||||||
|
|
||||||
hb_require_cmd rsync rsync || return 1
|
hb_require_cmd rsync rsync || return 1
|
||||||
|
|
||||||
dest_dir=$(hb_prompt_dest_dir) || return 1
|
dest_dir=$(hb_select_local_target) || return 1
|
||||||
hb_select_profile_paths "$profile_mode" paths || return 1
|
hb_select_profile_paths "$profile_mode" paths || return 1
|
||||||
|
|
||||||
# Safety check: if the destination directory is INSIDE any selected
|
# Safety check: if the destination directory is INSIDE any selected
|
||||||
@@ -416,53 +416,127 @@ _bk_scheduler() {
|
|||||||
|
|
||||||
_bk_manage_local_destinations() {
|
_bk_manage_local_destinations() {
|
||||||
while true; do
|
while true; do
|
||||||
# Snapshot all currently mounted USB backup partitions with size info
|
# Single configured target (or none → caller falls back to default)
|
||||||
local -a usb_mp=()
|
local current=""
|
||||||
local -a usb_desc=()
|
current=$(hb_get_local_target 2>/dev/null) || current=""
|
||||||
local state path_or_dev label size fstype uuid
|
|
||||||
while IFS=$'\t' read -r state path_or_dev label size fstype uuid; do
|
|
||||||
[[ "$state" != "mounted" ]] && continue
|
|
||||||
local dfline
|
|
||||||
dfline=$(df -h "$path_or_dev" 2>/dev/null | tail -1)
|
|
||||||
local used="?" avail="?" pct="?"
|
|
||||||
if [[ -n "$dfline" ]]; then
|
|
||||||
used=$(awk '{print $3}' <<<"$dfline")
|
|
||||||
avail=$(awk '{print $4}' <<<"$dfline")
|
|
||||||
pct=$(awk '{print $5}' <<<"$dfline")
|
|
||||||
fi
|
|
||||||
usb_mp+=("$path_or_dev")
|
|
||||||
usb_desc+=("${label:-?} [${fstype}] $size → $path_or_dev ($used $(translate "used"), $avail $(translate "free"), $pct)")
|
|
||||||
done < <(hb_list_usb_partitions)
|
|
||||||
|
|
||||||
local body=""
|
local body=""
|
||||||
if (( ${#usb_desc[@]} == 0 )); then
|
if [[ -n "$current" ]]; then
|
||||||
body+="$(translate "No USB drives are currently mounted by ProxMenux.")"
|
body+="\Zb$(translate "Currently configured target:")\ZB"$'\n'
|
||||||
|
body+=" \Z4${current}\Zn"
|
||||||
else
|
else
|
||||||
body+="\Zb$(translate "Mounted USB drives:")\ZB"$'\n'
|
body+="$(translate "No target configured.")"$'\n'
|
||||||
local d
|
body+="$(translate "Default will be used:") \Z4${HB_LOCAL_TARGET_DEFAULT}\Zn"
|
||||||
for d in "${usb_desc[@]}"; do
|
|
||||||
body+=" • ${d}"$'\n'
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
body+=$'\n'"$(translate "Local destinations are file paths — they are NOT registered as Proxmox storage.")"
|
|
||||||
|
|
||||||
local -a menu_args=()
|
local -a menu_args=()
|
||||||
menu_args+=("mount" "+ $(translate "Mount a USB drive now")")
|
menu_args+=("default" "1 $(translate "Use default") (${HB_LOCAL_TARGET_DEFAULT})")
|
||||||
if (( ${#usb_mp[@]} > 0 )); then
|
menu_args+=("custom" "2 $(translate "Use a custom path")")
|
||||||
menu_args+=("unmount" "− $(translate "Unmount a USB drive")")
|
menu_args+=("usb" "3 $(translate "Use a USB disk")")
|
||||||
|
if [[ -n "$current" ]]; then
|
||||||
|
menu_args+=("clear" "C $(translate "Clear configured target")")
|
||||||
fi
|
fi
|
||||||
menu_args+=("back" "$(translate "← Return")")
|
menu_args+=("back" "$(translate "← Return")")
|
||||||
|
|
||||||
local choice
|
local choice
|
||||||
choice=$(dialog --backtitle "ProxMenux" --colors \
|
choice=$(dialog --backtitle "ProxMenux" --colors \
|
||||||
--title "$(translate "Local archive destinations")" \
|
--title "$(translate "Manage local backup target")" \
|
||||||
--menu "\n${body}\n" \
|
--menu "\n${body}\n" \
|
||||||
"$HB_UI_MENU_H" "$HB_UI_MENU_W" "$HB_UI_MENU_LIST" "${menu_args[@]}" \
|
"$HB_UI_MENU_H" "$HB_UI_MENU_W" "$HB_UI_MENU_LIST" "${menu_args[@]}" \
|
||||||
3>&1 1>&2 2>&3) || break
|
3>&1 1>&2 2>&3) || break
|
||||||
|
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
|
default)
|
||||||
|
hb_set_local_target "$HB_LOCAL_TARGET_DEFAULT"
|
||||||
|
;;
|
||||||
|
custom)
|
||||||
|
local new_path
|
||||||
|
new_path=$(dialog --backtitle "ProxMenux" \
|
||||||
|
--title "$(translate "Custom path")" \
|
||||||
|
--inputbox "$(translate "Absolute directory path to use as backup target:")" \
|
||||||
|
"$HB_UI_INPUT_H" "$HB_UI_INPUT_W" "/backup" \
|
||||||
|
3>&1 1>&2 2>&3) || continue
|
||||||
|
new_path=$(hb_trim_dialog_value "$new_path")
|
||||||
|
[[ -z "$new_path" ]] && continue
|
||||||
|
mkdir -p "$new_path" 2>/dev/null || {
|
||||||
|
dialog --backtitle "ProxMenux" --msgbox \
|
||||||
|
"$(translate "Cannot create:") $new_path" 8 60
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hb_set_local_target "$new_path"
|
||||||
|
;;
|
||||||
|
usb)
|
||||||
|
_bk_local_target_usb_submenu
|
||||||
|
;;
|
||||||
|
clear)
|
||||||
|
hb_clear_local_target
|
||||||
|
;;
|
||||||
|
back) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Submenu reached when the user picks "Use a USB disk" in the local
|
||||||
|
# target manager. Lists mounted USB partitions so the operator can pick
|
||||||
|
# one as the target; mount / unmount are auxiliary actions for preparing
|
||||||
|
# a fresh disk or releasing one. Picking a USB sets it as the configured
|
||||||
|
# target and returns to the parent menu.
|
||||||
|
_bk_local_target_usb_submenu() {
|
||||||
|
while true; do
|
||||||
|
local -a usb_mp=()
|
||||||
|
local -a usb_desc=()
|
||||||
|
local state path_or_dev label size fstype uuid
|
||||||
|
while IFS=$'\t' read -r state path_or_dev label size fstype uuid; do
|
||||||
|
[[ "$state" != "mounted" ]] && continue
|
||||||
|
usb_mp+=("$path_or_dev")
|
||||||
|
usb_desc+=("${label:-?} [${fstype}] $size → $path_or_dev")
|
||||||
|
done < <(hb_list_usb_partitions)
|
||||||
|
|
||||||
|
local body=""
|
||||||
|
if (( ${#usb_mp[@]} > 0 )); then
|
||||||
|
body+="\Zb$(translate "USB drives mounted now:")\ZB"$'\n'
|
||||||
|
local d
|
||||||
|
for d in "${usb_desc[@]}"; do
|
||||||
|
body+=" • ${d}"$'\n'
|
||||||
|
done
|
||||||
|
else
|
||||||
|
body+="$(translate "No USB drives mounted by ProxMenux yet. Mount one first to use it as a target.")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local -a menu_args=()
|
||||||
|
if (( ${#usb_mp[@]} > 0 )); then
|
||||||
|
menu_args+=("pick" "$(translate "Pick a mounted USB as target")")
|
||||||
|
fi
|
||||||
|
menu_args+=("mount" "⊕ $(translate "Mount a USB drive now")")
|
||||||
|
if (( ${#usb_mp[@]} > 0 )); then
|
||||||
|
menu_args+=("unmount" "⊖ $(translate "Unmount a USB drive")")
|
||||||
|
fi
|
||||||
|
menu_args+=("back" "$(translate "← Return")")
|
||||||
|
|
||||||
|
local choice
|
||||||
|
choice=$(dialog --backtitle "ProxMenux" --colors \
|
||||||
|
--title "$(translate "USB disk target")" \
|
||||||
|
--menu "\n${body}\n" \
|
||||||
|
"$HB_UI_MENU_H" "$HB_UI_MENU_W" "$HB_UI_MENU_LIST" "${menu_args[@]}" \
|
||||||
|
3>&1 1>&2 2>&3) || break
|
||||||
|
|
||||||
|
case "$choice" in
|
||||||
|
pick)
|
||||||
|
local pick_menu=() i=1 idx
|
||||||
|
for idx in "${!usb_mp[@]}"; do
|
||||||
|
pick_menu+=("$i" "${usb_desc[$idx]}"); ((i++))
|
||||||
|
done
|
||||||
|
local pick
|
||||||
|
pick=$(dialog --backtitle "ProxMenux" \
|
||||||
|
--title "$(translate "Pick USB target")" \
|
||||||
|
--menu "\n$(translate "Select the mounted USB to use as backup target:")" \
|
||||||
|
"$HB_UI_MENU_H" "$HB_UI_MENU_W" "$HB_UI_MENU_LIST" "${pick_menu[@]}" \
|
||||||
|
3>&1 1>&2 2>&3) || continue
|
||||||
|
hb_set_local_target "${usb_mp[$((pick-1))]}"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
mount)
|
mount)
|
||||||
# Reuse the runtime USB picker; result is discarded.
|
# Auxiliary: prepare a USB so it can be picked next pass.
|
||||||
hb_prompt_mounted_path "/mnt/backup" >/dev/null || true
|
hb_prompt_mounted_path "/mnt/backup" >/dev/null || true
|
||||||
;;
|
;;
|
||||||
unmount)
|
unmount)
|
||||||
@@ -506,7 +580,7 @@ _bk_manage_destinations() {
|
|||||||
"$HB_UI_MENU_H" "$HB_UI_MENU_W" "$HB_UI_MENU_LIST" \
|
"$HB_UI_MENU_H" "$HB_UI_MENU_W" "$HB_UI_MENU_LIST" \
|
||||||
1 "$(translate "Proxmox Backup Server (PBS) destinations")" \
|
1 "$(translate "Proxmox Backup Server (PBS) destinations")" \
|
||||||
2 "$(translate "Borg repositories")" \
|
2 "$(translate "Borg repositories")" \
|
||||||
3 "$(translate "Local archive destinations (mounted USBs, mount, unmount)")" \
|
3 "$(translate "Local archive targets (paths + USB mount/unmount)")" \
|
||||||
0 "$(translate "Return")" \
|
0 "$(translate "Return")" \
|
||||||
3>&1 1>&2 2>&3) || break
|
3>&1 1>&2 2>&3) || break
|
||||||
|
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ _create_job() {
|
|||||||
case "$backend" in
|
case "$backend" in
|
||||||
local)
|
local)
|
||||||
local dest_dir ext
|
local dest_dir ext
|
||||||
dest_dir=$(hb_prompt_dest_dir) || return 1
|
dest_dir=$(hb_select_local_target) || return 1
|
||||||
ext=$(dialog --backtitle "ProxMenux" --title "$(translate "Archive format")" \
|
ext=$(dialog --backtitle "ProxMenux" --title "$(translate "Archive format")" \
|
||||||
--menu "\n$(translate "Select local archive format:")" 12 62 4 \
|
--menu "\n$(translate "Select local archive format:")" 12 62 4 \
|
||||||
"tar.zst" "tar + zstd (preferred)" \
|
"tar.zst" "tar + zstd (preferred)" \
|
||||||
|
|||||||
@@ -1998,7 +1998,63 @@ hb_format_usb_disk() {
|
|||||||
printf '%s' "$mp"
|
printf '%s' "$mp"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Local backup target: single configured value (no list) ──
|
||||||
|
#
|
||||||
|
# Only ONE local target is active at a time. Persisted as a single line in
|
||||||
|
# $HB_STATE_DIR/local-target.conf. If the file is absent, callers default
|
||||||
|
# to HB_LOCAL_TARGET_DEFAULT (/var/lib/vz/dump).
|
||||||
|
|
||||||
|
HB_LOCAL_TARGET_DEFAULT="/var/lib/vz/dump"
|
||||||
|
|
||||||
|
# Echoes the configured target path. Returns 1 if none configured (caller
|
||||||
|
# may default to HB_LOCAL_TARGET_DEFAULT).
|
||||||
|
hb_get_local_target() {
|
||||||
|
local cfg="$HB_STATE_DIR/local-target.conf"
|
||||||
|
[[ -f "$cfg" ]] || return 1
|
||||||
|
local path
|
||||||
|
path=$(head -1 "$cfg" 2>/dev/null | tr -d '\r\n')
|
||||||
|
[[ -z "$path" ]] && return 1
|
||||||
|
echo "$path"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_set_local_target() {
|
||||||
|
local path="$1"
|
||||||
|
[[ -z "$path" ]] && return 1
|
||||||
|
path="${path%/}"
|
||||||
|
mkdir -p "$HB_STATE_DIR"
|
||||||
|
local cfg="$HB_STATE_DIR/local-target.conf"
|
||||||
|
printf '%s\n' "$path" > "$cfg"
|
||||||
|
chmod 600 "$cfg"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_clear_local_target() {
|
||||||
|
rm -f "$HB_STATE_DIR/local-target.conf"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Always returns a usable path. If nothing is configured, falls back to
|
||||||
|
# the default. Callers do NOT prompt — the user pre-configures the target
|
||||||
|
# in "Manage local backup target".
|
||||||
|
hb_select_local_target() {
|
||||||
|
local path
|
||||||
|
if path=$(hb_get_local_target); then
|
||||||
|
echo "$path"
|
||||||
|
else
|
||||||
|
echo "$HB_LOCAL_TARGET_DEFAULT"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
hb_prompt_mounted_path() {
|
hb_prompt_mounted_path() {
|
||||||
|
# `dialog --yesno` / `dialog --msgbox` write their TUI to stdout by
|
||||||
|
# convention. When this function is called as `mnt=$(hb_prompt_mounted_path)`
|
||||||
|
# the subshell captures every TUI escape into $mnt and corrupts the
|
||||||
|
# caller (saw it as garbage in borg-targets.txt). Stash real stdout in
|
||||||
|
# fd 9, redirect stdout to the TTY for the body, and emit the actual
|
||||||
|
# return value through fd 9.
|
||||||
|
exec 9>&1 >/dev/tty
|
||||||
|
|
||||||
local default_path="${1:-/mnt/backup}"
|
local default_path="${1:-/mnt/backup}"
|
||||||
|
|
||||||
local -a menu=()
|
local -a menu=()
|
||||||
@@ -2038,7 +2094,7 @@ hb_prompt_mounted_path() {
|
|||||||
--yesno "$(hb_translate "This path is not a registered mount point. Use it anyway?")" \
|
--yesno "$(hb_translate "This path is not a registered mount point. Use it anyway?")" \
|
||||||
"$HB_UI_YESNO_H" "$HB_UI_YESNO_W" || return 1
|
"$HB_UI_YESNO_H" "$HB_UI_YESNO_W" || return 1
|
||||||
fi
|
fi
|
||||||
echo "$out"
|
echo "$out" >&9
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -2054,7 +2110,7 @@ hb_prompt_mounted_path() {
|
|||||||
|
|
||||||
case "$s_state" in
|
case "$s_state" in
|
||||||
mounted)
|
mounted)
|
||||||
echo "$s_path"
|
echo "$s_path" >&9
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@@ -2078,7 +2134,7 @@ hb_prompt_mounted_path() {
|
|||||||
# The wizard prints the destination path right after, so go
|
# The wizard prints the destination path right after, so go
|
||||||
# straight to the backup flow instead of asking for an extra
|
# straight to the backup flow instead of asking for an extra
|
||||||
# confirmation click on a "mounted OK" dialog.
|
# confirmation click on a "mounted OK" dialog.
|
||||||
echo "$mounted_at"
|
echo "$mounted_at" >&9
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@@ -2116,7 +2172,7 @@ hb_prompt_mounted_path() {
|
|||||||
dialog --backtitle "ProxMenux" --colors \
|
dialog --backtitle "ProxMenux" --colors \
|
||||||
--title "$(hb_translate "Formatted and mounted")" \
|
--title "$(hb_translate "Formatted and mounted")" \
|
||||||
--msgbox "\Zb$(hb_translate "Mounted at")\ZB \Z4${mounted_at}\Zn" 8 70
|
--msgbox "\Zb$(hb_translate "Mounted at")\ZB \Z4${mounted_at}\Zn" 8 70
|
||||||
echo "$mounted_at"
|
echo "$mounted_at" >&9
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Reference in New Issue
Block a user