349 Commits

Author SHA1 Message Date
lerko a32a443a4a perf(tui): precompute maintenance set, eliminate redundant GetAllSites
CI / test (pull_request) Successful in 1m45s
CI / lint (pull_request) Successful in 1m16s
CI / vulncheck (pull_request) Successful in 46s
Replace O(windows × sites) isMonitorInMaintenance with O(1) map lookup.
buildMaintSet runs once per refreshLive/handleTabData, not per call site.

groupSparkline/groupUptime now use m.sites (already on model) instead of
calling engine.GetAllSites() which copies the full map under a mutex.
2026-07-01 19:37:27 -04:00
lerko b90033c7f0 fix(tui): use titledPanelH chrome for fullscreen detail view
CI / test (pull_request) Successful in 1m52s
CI / lint (pull_request) Successful in 1m22s
CI / vulncheck (pull_request) Successful in 56s
Match the sidebar's bordered panel style (╭─ Title ─╮) so the
fullscreen detail view on narrow terminals looks cohesive with the
rest of the UI. Breadcrumb now renders as the panel title.
2026-07-01 16:22:49 -04:00
lerko 989dd1fb39 feat(tui): fullscreen detail view + enriched sidebar content
On narrow terminals (<120 cols), Enter opens a fullscreen detail view
instead of the sidebar that can't be seen. Wide terminals keep existing
sidebar toggle behavior.

Enrich detail panel with: state since, last success, connection chain
diagnostic, probe results, latency histogram, extended endpoint fields
(interval/timeout/method/codes/regions/description), push token,
maintenance window name. Breadcrumb shown in fullscreen mode only.
2026-07-01 16:12:45 -04:00
lerko faf7d36c64 refactor(tui): replace # column with colored status dot
CI / test (pull_request) Successful in 2m7s
CI / lint (pull_request) Successful in 1m27s
CI / vulncheck (pull_request) Successful in 1m1s
Drop the row-number column and add a colored status dot as the first
column. Dot uses the same icon/color as the existing status indicators
(▲ green for up, ▼ red for down, ◼ purple for maint, etc). Matches
the maint strip visual pattern. Status text column retained for
explicit label.
2026-06-30 23:38:05 -04:00
lerko 16f0c2eb66 fix(tui): pad monitors panel to fill available height
CI / test (pull_request) Successful in 1m55s
CI / lint (pull_request) Successful in 1m22s
CI / vulncheck (pull_request) Successful in 1m1s
Monitors panel now uses titledPanelH with a target height based on
maxTableRows, filling the space down to the bottom strip. No more
gap between monitors panel and logs/maint strip when fewer monitors
than available rows.
2026-06-30 23:22:51 -04:00
lerko f0d97f5562 feat(tui): click anywhere in row to select monitor or maint item
CI / test (pull_request) Successful in 1m56s
CI / lint (pull_request) Successful in 1m22s
CI / vulncheck (pull_request) Successful in 56s
Use panel zone Pos() to compute clicked row from Y offset instead of
per-cell zone matching. Monitors and maint strip both support full-row
click selection.
2026-06-30 23:10:16 -04:00
lerko 0484153103 fix(tui): fix maint strip spacing and ANSI padding
Use rune-based padding instead of fmt %-*s which miscounts ANSI escape
sequences. Remove outer lipgloss width wrapper that added extra lines.
2026-06-30 23:00:56 -04:00
lerko e3d681311f refactor(tui): move maintenance from sidebar to bottom strip
Replace the cramped 22-char maint sidebar with a full-width bottom
strip in the same position as logs. Bottom panel is modal: l for logs,
m for maint, same key again to close. Maint strip shows one row per
window with icon, title, affected monitors, and status/time remaining.

