Commit Graph
30 Commits
Author SHA1 Message Date
Hugh KaznowskiandClaude Sonnet 5 559883dbab Add "All dashboards" print-friendly stacked view (ticket 009)
Adds an "All dashboards" selector alongside the existing click-to-select
single-dashboard view. Selecting it stacks every dashboard vertically in
normal document flow, each preceded by a heading naming it, with no
fixed-height or scroll-clipping containers, so the browser's native print
function can render the full stack across pages.

Verified in-browser: single-dashboard editing still works unchanged, and
"All dashboards" renders all dashboards (including an empty one) stacked
with named separators; confirmed via computed layout that only the
pre-existing app-level scroll container grows to fit the content, with no
clipping container inside the Dashboards section itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:54:52 +01:00
Hugh KaznowskiandClaude Sonnet 5 b2e97520ec Simplify Dashboards header to just "Dashboards" (ticket 007)
Drop the redundant profile-name suffix from the Dashboards section
header; the active profile is already surfaced via the profile
dropdown in NavMenu.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:51:10 +01:00
Hugh KaznowskiandClaude Sonnet 5 5038295554 Collapse sections by clicking their title bar (ticket 006)
Alerts, Metrics, Params, and Dashboards now toggle collapsed state when
their header row is clicked, instead of requiring a dedicated collapse
button. The chevron (CollapseToggle) becomes a purely visual, non-focusable
indicator for these sections; HelpIcon and PopOutButton now stop
propagation so they keep working without also collapsing the section.

The log viewer's toggle (App.tsx/FilterBar) keeps its dedicated button,
since that row is a filter toolbar with an editable input rather than a
plain title bar, so CollapseToggle's onToggle prop stays available for
that case.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:48:59 +01:00
Hugh KaznowskiandClaude Sonnet 5 01eadf415c Merge ticket/002-collapsible-alerts-section
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:44:33 +01:00
Hugh KaznowskiandClaude Sonnet 5 87209ea401 Make Alerts section collapsible
Wire the Alerts section into the shared CollapsibleSection mechanism
(CollapseToggle + useSectionCollapsed), matching the pattern used by
Metrics and Params, with its own persisted 'alerts' section id.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:44:22 +01:00
Hugh KaznowskiandClaude Sonnet 5 ffeba3c274 Merge "custom themes" and "configured/imported CSS" into one mechanism (ticket 012)
The backend already stored both under one CssEntry list (Imported/Linked,
differing only by the is_theme flag), but the NavMenu Settings panel split
them into two visually-duplicated sections — "Custom themes" with its own
upload/link forms and list, and "Import CSS"/"Configured CSS" with a nearly
identical upload form and a separate list — and useSettingsPanel exposed
parallel importCssEntry/importThemeEntry and (theme-only) linkThemeEntry
wrappers around the same underlying API calls.

Consolidate to one "CSS" section: a single list of all CssEntries (each
tagged "theme" and selectable when is_theme is set), one import form and
one link form, each with a "Use as theme" checkbox instead of a duplicate
theme-only form. useSettingsPanel now exposes a single importCssEntry(name,
content, isTheme) and a generic linkCssEntry(url, isTheme) — the latter also
fixes the prior asymmetry where linking (vs. uploading) was only available
for themes, not arbitrary CSS.

No backend or settings-schema changes were needed: is_theme already
persists correctly, so existing custom-theme and imported-CSS
configuration keeps working unmodified under the unified UI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:42:40 +01:00
Hugh KaznowskiandClaude Sonnet 5 ed0be9726f Remove duplicate "grey" theme, keep "dark" (ticket 004)
"grey" and "dark" rendered identically apart from accent colour, so
drop "grey" as a selectable colour scheme everywhere in the frontend
(index.css, api.ts's ColorScheme type, the NavMenu picker, the
downloadable BUILTIN_THEMES table) and keep "dark" as the single
equivalent theme.

