15 Commits

Author SHA1 Message Date
86766cc004 feat: add warmup schedule (cron) field to config UI
The backend already supports warmup_schedule for periodic cache warmup,
but the field was missing from the web config editor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 01:39:21 +08:00
d2b9f46b1a feat: add Apply Config progress modal and fix stale PENDING health after reload
- Add 4-step progress modal to config apply flow (validate, write, reload, services ready)
- Poll SSE-updated data-share-health attributes to detect when services finish restarting
- Fix stale health bug: recalculate health for affected shares based on actual mount
  success instead of preserving old health from before reload
- Add modal overlay/card/step CSS matching the dark theme
- Include connection refactor (multi-protocol support) and probe helpers from prior work

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 01:11:50 +08:00
3a858431f1 Fix config test button lock and add backend timeout 2026-02-19 23:18:09 +08:00
d5b83a0075 fix: SSE 实时更新同步状态指示器
sync-status 区域未包含在 SSE OOB swap 中,导致页面加载后
状态永远不会更新。新增 SyncStatusPartial 模板并加入 SSE
payload,使 dirty count 归零时 UI 能实时切换。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 17:30:08 +08:00
faf9d80824 feat: fill implementation gaps — preset unification, cron, adaptive bw, update cmd, tests
Step 1 — Unify preset logic (eliminate dual implementation)
- src/cli/preset.rs: add missing fields (chunk_limit, multi_thread_streams,
  multi_thread_cutoff), fix Office buffer_size 64M→128M, implement FromStr
- src/web/api.rs: post_preset() now calls Preset::apply() — no more inlined
  params; Office write_back unified to 5s (was 3s in API)

Step 2 — Fix setup.rs connection test: warn→bail
- All 4 "Warning: Could not connect/resolve" prints replaced with anyhow::bail!
  matching deploy/setup.rs behavior

Step 3 — Web UI: add [web] and [notifications] edit sections
- templates/web/tabs/config.html: new collapsible Web UI (password) and
  Notifications (webhook_url, cache_threshold_pct, nas_offline_minutes,
  writeback_depth) sections, both tagged "No restart"
- Also adds [log] section (file path + level select, "Full restart")

Step 4 — Full cron expression support in warmup scheduler
- Cargo.toml: add cron = "0.12", chrono = "0.4"
- supervisor.rs: normalize_cron_schedule() converts 5-field standard cron to
  7-field cron crate format; replaces naive hour-only matching

Step 5 — Adaptive bandwidth algorithm
- supervisor.rs: extract compute_adaptive_limit() pure function; sliding
  window of 6 samples, cv>0.3→congested (−25%, floor 1MiB/s), stable
  near-limit→maintain, under-utilizing→+10% (capped at limit_up)

Step 6 — warpgate update command
- src/cli/update.rs: query GitHub Releases API, compare with CARGO_PKG_VERSION
- src/main.rs: add Update{apply}, SetupWifi, CloneMac{interface} commands
- src/cli/wifi.rs: TODO stub for WiFi AP setup

Unit tests (+35, total 188→223)
- cli/preset.rs: 10 tests — FromStr, all fields for each preset, idempotency,
  connection/share isolation, write_back consistency regression
- supervisor.rs: 14 tests — normalize_cron_schedule (5 cases),
  compute_adaptive_limit (9 cases: congestion, floor, stable, under-utilizing,
  cap, zero-current, zero-max, empty window)
- config.rs: 11 tests — WebConfig (3), NotificationsConfig (4), LogConfig (4)

Shell tests (+4 scripts)
- tests/09-cli/test-preset-cli.sh: preset CLI without daemon; checks all
  three presets write correct values including unified buffer_size/write_back
- tests/09-cli/test-update-command.sh: update command; skips on no-network
- tests/10-scheduled/test-cron-warmup-schedule.sh: "* * * * *" fires in <90s
- tests/10-scheduled/test-adaptive-bandwidth.sh: adaptive loop stability
- tests/harness/config-gen.sh: add warmup.warmup_schedule override support
- tests/run-all.sh: add 10-scheduled category

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 16:55:00 +08:00
ee9ac2ce2d feat: Web UI — offline banner, sync indicator, preset buttons, reconnect button
- Task A: Offline mode banner in layout (nas_offline field in LayoutTemplate)
- Task B: Safe-to-disconnect sync indicator on dashboard (all_synced field)
- Task C: Preset apply buttons (photographer/video/office) in config tab with POST /api/preset/{profile} endpoint
- Task D: Reconnect button and error banner in share detail panel
- Added nas_offline/all_synced fields to DaemonStatus for integration contract

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:44:36 +08:00
5efef83a90 Add multi_thread_streams/cutoff support and Samba performance tuning
- Add multi_thread_streams (default 4) and multi_thread_cutoff (default "50M")
  fields to ReadConfig, wired into rclone mount args
- Expose both fields in Web UI config editor under Read Tuning section
- Add Samba performance options: TCP_NODELAY, large readwrite, max xmit
- Update config.toml.default with new fields and sftp_connections guidance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 14:15:23 +08:00
64d6171ec9 Unify logging to tracing: file appender + unified log viewer
Replace scattered println!/eprintln! with structured tracing macros throughout
supervisor, scheduler, and web modules. Add LogConfig (file + level) to Config
and a new logging module that initialises a stderr + optional non-blocking file
appender on `warpgate run`. Remove the in-memory LogBuffer/LogEntry from
AppState; the web /api/logs endpoint now reads the log file directly with
from_line/lines pagination. `warpgate log` replaces journalctl with `tail`,
and the Logs tab Alpine.js is updated to match the new API response shape.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 11:24:06 +08:00
74b0e72549 Add periodic dir-refresh and per-share refresh status display
Introduces a ScheduledTask mechanism that periodically calls rclone RC
vfs/refresh to keep directory listing caches warm (no file downloads),
with two-level config (global default + per-share override). Adds
dir-refresh status badges and timestamps to the web UI shares tab and
CLI status output, following the same pattern as warmup/warmed.