Removes maintSidebarW constant and maintOffset field. Introduces
bottomPanel enum (bottomNone/bottomLogs/bottomMaint) replacing
logsOpen and maintOpen booleans. m key no longer gated behind
wideBreakpoint.
2026-06-30 22:47:50 -04:00
lerko f7303c946c fix(tui): show — for uptime when monitor is in maintenance
CI / test (pull_request) Successful in 1m57s
CI / lint (pull_request) Successful in 1m27s
CI / vulncheck (pull_request) Successful in 55s
Monitors in active maintenance now display — instead of a misleading
0.0% uptime in both the main table and detail sidebar.
2026-06-30 21:33:39 -04:00
lerko 6e936ecce3 style(tui): adjust monitor/detail split to 60/40
CI / test (pull_request) Successful in 1m49s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
Gives monitors panel more room for columns while detail sidebar
content stacks vertically and doesn't need the extra width.
2026-06-30 21:12:00 -04:00
lerko 04cf12f52b style(tui): match detail panel footer to hotbar styling
Detail panel footer now uses accent keys, muted descriptions, and dot
separators — same visual style as the bottom hotbar.
2026-06-30 21:07:47 -04:00
lerko 33df597dda fix(tui): merge SLA footer into single line
Period keys and Esc Back now render on one line instead of two.
2026-06-30 20:59:04 -04:00
lerko 1d14f640f4 feat(tui): pin detail panel footer keys at bottom of sidebar
CI / test (pull_request) Successful in 1m53s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 1m1s
Footer keys (period selector, edit/history/SLA shortcuts, Esc) are now
pinned at the bottom of the detail panel, always visible regardless of
scroll position. Scrollable content fills the space between the header
and the pinned footer.
2026-06-30 20:46:43 -04:00
lerko 631f07c242 feat(tui): stable detail panel height with scroll support
CI / test (pull_request) Successful in 1m56s
CI / lint (pull_request) Successful in 1m12s
CI / vulncheck (pull_request) Successful in 56s
Detail sidebar now maintains consistent height matching the monitors
panel across all modes (default, SLA, history). Content scrolls within
the fixed frame via mouse wheel or j/k when the detail panel is
focused. Scroll offset resets on mode/monitor/period changes. Logs
strip stays visible in all states.
2026-06-30 20:36:25 -04:00
lerko 0badc2ddf5 fix(tui): cap detail sidebar height to match monitors panel
CI / test (pull_request) Successful in 1m51s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
SLA daily breakdown no longer overflows past the monitors panel. Detail
sidebar height is capped to monitors panel height via titledPanelH.
SLA daily rows are limited to fit within available space. Logs strip
stays visible in all detail modes.
2026-06-30 20:18:39 -04:00
lerko be14436701 style(tui): accent keys, muted descriptions, dot separators in hotbar
CI / test (pull_request) Successful in 1m49s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
Keys rendered in accent color, descriptions in muted. Dot separators
between items. No brackets. Faster to scan at a glance.
2026-06-30 19:56:16 -04:00
lerko efa8894b18 refactor(tui): unify detail toggle on Enter, remove i keybind
Enter now toggles detail sidebar open/closed with preference
persistence. Removes redundant i keybind that did the same thing.
Hotbar updated: [Enter]Detail when closed, [Enter]Close when open.
2026-06-30 19:51:44 -04:00
lerko ef54b36e0d refactor(tui): make Enter always open detail, Space for group collapse
Enter now consistently opens the detail sidebar for both monitors and
groups. Group collapse/expand is Space-only. Hotbar shows [Space]Expand
or [Space]Collapse contextually when cursor is on a group row.
2026-06-30 19:09:51 -04:00
lerko 835844314e fix(tui): show context-aware Enter hint in hotbar
CI / test (pull_request) Successful in 1m49s
CI / lint (pull_request) Successful in 1m12s
CI / vulncheck (pull_request) Successful in 50s
When cursor is on a group row, hotbar now shows [Enter]Expand or
[Enter]Collapse instead of [Enter]Detail, matching actual behavior.
2026-06-30 17:09:58 -04:00
lerko dc79e2baaa refactor(tui): remove full-page detail, SLA, and history views
CI / test (pull_request) Successful in 1m49s
CI / lint (pull_request) Successful in 1m16s
CI / vulncheck (pull_request) Successful in 56s
All monitor detail content now lives in the sidebar panel.
Delete the full-page viewDetailPanel, viewSLAPanel, viewHistoryPanel,
handleDetailKey, handleSLAKey, handleHistoryKey, openSLAView, and
related dead code (histogram, sparkline tooltip, detailViewport).

