Skip to content

feat(notifications): redesign the console Notifications pane (channels, alert-text editor, quiet hours) - #583

Merged
badbread merged 3 commits into
mainfrom
feat/notifications-pane-redesign
Aug 8, 2026
Merged

feat(notifications): redesign the console Notifications pane (channels, alert-text editor, quiet hours)#583
badbread merged 3 commits into
mainfrom
feat/notifications-pane-redesign

Conversation

@badbread

@badbread badbread commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Fixes #582.

Redesign of the console Notifications pane (server + web console). Scope is the Notifications pane; the Home Assistant camera-editor rework and the Android embed are out of scope for this PR.

WU-1 Channel visibility + global round-trip (server + console)

  • Admins now list all channels with owner attribution (db::list_all_notification_channels, a LEFT JOIN users); non-admin scope (own only) is unchanged. This makes a channel created under another account visible, testable, and removable, while the engine fan-out (every enabled channel) is untouched.
  • ChannelResponse gains global (bool) and owner_username. UpdateChannelRequest / UpdateChannelParams gain an admin-only owner toggle (globaluser_id = NULL, or claim ownership). A non-admin supplying global on update is rejected (403). The console shows an owner chip (Global / Yours / owner name) and only renders the global checkbox for admins (gated via GET /auth/me).

WU-3 System-alert text editor

  • The per-row inline "Customize alert text" block is replaced with a compact "✎ Customize" button plus a "Customized" chip, opening one shared modal (#sysalert-editor-modal, reusing the existing .modal-overlay pattern).
  • The modal holds the message textarea, a conditional Title field (shown only when a Pushover/ntfy destination is configured, named in the hint), a per-alert token legend (click-to-insert with sample values), and a live preview rendered as a generic notification card with a sample-image slot gated on real delivery (image-capable channel + an event type that carries an image, currently plate_watchlist_hit, with an SVG fallback).
  • Save issues the existing per-alert PUT, decoupled from the row-toggle bulk save (notifSaveSystemAlerts no longer reads or sends templates).

WU-4 Quiet hours

  • Both quiet-hours pairs (per-user rules and system alerts) become whole-hour <select>s ("— off —" + 24 friendly 12h options) inside collapsed details.detail-section sections with live-state summaries; per-camera overrides collapse too.
  • Server-side 0..=23 validation added to do_upsert_rule and put_notification_settings; the engine-side clamp stays as defense, and the console renders any legacy out-of-range value as "— off —" with a warning line. Copy states hours are server local time.

WU-6 Motion-cache polish

  • The per-camera ring panel surfaces updated_at as "as of Ns ago" and a header hint that 0 seg / 0 B during or after motion is normal (no footage lost).

Tests

services/api/tests/notification_pane.rs: quiet-hours range validation (rules + system settings), admin-lists-all-channels with owner attribution, global round-trip on update, non-admin cannot toggle global. The shared test harness caps DB_POOL_SIZE at 4 so concurrent tests don't exhaust a stock max_connections.

Gate run on a fresh throwaway Postgres: cargo fmt --all --check, cargo clippy --all-targets -D warnings, and cargo test --workspace all green (every binary 0 failed); the new DB-backed tests confirmed to run (not skipped) with both DATABASE_URL and TEST_DATABASE_URL set. node --check passes on the extracted admin.html script.

Docs

docs/DECISIONS.md entry (modal editor + quiet-hours validation + admin listing), docs/COMPONENT-MAP.md notifications row, and a minimal docs/AI-INSTALL.md note on the additive global/owner_username response fields (flagging that AI-INSTALL is being audited separately).

…s, alert-text editor, quiet hours)

Notifications-pane UX overhaul (server + web console):

WU-1 Pushover/global channel visibility
- The engine fans out to every enabled channel regardless of owner, but the
  console listed only the caller's own + global channels, hiding a channel
  created under another account. Admins now list ALL channels with owner
  attribution (list_all_notification_channels, LEFT JOIN users); non-admin
  scope (own only) unchanged.
- ChannelResponse gains `global` (bool) and `owner_username`; the global
  checkbox was cosmetic (missing field) and a no-op on edit (UpdateChannelRequest
  dropped it). UpdateChannelRequest/Params gain an admin-only owner toggle;
  a non-admin supplying `global` on update is rejected (403).

