Commit Graph

124 Commits

Author SHA1 Message Date
shuki
09b7dd184e Replace all Target/Remote terminology with Source/Destination and add search to file browsers
- Rename all user-facing strings: Target→Source, Remote→Destination across TUI, docs, web dashboard, bash scripts, config examples, and README
- Add go-to-path search input to both FolderPicker and RemoteFolderPicker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:31:35 +02:00
shuki
9be7226a35 Rename Targets/Remotes to Sources/Destinations, add Browse to remote editor, fix RichLog crash and crontab sync
- Rename Targets → Sources, Remotes → Destinations across all screens
- Reorganize main menu with logical groupings and separators
- Add Browse button to Base path field in remote editor (local + SSH)
- Fix RichLog IndexError crash when compositor renders with y=-1
- Fix _sync_crontab accidentally wiping crontab via premature remove
- Per-target locking and auto-create local remote base directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:17:04 +02:00
shuki
fb508d9e0b Add remote folder browser for SSH source targets
Browse button now opens an SSH directory tree picker when source type is
SSH, using the configured credentials. Folders input and Browse button
placed on same row so they're visible without scrolling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:32:30 +02:00
shuki
04a0c45abc Add rsync auto-retry on partial transfer and show running tasks in header
Rsync exit 23 (partial transfer) now triggers an automatic retry to recover
failed files before accepting with a warning. Also adds a task counter next
to the clock in the header bar showing running job count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:26:13 +02:00
shuki
fec13135ce Add source targets, docs panel, tail-style log viewer, and various improvements
- Add source.sh for remote source backup support
- Add responsive DocsPanel with layout adaptations for narrow screens
- Running tasks log viewer now shows last 100 lines (tail -f style)
- Add incremental backup explanation to README
- Update backup, transfer, schedule, and snaplog modules
- Add MCP config and logo asset

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:06:39 +02:00
shuki
eca08483e4 Move docs panel layout logic into DocsPanel.on_mount
The app-level on_resize/on_screen_resume didn't fire on initial
screen push. Now DocsPanel handles its own responsive layout
via on_mount and on_resize, ensuring it works immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:31:21 +02:00
shuki
b578d2f9a6 Fix docs panel on mobile: lower hide threshold to 45 cols
The auto-hide threshold (100 cols) was hiding the panel before
the vertical layout logic could apply. Now:
- >= 80 cols: panel on the right (horizontal)
- 45-79 cols: panel at the bottom (vertical, max 40% height)
- < 45 cols: panel hidden

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:30:26 +02:00
shuki
3526a2b71a Move docs panel to bottom on narrow screens (<80 cols)
On mobile/narrow terminals the .screen-with-docs container
switches from horizontal to vertical layout, placing the
help panel below the main content instead of beside it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:28:38 +02:00
shuki
2b6a58f9df Fix touch scroll: dispatch wheel events to xterm canvas for page scrolling
Target the xterm canvas element with WheelEvent including proper
clientX/clientY coordinates so xterm.js forwards scroll events to
the Textual app for container-level scrolling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:22:24 +02:00
shuki
3b605807cd Fix touch scrolling: dispatch arrow key events to xterm textarea
WheelEvent approach didn't work. Now dispatches ArrowUp/ArrowDown
KeyboardEvents to the xterm helper textarea, which xterm forwards
to the Textual app as actual key presses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:20:53 +02:00
shuki
d2615ab4d2 Add touch-to-scroll support for mobile web view
Translate touch swipe gestures into wheel events dispatched to
the xterm terminal, enabling scrolling on touch devices.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:17:42 +02:00
shuki
0ad929a4b6 Fix main menu scroll on mobile: align top and enable overflow
When in vertical layout (narrow screens), align content to top
and enable vertical scrolling so the menu list isn't cut off.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:15:23 +02:00
shuki
af150f912d Increase mobile web font size: target 50 cols instead of 80
At 320px viewport this gives 10px font instead of 6px,
making the TUI readable on phones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:11:13 +02:00
shuki
3292575233 Make main menu responsive: vertical layout on narrow screens
- Below 100 cols: stack logo on top, menu below (vertical)
- Below 48 cols (~290px): hide logo entirely, show only menu
- 100+ cols: original side-by-side horizontal layout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:08:15 +02:00
shuki
139ea3149c Add mobile-responsive web template, gniza uninstall command, fix web commands for user mode
- Custom textual-serve template with viewport meta tag, full-viewport
  terminal sizing, and auto font-size for mobile (<768px)
- Fix web install-service/remove-service/status to handle user-mode
  systemd (systemctl --user) alongside root mode