Remove stateDetail, stateSLA, stateHistory session states.
Update tests to use detailOpen/detailMode instead of removed states.
2026-06-30 09:28:12 -04:00
lerko 3e02833df4 feat(tui): enter opens detail sidebar, logs as bottom strip
Enter on a site now opens the detail sidebar instead of a
full-page takeover. Enter on a group expands/collapses children
(same as space). Logs panel moves to a toggleable bottom strip
via the l key with j/k scrolling when focused.
2026-06-30 09:12:13 -04:00
lerko 8581662237 feat(tui): SLA and history as sidebar detail modes
SLA and History views now render inside the detail sidebar panel
instead of taking over the full screen. Press s/h to switch modes,
Esc to return to default detail view. Cursor movement resets to
default mode.

- Add detailMode state (detailDefault/detailSLA/detailHistory)
- SLA sidebar: period selector, uptime bars, daily breakdown
- History sidebar: sparkline density, transition list, stats
- Panel title shows "SLA · name" or "History · name" in sub-modes
- Period keys [1]-[4] work in SLA mode from dashboard state
2026-06-30 09:09:04 -04:00
lerko 2779f9f532 feat(tui): tall-narrow detail sidebar for master-detail layout
Replace the old two-column/single-column inline detail with a
vertically stacked layout optimized for the right-side panel.

Content stack: status line, type details, uptime, error, latency
chart (3-row), 30d timeline, sparkline, min/avg/max stats, and
up to 5 state changes — all flowing top-to-bottom within the
~55% width detail panel.
2026-06-30 09:03:30 -04:00
lerko 4321e094a3 feat(tui): move detail panel from bottom overlay to right side
Restructure dashboard from [Monitors 70% | Logs 30%] to
[Monitors 45% | Detail 55%] master-detail layout. Detail panel
now sits beside the monitor list instead of below it, keeping
dashboard context visible during inspection.

- Detail panel renders in horizontal split (right of monitors)
- Logs sidebar removed; `l` key opens fullscreen logs directly
- recalcLayout no longer subtracts detail height from table rows
- Remove unused renderCompactLogLine/viewLogsSidebar (Phase 4 recreates)
2026-06-30 08:59:17 -04:00
lerko 1856820c3e feat(tui): single-dashboard layout with sidebar and overlay
CI / test (pull_request) Successful in 1m44s
CI / lint (pull_request) Successful in 1m16s
CI / vulncheck (pull_request) Successful in 50s
Replace 3-tab navigation with a single monitoring dashboard.

- Replace tab bar with minimal status line (pulse + counts + version)
- Maintenance becomes a toggleable left sidebar (m key)
  - Compact list: active (●) and scheduled (○) windows
  - Enter opens full-screen detail with end/delete actions
- Settings becomes a centered floating overlay (S key)
  - Alerts/Nodes/Users sub-sections with left/right navigation
  - Full CRUD support inside overlay with returnState tracking