Existing settings.json files saved with color_scheme: "grey" keep
loading correctly: the backend ColorScheme enum aliases the legacy
"grey" serde value onto Dark, so old configs transparently migrate to
"dark" without any manual intervention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:42:40 +01:00
Hugh KaznowskiandClaude Sonnet 5 049c4f8311 Remove tickets/008-docs-add-worked-examples.md (implemented)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:38:56 +01:00
Hugh KaznowskiandClaude Sonnet 5 80515e0f84 Merge ticket/005-sharp-angular-timeline-spikes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:38:43 +01:00
Hugh KaznowskiandClaude Sonnet 5 2c509b51fc Remove tickets/011-approximate-heap-tracker.md (implemented)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:38:29 +01:00
Hugh KaznowskiandClaude Sonnet 5 de48e218a1 Use sharp/angular tops for timeline event spikes
Remove the rounded-t Tailwind class from timeline bars so spike peaks
render as sharp, flat-topped rectangles instead of rounded corners,
making bucket boundaries clearer to read. Verified in the browser in
both light and dark theme.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:37:27 +01:00
Hugh KaznowskiandClaude Sonnet 5 b1e509efbd Record JSON log ingestion design decision, file follow-up tickets (ticket 003)
Decision covers detection, invalid-JSON handling, and a prioritized feature
roadmap (repowise decision fdb47034ad954e3ea0b898fdc2750c32). Files three
follow-up implementation tickets (014-016) and removes the investigation
ticket now that the decision is recorded.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:36:27 +01:00
Hugh KaznowskiandClaude Sonnet 5 bb513b5eac Merge ticket/013-ntfy-sink-inline-fields
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:35:43 +01:00
Hugh KaznowskiandClaude Sonnet 5 83c617d628 Remove tickets/001-remove-dashboard-nav-entry.md (implemented)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:35:30 +01:00
Hugh KaznowskiandClaude Sonnet 5 70d9956059 Lay out ntfy sink server URL and topic inputs on one line
Combines the ntfy server URL and topic fields into a single flex row
separated by a "/" to visually communicate that they compose into one
destination (server + topic), instead of stacking as two full-width
rows.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 18:35:24 +01:00
Hugh Kaznowski 893464b3b1 Create tickets 2026-09-05 18:31:22 +01:00
Hugh KaznowskiandClaude Sonnet 5 00c21c8032 Trim comments across Rust and webapp source to direct one-liners (ticket 030)
Pass over src/*.rs, webapp/src/**, and the in-app "?" docs prose:
condensed multi-paragraph doc comments to single lines that state the
non-obvious why, deleted comments that only restated adjacent code, and
tightened the Docs.tsx help-panel wording. No logic, structure, or code
formatting changed — verified via cargo test (143 passed) and
tsc -b && vite build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 17:02:33 +01:00
Hugh KaznowskiandClaude Sonnet 5 3cef6dc8ae Remove unused tower-http dependency (ticket 029)
Audited every entry in Cargo.toml and webapp/package.json against actual
usage. tower-http was declared but never referenced in src/ (no ServeDir,
CorsLayer, or other tower_http usage) — it was only pulled in transitively
via reqwest anyway, so it's dead weight as a direct dependency. All other
Cargo.toml and package.json entries have live usage (including include_dir,
which looked unused via grep but is required transitively by the
fs_embed::fs_embed! macro, and tailwindcss, which is pulled in via
@import "tailwindcss" in src/index.css rather than a JS import).

cargo test (143 passed) and webapp npm run build both pass after pruning.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:50:54 +01:00
Hugh KaznowskiandClaude Sonnet 5 0c4b596e3c Add pop-out button to open a section in its own tab (ticket 036)
Each of the four primary sections (Log viewer, Params, Metrics,
Dashboards) gets a PopOutButton next to its CollapseToggle/HelpIcon that
opens `?section=<id>` in a new tab via window.open. App.tsx branches on
that query param to render just the one section full-page, with no
NavMenu/FilterBar/sibling chrome — Metrics/Dashboards get the range that
was active at pop-out time via startMs/endMs query params (they have no
LogTimeline of their own to pick one), Params gets a small self-contained
params fetch since it has no LogPreview sibling to share state with, and
the popped-out Log viewer owns its own copy of the log/timeline polling
state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:49:12 +01:00
Hugh KaznowskiandClaude Sonnet 5 7db1e0f055 Add collapsible primary UI sections (ticket 035)
Log viewer (FilterBar+LogTimeline+LogPreview), Params, Metrics, and
Dashboards can each be collapsed/expanded via a toggle next to their
existing help icon. Collapsed state persists per-section in
localStorage (ottyl.collapsedSections) and content is hidden with the
`hidden` attribute rather than unmounted, so in-progress form state
(a half-filled Metrics/Params form, in-progress Dashboards panel
edits) survives a collapse/expand cycle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:46:22 +01:00
Hugh KaznowskiandClaude Sonnet 5 dd1a0a234d Add Params declaration UI (ticket 034)
New Params panel (Log viewer / Params / Metrics / Dashboards) declares a
bare param via POST /api/params, mirroring Metrics' declare-then-list
pattern including inline 400 error surfacing. Lifted the params list from
LogPreview's own effect into App.tsx so declaring a param there updates
the Columns picker immediately, without a page reload.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:43:53 +01:00
Hugh KaznowskiandClaude Sonnet 5 41c9a3660b Add downloadable/re-uploadable custom themes (ticket 033)
Themes download as a small `:root { --c-*: ...; }` CSS file (full
canonical variable set); uploading validates that set is complete and
registers the file as a CssEntry the theme picker can select. A new
`is_theme` flag on CssEntry distinguishes theme entries from arbitrary
imported/linked CSS so they don't leak into the page unconditionally
like the existing "Configured CSS" list does — a selected custom
theme's CSS is injected only while active, with built-in html.<scheme>
classes removed so its :root override isn't outranked in the cascade.
Linked (URL) custom themes reuse the existing CSS link mechanism and
inherit its non-deletable semantics.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:41:39 +01:00
Hugh KaznowskiandClaude Sonnet 5 7bf323dd50 Add Alerts webapp UI (ticket 020)
New Alerts panel: lists rules with condition summaries and an enabled
toggle, and a condition-type-specific editor (Immediate/Threshold/NewValue/
Ratio) with client-side validation before save, reusing FilterBar's query
input styling for query-based conditions. Adds a test-notification endpoint
(POST /api/settings/alerts/test) so an ntfy topic/server can be verified
without saving a rule first, plus a docs section and help icons matching
ticket 021's pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:34:14 +01:00
Hugh KaznowskiandClaude Sonnet 5 dd3320812c Add alert rules with FilterBar-based triggers and ntfy delivery (tickets 017-019)
Adds AlertRule/AlertCondition/AlertSink models with CRUD persisted on
Settings (mirroring CssEntry's shape), per-line trigger evaluation hooked
into the engine's ingest path (Immediate/Threshold/NewValue/Ratio
conditions), and best-effort ntfy delivery spawned off the ingest hot path.

Design notes:
- Alert queries reuse FilterBar syntax but only support the
  regex()/sequence/timestamp subset (no metric[param] comparisons), since
  resolving those would require a full bucket rescan per alert per ingested
  line rather than cost proportional to new logs.
- Ratio's zero-denominator case skips evaluation for that line rather than
  treating the ratio as infinite.
- NewValue's seen-value set is in-memory only and does not survive a
  restart, matching the engine's other non-persisted runtime state.

engine::run now takes a SettingsHandle (moved from api.rs to settings.rs so
engine.rs can depend on it without a circular import) to read the current
alert rules on each ingest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:30:14 +01:00
Hugh KaznowskiandClaude Sonnet 5 758feca780 Rework colour themes as greyscale + accent-only colour (ticket 032)
light/dark are now exact lightness mirrors of one true neutral scale,
grey is that same canonical neutral scale, and each named theme
(red/green/blue/yellow/pink/orange) derives its surface/border/text
greys by desaturating its own Tailwind hue at each scale step (HSL
S->0, lightness kept), leaving saturated colour only on --c-accent*.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:21:50 +01:00
Hugh KaznowskiandClaude Sonnet 5 7694dcf120 Embed webapp into the binary with fs-embed, drop --static-dir
ottyl was requiring webapp/dist to be shipped alongside the binary and
served via ServeDir/ServeFile pointed at a --static-dir CLI arg. Embed
the built webapp at compile time instead, so ottyl is a single
self-contained executable with no runtime static directory dependency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:21:02 +01:00
Hugh KaznowskiandClaude Sonnet 5 1d1b0eee01 Add timeline start/end markers, cursor hover, and live drag readout (ticket 031)
LogTimeline now always shows the first/last bucket's index and timestamp,
a hover readout that tracks the cursor with the bucket at/before it, and
a live-updating start/end readout while dragging a selection.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:20:18 +01:00
Hugh Kaznowski b8a55b3caa Update tickets 2026-09-05 16:17:18 +01:00
Hugh Kaznowski 51e577f01e Docs, ticks, working app 2026-09-05 15:05:39 +01:00
Hugh Kaznowski 1d3bc0d0d6 Merge branch 'worktree-agent-a63474e92b05425a5'
# Conflicts:
#	Cargo.lock
#	Cargo.toml
2026-09-05 12:46:45 +01:00