- Add 'gniza uninstall' command that runs the uninstall script

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:58:57 +02:00
shuki
ef80c6f19e Fix web dashboard: exempt static assets from auth, fix user-mode uninstall
- Auth middleware now skips /static/ paths and WebSocket upgrades,
  fixing the blank splash screen (xterm.css and textual.js were 401'd)
- Uninstall script now properly stops and removes the user systemd
  service (~/.config/systemd/user/gniza-web.service) in user mode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:50:43 +02:00
shuki
3ebf692b36 Make TUI responsive to terminal size
- Auto-hide docs panel when terminal < 100 cols, respects manual F1 toggle
- Hide logo on main menu when terminal < 80 cols
- DataTable: flexible height (auto with min/max) instead of fixed 12
- Dialogs, pickers, wizard: percentage-based widths with max-width caps
- Menu list: flexible height and width constraints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:44:23 +02:00
shuki
5ea4bea00a Fix docs panel text wrapping: remove hardcoded line breaks
Let Rich handle word wrapping naturally instead of breaking lines
at fixed widths, which caused mid-word cuts in narrow panels.
Also use NoMatches instead of bare Exception in toggle handler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:41:36 +02:00
shuki
b28146529e Add contextual Help panel to all TUI screens (F1 toggle)
Split each screen into two columns: existing controls on the left,
a DocsPanel with Rich-markup documentation on the right (30% width).
Press F1 to toggle the help panel on/off from any screen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:38:47 +02:00
shuki
040f861096 Fix progress bar stuck: split on \r to get latest rsync progress
rsync --info=progress2 uses \r without \n, so the entire progress
stream is one long line. Split on both \r and \n to parse each
progress update independently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:57:17 +02:00
shuki
0ea7d10a9c Add rsync progress bar to Running Tasks screen
- Add --info=progress2 --no-inc-recursive to rsync for overall progress
- Parse rsync progress output (percentage, speed, ETA) from log file
- Show ProgressBar widget and progress label below buttons
- Progress bar auto-hides when job finishes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:55:02 +02:00
shuki
666f1bd52a Fix View Log job lookup: extract RowKey.value
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:51:10 +02:00
shuki
fdf2f0b10a Show job log inline below running tasks table
View Log now displays the log in a RichLog panel below the buttons
instead of opening a modal screen. The log tails the file in real-time
with a 0.3s poll interval while the job is running.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:47:49 +02:00
shuki
83ccf44117 Fix live log not updating: tail log file directly in OperationLog
The poll timer was reading from job.output in memory, which depended on
run_job's async task populating it. Now OperationLog reads new content
directly from the log file using seek, making it independent of the
async task. Also store the asyncio task reference to prevent GC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:40:56 +02:00
shuki
d60c2f06aa Add Status column to Logs screen
Detects status from log content: Success (backup completed, no errors),
Failed (ERROR/FATAL markers), OK (lock released), Interrupted (no clean exit).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:34:42 +02:00
shuki
ad65a376fd Use subprocess.Popen for background jobs to survive TUI exit
asyncio's SubprocessTransport sends SIGKILL to child processes during
event loop cleanup, killing the gniza bash wrapper when the TUI exits.
Switch to subprocess.Popen which has no such cleanup behavior, allowing
backup jobs to continue running after the TUI is closed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:28:32 +02:00
shuki
ae1563396c Fix WORK_DIR override: config file was clobbering detect_mode
The settings screen wrote WORK_DIR="/usr/local/gniza/workdir" (root-mode
path) into gniza.conf. load_config then overrode the correct user-mode
path set by detect_mode, causing mktemp and rsync log redirects to fail
with Permission denied — crashing the bash script while rsync continued
as an orphan.

- Remove WORK_DIR from AppSettings model and settings screen
- Re-run detect_mode after config load to restore correct paths
- Removed stale WORK_DIR from user's gniza.conf

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:14:14 +02:00
shuki
58819abcd4 Persist finished jobs in registry and fix reconnection bugs
- Save finished jobs to registry (24h TTL) so they survive TUI restart
- Fix PermissionError in PID check incorrectly marking alive processes as dead
- Handle CancelledError explicitly to preserve running status on TUI exit
- Tail log files for reconnected running jobs instead of showing stale output
- Detect actual return code from log content; show "?" for unknown status

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:06:48 +02:00
shuki
8fec087987 Write job output to file instead of pipe to survive TUI exit
The subprocess stdout was a pipe to the TUI. When the TUI exited, the
pipe broke (SIGPIPE) and killed the backup process. Now the subprocess
writes to a log file in WORK_DIR, and the TUI tails it for live
display. When the TUI exits, the subprocess keeps running because it
writes to a file, not a pipe. On restart, the log file is loaded to
show output for reconnected or finished background jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:50:09 +02:00
shuki
a08cf9911c Show background jobs that finished while TUI was closed
Previously _load_registry silently dropped dead PIDs, so jobs that
completed in the background were invisible on restart. Now dead PIDs
are loaded as 'success' status so the user sees they completed. The
registry is cleaned up after loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:46:47 +02:00
shuki
0de0f7783a Don't kill running jobs on TUI exit
Previously action_quit() killed all running jobs before exiting,
making it impossible to reconnect to them on restart. Now shows a
confirmation dialog when jobs are running and lets them continue
in the background.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:38:03 +02:00
shuki
ba93a74f8e Persist running jobs to registry for TUI reconnection
Jobs are now saved to gniza-jobs.json in WORK_DIR when they start and
finish. On TUI restart, the registry is loaded and PIDs are checked —
still-running jobs appear in the Running Tasks screen and can be
killed. Reconnected jobs are polled every second to detect completion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:27:37 +02:00
shuki
92828ab891 Debug: show row key and job IDs when kill fails to find job
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:24:15 +02:00
shuki
53476455e3 Improve kill job feedback messages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:22:55 +02:00
shuki
54c7b75cee Add debug output to kill_job to diagnose kill failure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:20:53 +02:00
shuki
0110b00b67 Decouple job lifecycle from screen workers
Jobs were tied to screen @work tasks, so switch_screen cancelled the
worker and lost the process reference. Now start_job uses
asyncio.create_task so jobs survive screen changes and can be killed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:18:39 +02:00
shuki
6a0389f437 Use SIGKILL and os.getpgid for reliable job killing
SIGTERM was being ignored by child processes. Use SIGKILL via the
actual process group ID, with proc.kill() as fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:16:09 +02:00
shuki
5e21d1b20a Navigate to Running Tasks after starting backup or restore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:15:30 +02:00
shuki
df07e4e4f9 Remove duplicate completion notifications from backup/restore screens
The app-level on_job_finished handler already shows these.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:12:33 +02:00
shuki
c96930f3ff Kill entire process group when stopping a job
Start CLI subprocesses in their own session so SIGTERM via
os.killpg reaches child processes (rsync, etc.) not just the shell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:11:37 +02:00
shuki
2379c2fdeb Add Kill Job button to Running Tasks screen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:10:19 +02:00
shuki
8a83812584 Add background jobs system with Running Tasks screen
Backup and restore operations now run as background jobs instead of
blocking modal screens. Users can navigate away and check progress
from a dedicated Running Tasks screen. OperationLog supports attaching
to running jobs with live output polling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:07:34 +02:00
shuki
0b0204dada Format log filenames as readable date/time columns in logs screen
Show '2026-03-06' and '14:45:16' instead of 'gniza-20260306-144516.log'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:46:10 +02:00
shuki
f9f7ae6ad3 Format snapshot timestamps as readable dates in snapshots browser
Display '2026-03-06 14:07:06' instead of raw '2026-03-06T140706'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:42:41 +02:00
shuki
99774efe52 Show 'never' instead of '--' for empty last/next run in schedule table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:09:55 +02:00
shuki
63cc7f842e Fix security and correctness bugs found in code review
- Add shquote() to escape single quotes in paths passed to remote_exec,
  preventing shell injection via REMOTE_BASE containing single quotes
- Apply shquote to remote_exec calls in remotes.sh, backup.sh, transfer.sh, ssh.sh
- Add DISK_USAGE_THRESHOLD validation in config.sh
- Export SMTP_PASSWORD (was missing from export list)
- Fix WEB_PORT default mismatch: use 2323 consistently in from_conf and settings save
- Narrow exception catch in remotes.py disk info fetch to KeyError/LookupError
- Quote REMOTE_KEY in build_rsync_ssh_cmd for paths with spaces

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 08:13:20 +02:00
shuki
590b87843d Add configurable disk usage threshold setting
Disk usage threshold (default 95%) can now be controlled from
Settings. Set to 0 to disable the check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 07:08:42 +02:00
shuki
993a66d8c6 Add include/exclude filter support and disk space pre-check
- Add TARGET_INCLUDE field for rsync include patterns (comma-separated)
- Pass TARGET_INCLUDE and TARGET_EXCLUDE to rsync in transfer_folder
- Include mode uses --include='*/' + patterns + --exclude='*' + --prune-empty-dirs
- Abort backup if remote disk usage >= 95%

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 07:04:52 +02:00
shuki
eb9dda416b Remove Speed Test and Disk Info buttons from remotes screen
Disk info is now shown directly in the table. Speed test and detailed
disk info buttons/commands are no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 06:47:05 +02:00
shuki
8b3d6ede4f Show disk usage in remotes table with async loading
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 06:44:27 +02:00