- Remove currentTab, switchTab, tab constants, tab click zones
- Replace deleteTab with deleteKind string for cleaner dispatch
- Separate settingsCursor/settingsOffset from main cursor
- Panel focus: maint → monitors → logs → detail
- Context-sensitive footer key hints per focused panel
2026-06-29 16:12:53 -04:00
lerko aeee2cd0ce fix(tui): cohesion polish across all views
CI / test (pull_request) Successful in 1m44s
CI / lint (pull_request) Successful in 1m16s
CI / vulncheck (pull_request) Successful in 56s
- Hide nonsense latency/histogram data for group monitors in detail view
- Add missing status colors to fmtStatusWord (LATE, STALE, PENDING, etc)
- Wrap Maint and Settings tabs in titled panels to match Monitors tab
- Standardize headers: breadcrumb style (History > Name, SLA > Name)
- Standardize footer key order: actions first, [q/Esc] Back last
- Add # column to Nodes table for consistency with all other tables
- Use titleStyle for section headers (CONFIGURATION, DAILY BREAKDOWN)
- Fix panel focus not switching when clicking monitor rows from logs panel
2026-06-29 11:06:58 -04:00
lerko 7ce5af5bf6 fix(tui): correct delete confirm labels, normalize help text
CI / test (pull_request) Successful in 1m52s
CI / lint (pull_request) Successful in 1m11s
CI / vulncheck (pull_request) Successful in 56s
Delete confirmation dialog used wrong magic numbers for entity kind
mapping — maintenance windows showed as "alert", settings deletions
showed as "monitor". Now uses tab/section constants to match correctly.

Also: consistent [q/Esc] Back across all views (detail inline, logs,
SLA, history headers), extract detailKeys(), remove dead maxSections
variable, add nodes empty state hint, use models.Status constants in
siteOrder, delete orphaned theme.png.
2026-06-29 09:44:51 -04:00
lerko 18e2d60210 feat(tui): mouse click for settings sections, column sort, logs panel
CI / test (pull_request) Successful in 1m44s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
- Click Alerts/Nodes/Users sub-tabs in settings to switch sections
- Click STATUS/NAME/LATENCY column headers to sort (click again
  to reverse direction)
- Logs panel show/hide: [l] toggles sidebar visibility, click
  focused panel to hide. Monitors expand to full width when hidden.
- Logs full-screen: Enter when focused on logs opens scrollable
  full-screen log view with severity tags, filter toggle [f],
  and live updates
2026-06-28 12:24:52 -04:00
lerko ab1194f74d fix(monitor): refresh maintenance cache after loading sites
CI / test (pull_request) Successful in 1m49s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
Move refreshMaintenanceCache() to after sites are loaded into
liveState. Previously it ran before the site loading loop, so on
the first iteration liveState was empty and the cache resolved
to nothing. This caused groups to briefly show DOWN on startup
for children that were in maintenance, until the next poll cycle
repopulated the cache.
2026-06-28 11:15:35 -04:00
lerko 25f4b20b87 feat(monitor): save state changes for group monitors
CI / test (pull_request) Successful in 1m57s
CI / lint (pull_request) Successful in 1m11s
CI / vulncheck (pull_request) Successful in 56s
checkGroup() now detects status transitions and persists them as
state change records, same as individual monitors. Groups also
get StatusChangedAt updates and log entries for down/recovery
events. This enables history and SLA views for group monitors.
2026-06-28 11:00:25 -04:00
lerko 7171dcd6f8 feat(tui): expand selected alert config below table
CI / test (pull_request) Successful in 1m51s
CI / lint (pull_request) Successful in 1m22s
CI / vulncheck (pull_request) Successful in 56s
Show a detail line below the alert table for the selected row
with untruncated config, health status, last sent time, and
send/fail counts. Solves the CONFIG column truncation issue
without requiring the full-screen detail view.
2026-06-28 10:41:25 -04:00
lerko 822eda4dfd feat(tui): two-column detail panel with type-specific enrichment
CI / test (pull_request) Successful in 1m52s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 51s
Redesign the inline detail panel from a single left-aligned column
to a two-column layout that uses the full panel width.

Left column (55%): latency chart, min/avg/max stats, 30-day
uptime timeline.

Right column (45%): status/latency/last-check summary, type-
specific metadata (HTTP response code + SSL expiry, ping hostname,
port target, push interval/last heartbeat, DNS resolver), uptime
percentage + retry count, and up to 5 state changes listed
vertically with error reasons.