WU-3 System-alert editor
- Replace the per-row inline "Customize alert text" wall with a compact
  "Customize" button + "Customized" chip and ONE shared modal
  (#sysalert-editor-modal): message textarea, conditional Title (only when a
  Pushover/ntfy destination is configured, named in the hint), a per-alert
  token legend (click-to-insert), and a live preview rendered as a generic
  notification card with a sample-image slot gated on real delivery.
- Save issues the per-alert PUT, decoupled from the row-toggle bulk save
  (notifSaveSystemAlerts no longer reads/sends templates).

WU-4 Quiet hours
- Both quiet-hours pairs become whole-hour <select>s (— off — + 24 friendly
  12h options) inside collapsed details.detail-section with live summaries;
  per-camera overrides collapse too.
- Server-side 0..=23 validation (do_upsert_rule, put_notification_settings):
  a value like 2200 was stored verbatim and clamped at read time to a
  zero-width window, so quiet hours silently never fired. Rejected now; the
  console renders any legacy bad value as "— off —" with a warning.

WU-6 Motion-cache polish
- Surface the per-camera updated_at as "as of Ns ago" and a header hint that
  0 seg / 0 B during or after motion is normal.

Tests (services/api/tests/notification_pane.rs): quiet-hours range validation
(rules + system settings), admin-lists-all-channels with owner attribution,
global round-trip on update, non-admin cannot toggle global. The shared test
harness caps DB_POOL_SIZE at 4 so concurrent tests don't exhaust a stock
max_connections.

Docs: DECISIONS.md entry (modal editor + quiet-hours validation + admin
listing), COMPONENT-MAP notifications row, AI-INSTALL channels-API note.

Signed-off-by: badbread <badbread@users.noreply.github.com>
…o modal)

Replace the per-alert alert-text affordance in the console's System alerts
table. The compact "Customize" button + "Customized" chip that opened a shared
.modal-overlay is gone; each alert row now shows a small inline pencil (✎) icon
on its control row, right next to "Bypass quiet hours". Clicking it expands the
editor in place as a panel directly under that row (no modal), and clicking it
again (or another alert's icon) collapses it, so only one editor is open at a
time and the list reads as a clean list with a tiny icon per row.

The icon carries the customized state itself (accent border + a dot) when a
template override is set, so the separate chip is no longer needed. All of the
editor content and behavior is unchanged: message textarea, conditional Title
(Pushover/ntfy only), per-alert token legend with samples, live preview,
Restore default, and the per-alert PUT save decoupled from the bulk row-toggle
save.

Update the same-day DECISIONS.md entry so the modal is not "restored".

Signed-off-by: badbread <badbread@users.noreply.github.com>
@badbread

badbread commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Adjusted the per-alert alert-text affordance to match the requested "little icon to click, inline with Bypass quiet hours".

What changed (admin.html):

  • Removed the compact "Customize" button + "Customized" chip and the shared .modal-overlay dialog (#sysalert-editor-modal deleted).
  • Each System-alerts row now has a small inline pencil (✎) icon on its control row, right next to "Bypass quiet hours" (alongside the enable toggle / threshold / bypass).
  • Clicking the icon expands the editor in place, a panel directly under that row (_sysAlertEditorBody rendered into a colspan row); clicking it again or another alert's icon collapses it. Only one editor is open at a time.
  • The icon carries the customized state itself (accent border + a dot) when a template override is set, so the separate chip is gone and the list reads as a clean list with a tiny icon per row.
  • All editor content/behavior is unchanged: message textarea, conditional Title (Pushover/ntfy only), per-alert token legend with samples, live preview, Restore default, and the per-alert PUT save decoupled from the bulk row-toggle save.

Verification:

  • node --check on the extracted <script> block: OK. No dangling references to the removed sysAlertOpenEditor / #sysalert-editor-modal / sae-modal-* ids.
  • cargo check -p crumb-api on the build box (confirms the include_str! embed still builds): OK.

DECISIONS.md: updated the same-day entry, the "one shared modal" decision is now "inline ✎ icon opens the editor in place (no modal)", with a note not to restore the modal.

@badbread
badbread merged commit 4170d37 into main Aug 8, 2026
8 checks passed
@badbread
badbread deleted the feat/notifications-pane-redesign branch August 8, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Notifications pane: hidden channels, silent quiet-hours no-op, and alert-text/quiet-hours UX

1 participant