- src/scheduler.rs: New generic ScheduledTask runner with generation-based
  cancellation and parse_interval() helper
- src/rclone/rc.rs: Add vfs_refresh() RC API call
- src/config.rs: Add DirRefreshConfig, per-share dir_refresh_interval
  override, effective_dir_refresh_interval() resolution method
- src/config_diff.rs: Track dir_refresh_changed for hot-reload
- src/daemon.rs: Track per-share last_dir_refresh timestamps (HashMap),
  add dir_refresh_ago_for() helper and format_ago()
- src/supervisor.rs: spawn_dir_refresh() per-share background threads,
  called on startup and config reload
- src/web/api.rs: Expose dir_refresh_active + last_dir_refresh_ago in
  ShareStatusResponse
- src/web/pages.rs: Populate dir_refresh_active + last_dir_refresh_ago
  in ShareView and ShareDetailView
- templates/web/tabs/shares.html: DIR-REFRESH badge (yellow=pending,
  green=N ago) in health column; Dir Refresh row in detail panel
- templates/web/tabs/config.html: Dir Refresh section and per-share
  interval field in interactive config editor
- src/cli/status.rs: Append Dir-Refresh suffix to mount status lines

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 10:54:08 +08:00
15f915fbee Show active transfer count, add SFTP retry resilience, and fix config tab refresh
- Use rclone transferring array to show only active transfers instead of
  cumulative count; zero out speed when no transfers are active
- Add SFTP retry/timeout flags to rclone mount for flaky Tailscale tunnels
- Skip auto-refresh on config tab to prevent editor resets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 00:21:22 +08:00
e8f1971d63 Add auto-refresh toggle for web UI tabs with localStorage persistence
Periodic client-side refresh for Shares/Config tabs using Alpine.js
setInterval, with toggle and configurable interval (2-30s) in header.
Dashboard (SSE) and Logs (own polling) are excluded. Shares tab
preserves row expansion state across refreshes via ?expand= param.
Adds [x-cloak] CSS rule and conditional x-cloak on detail rows to
prevent flash during content swaps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 19:31:54 +08:00
2432f83914 Re-trigger warmup on config reload and add per-share warmup status tracking
Warmup config changes via the web UI now actually run warmup without requiring
a daemon restart. Adds generation-based warmup tracking with progress reporting
across CLI status, JSON API, SSE live updates, and web UI badges/detail panels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 19:13:04 +08:00
6bb7ec4d27 Web UI overhaul: interactive config editor, SSE live updates, log viewer, and SMB reload fixes
- Replace raw TOML textarea with Alpine.js interactive form editor (10 collapsible
  sections with change-tier badges, dynamic array management for connections/shares/
  warmup rules, proper input controls per field type)
- Add SSE-based live dashboard updates replacing htmx polling
- Add log viewer tab with ring buffer backend and incremental polling
- Fix SMB not seeing new shares after config reload: kill entire smbd process group
  (not just parent PID) so forked workers release port 445
- Add SIGHUP-based smbd config reload for share changes instead of full restart,
  preserving existing client connections
- Generate human-readable commented TOML from config editor instead of bare
  toml::to_string_pretty() output
- Fix Alpine.js 2.x __x.$data calls in dashboard/share templates (now Alpine 3.x)
- Fix toggle switch CSS overlap with field labels
- Fix dashboard going blank on tab switch (remove hx-swap-oob from tab content)
- Add htmx:afterSettle → Alpine.initTree() bridge for robust tab switching

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 18:06:52 +08:00
466ea5cfa8 Add pre-mount remote path probe and per-share health status
Before mounting, probe each share's remote path with `rclone lsf`
(10s timeout, parallel execution). Failed shares are skipped — they
never get mounted or exposed to SMB/NFS/WebDAV — preventing the
silent hang that occurred when rclone mounted a nonexistent directory.

- ShareHealth enum: Pending → Probing → Healthy / Failed(reason)
- Supervisor: probe phase between preflight and mount, protocol
  configs generated after probe with only healthy shares
- Web UI: health-aware badges (OK/FAILED/PROBING/PENDING) with
  error messages on dashboard, status partial, and share detail
- JSON API: health + health_message fields on /api/status
- CLI: `warpgate status` queries daemon API first for tri-state
  display (OK/FAILED/DOWN), falls back to direct mount checks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 15:28:56 +08:00
ba1cae7f75 Add daemon web UI, JSON API, and config hot-reload engine
- New: axum web server on port 8090 with htmx dashboard
- New: JSON API endpoints (/api/status, /api/config, /api/bwlimit)
- New: config diff engine with 4-tier change classification
- New: tiered config hot-reload (live/protocol/per-share/global)
- Refactor: supervisor loop uses mpsc command channel (recv_timeout)
- Refactor: supervisor updates shared DaemonStatus every poll cycle
- Dependencies: tokio, axum, askama, tower-http

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 14:18:20 +08:00