Narrow terminals (<80 cols) fall back to the original stacked
single-column layout.
2026-06-28 10:23:45 -04:00
lerko a5fd3aec90 refactor: propagate context.Context through call chains
CI / test (pull_request) Successful in 1m56s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
Thread context.Context from callers instead of creating
context.Background() at every call site. Engine stores its
lifecycle ctx for use by triggerAlert goroutines. TUI Model
carries ctx for store operations in Cmd closures. CLI commands
create a root ctx and thread it through openStore, seed
functions, and init methods.

Only two intentional context.Background() remain in non-root
positions: engine constructor default (overridden by Start)
and drainWrites (parent already cancelled at shutdown).
2026-06-27 19:43:44 -04:00
lerko 8f16a09da1 refactor: decompose monitor.go and sqlstore.go into focused files
CI / test (pull_request) Successful in 1m44s
CI / lint (pull_request) Successful in 1m11s
CI / vulncheck (pull_request) Successful in 56s
Split monitor.go (1131→350 lines) into alerts.go, checks.go,
sites.go, and maintenance.go by concern. Split sqlstore.go
(833→470 lines) into sqlstore_alerts.go, sqlstore_history.go,
and sqlstore_maintenance.go by domain. Tests move with their
implementation. Pure reorganization — no behavioral changes.
2026-06-27 19:23:34 -04:00
lerko 50f77da131 refactor: extract magic numbers to named constants
CI / test (pull_request) Successful in 1m43s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 51s
Replace inline numeric literals with named constants across 14 files:
server timeouts/rate limits, cluster thresholds/intervals, DB pool
sizes, alert/dial timeouts, TUI uptime thresholds, node status
thresholds, and state history limits.
2026-06-27 15:44:03 -04:00
lerko edbc2beddd fix(test): check errors instead of discarding with bare _
CI / test (pull_request) Successful in 1m53s
CI / lint (pull_request) Successful in 1m16s
CI / vulncheck (pull_request) Successful in 56s
Replace bare _ error discards with t.Fatalf checks across
sqlstore_test, crypto_test, server_test, and checker_test.
2026-06-27 11:53:10 -04:00
lerko 3a089e7c1d feat(store): detect overlapping maintenance windows
CI / test (pull_request) Successful in 1m46s
CI / lint (pull_request) Successful in 1m16s
CI / vulncheck (pull_request) Successful in 56s
Warn via log when creating a maintenance window that overlaps with an
existing one for the same monitor, parent group, or global scope.
Handles both timed and indefinite windows.
2026-06-27 10:58:43 -04:00
lerko 5cc1a005ea feat(assets): full screenshot refresh for new multi-panel layout
CI / test (pull_request) Successful in 1m50s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 46s
Recaptured all screenshots and demo GIF reflecting the complete TUI
overhaul: 3-tab layout, titled panel borders, log sidebar, inline
detail with latency chart + uptime timeline, full-screen detail with
two-column layout + response histogram.

New screenshots: fulldetail.png, settings.png, maint.png.
Removed: alerts.png, logs.png (now Settings sub-sections and sidebar).
Updated README screenshot grid to match new layout.
2026-06-26 15:57:36 -04:00
lerko 11344b4ae6 feat(tui): two-column bottom layout, endpoint/status split, clean labels
CI / test (pull_request) Successful in 2m4s
CI / lint (pull_request) Successful in 1m11s
CI / vulncheck (pull_request) Successful in 56s
Bottom section: graphs (latency + histogram) 70% left, state changes
30% right. Top section rearranged: endpoint details left, status +
timing + HTTP right. Bottom section labels use bold accent without
trailing rules. Spacing between top and bottom halves.

Removed unused renderSparkTooltip (zone marks not wired in column
layout — can restore later).
2026-06-24 21:11:04 -04:00
lerko 11b647b952 fix(tui): add spacing between latency graph and histogram 2026-06-24 20:58:44 -04:00
lerko 1268d99f5c feat(tui): styled section headers with trailing rules in detail panel
Section labels (STATE CHANGES, LATENCY, RESPONSE TIME DISTRIBUTION,
PROBE RESULTS) now render in bold accent color with a trailing ───
rule that fills the width. Two-column info block separated by a full
divider below. Creates clear visual boundaries between sections.
2026-06-24 20:56:21 -04:00
lerko fb50184f37 feat(tui): two-column detail layout with viewport scrolling
Refactored full-screen detail panel: status+endpoint on left column,
timing+config on right column. Halves vertical height of the info
section. Content wraps in a viewport when it exceeds terminal height
— scroll with j/k/arrows/pgup/pgdn.

Restored renderSparkTooltip lost in rewrite. Fixed lint warnings.
2026-06-24 20:48:15 -04:00
lerko 99121d07d8 feat(tui): response time distribution histogram in full-screen detail
Horizontal bar chart showing latency distribution across 5 buckets:
0-50ms, 50-100ms, 100-200ms, 200-500ms, 500ms+. Color-coded green
(fast), yellow (medium), red (slow). Shows count per bucket.

Appears in the full-screen detail panel (Enter) after the sparkline
stats. Skipped for push monitors (no latency data).
2026-06-24 20:23:22 -04:00
lerko a59edf8410 feat(tui): 30-day uptime timeline in inline detail panel
Statuspage-style colored bar — one █ per day, colored by uptime:
green (>= 99%), yellow (>= 95%), red (< 95%), gray (no data).
30-day percentage shown to the right.

Daily breakdown computed via ComputeDailyBreakdown from state_changes
and loaded alongside detail data in loadDetailCmd. Auto-updates on
cursor move.
2026-06-24 20:16:01 -04:00
lerko 6799163cd4 fix(tui): apply sort to group children, not just ungrouped monitors
CI / test (pull_request) Successful in 2m4s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
2026-06-24 19:44:50 -04:00
lerko 28fb6c8889 feat(tui): alert failure badge on Settings tab
Settings tab warn count now includes failed alert channels — alerts
where the last send failed (LastSendOK=false, LastSendAt not zero).
Shows as a red badge number alongside offline node count. Surfaces
broken alert channels without navigating to Settings.
2026-06-21 19:10:18 -04:00
lerko d982359f25 feat(tui): column sort with indicator on monitors table
Press < / > to cycle sort column (Status, Name, Latency). Press r to
reverse direction. Sorted column shows ▲/▼ arrow in the header.

Groups always float to top. Sort applies to ungrouped monitors and
group children independently. Default: Status descending (DOWN first).
2026-06-21 19:09:42 -04:00
lerko 4af800a359 feat(tui): multi-row color-coded sparkline chart with Y-axis
CI / test (pull_request) Successful in 1m48s
CI / lint (pull_request) Successful in 1m17s
CI / vulncheck (pull_request) Successful in 56s
Replace ntcharts with custom multi-row sparkline. Each bar is color-
coded by latency threshold (green < 200ms, yellow < 500ms, red > 500ms)
and DOWN checks render in red. 3 rows tall with 24 discrete levels.

Y-axis labels (max/min ms) on the left, Min/Avg/Max stats below.
Zero external dependencies — removed ntcharts.
2026-06-21 17:43:50 -04:00
lerko a8c43bdb8e feat(tui): ntcharts sparkline with Y-axis labels and stats
Replaced streamline chart with ntcharts sparkline (block elements,
auto-scaling). Height=2, Y-axis labels (max/min ms) on the left,
Min/Avg/Max stats below. Denser and more readable than the line chart.
2026-06-21 17:12:25 -04:00
lerko d0805f61c6 fix(tui): size chart width to data point count 2026-06-21 13:41:05 -04:00