Skip to content

Add header-level indicators of unread moderator notes#21

Merged
Shalom-Karr merged 2 commits into
masterfrom
feat/mod-note-header-indicators
May 20, 2026
Merged

Add header-level indicators of unread moderator notes#21
Shalom-Karr merged 2 commits into
masterfrom
feat/mod-note-header-indicators

Conversation

@Shalom-Karr

Copy link
Copy Markdown
Owner

Adds two header-level indicators of the moderator-notes shield-tab's own unread count, so staff see they have unread notes without opening the user menu.

What

1. Header shield pip

A staff-only shield pip rendered in the page header (via the before-header-panel plugin outlet) next to the avatar. Visible whenever currentUser.mod_note_unread_count > 0; clicking it opens the user menu on the moderator-notes tab.

2. Browser tab-title prefix

document.title is prefixed with (N) when the unread count is > 0, mirroring the bell's behaviour. Implemented as a pure applyUnreadPrefix helper (lib/mod-note-unread-title.js) plus a wrapper around the document.title setter so route transitions never drop the prefix.

Live reactivity

  • On page load the count comes from the bootstrapped currentUser.mod_note_unread_count.
  • When the staff member opens the shield tab the panel zeroes currentUser.mod_note_unread_count — the pip (tracked-property render) and the title prefix (property observer) both clear immediately.
  • When a new note or reply arrives, the server publishes { delta: 1 } on a dedicated /mod-note-unread-count/{user_id} MessageBus channel from notify_staff_of_note. The client subscribes and bumps the local count.
  • Marking the feed as seen also publishes { reset: true } on the same channel so multi-tab sessions stay in lockstep.

Tests

  • spec/requests/mod_note_header_indicators_spec.rbmod_note_unread_count across states + MessageBus publishes on note/reply and on notes-feed/seen.
  • test/javascripts/unit/mod-note-unread-title-test.js — pure applyUnreadPrefix / stripUnreadPrefix matrix.
  • spec/system/mod_note_header_indicators_spec.rb — header pip + (N) title prefix render for staff with unread notes, clear after the shield tab is opened, never render for a regular user (screenshots 190-192).

Docs

Updated docs/moderator-notes-tab.md, docs/features.md, docs/testing.md, and CHANGELOG.md.

APIs used

  • Header pip: before-header-panel plugin outlet (stable Discourse outlet just before the user-menu panel) — @ember/owner getOwner lookup of service:header / service:header-state for opening the user menu, with a DOM-click fallback for older builds.
  • Title prefix: pure helpers + a wrapper around the document.title property descriptor; observed via currentUser.addObserver('mod_note_unread_count', ...).
  • Live updates: MessageBus channel /mod-note-unread-count/{user_id} (independent from /notification-alert/ which drives the bell).

🤖 Generated with Claude Code

Shalom-Karr and others added 2 commits May 19, 2026 20:50
Adds two header-level indicators of the moderator-notes shield-tab's own
unread count, so staff see they have unread notes without opening the
user menu.

- A staff-only shield pip rendered in the page header next to the avatar
  via the `before-header-panel` plugin outlet. Visible whenever
  `currentUser.mod_note_unread_count > 0`; clicking it opens the user
  menu on the shield tab.
- A `(N) original-title` prefix on `document.title`, mirroring the
  bell. Implemented as a pure `applyUnreadPrefix` helper plus a
  `document.title` setter wrapper so route transitions don't drop the
  prefix.

Both indicators are reactive: the count updates on initial bootstrap,
drops to 0 when the staff member opens the shield tab (the panel zeroes
`currentUser.mod_note_unread_count` after `POST /notes-feed/seen`),
and bumps live on new notes via a dedicated MessageBus channel
`/mod-note-unread-count/{user_id}` — published from
`notify_staff_of_note` (a `{ delta: 1 }` per recipient) and from
`notes_feed_seen` (a `{ reset: true }` so multi-tab sessions stay
in lockstep).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…r prefix

Two robustness fixes for the system spec failures:

- The header pip now drives its render off a local `@tracked unreadCount`
  kept in sync with `currentUser.mod_note_unread_count` via a property
  observer + a direct MessageBus subscription on
  `/mod-note-unread-count/{user_id}`. This insulates the pip's
  reactivity from the User-model property-tracking quirks that differ
  across Discourse versions — the panel's `set('mod_note_unread_count', 0)`
  after `notes-feed/seen` now reliably hides the pip.
- The title-prefix initializer now uses a MutationObserver on the
  <title> node to reassert the `(N)` prefix every time Discourse's
  `document-title` service rewrites the title (on route transitions).
  Recursion is guarded with an `applying` flag so reassertions don't
  loop.

The system spec also got two small hardenings: the prefix test now visits
a topic so a stable bare title is in flight before polling, and the
clear test waits on the pip's own `.mod-note-header-pip-count` text
falling to zero (the panel's seen-ack is async).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Shalom-Karr
Shalom-Karr merged commit 3a39619 into master May 20, 2026
4 checks passed
@Shalom-Karr
Shalom-Karr deleted the feat/mod-note-header-indicators branch May 20, 2026 01:19
Shalom-Karr added a commit that referenced this pull request May 20, 2026
Adds 190-192 captured from PR #21's system specs:
- 190: header shield-tab pip visible with menu closed
- 191: browser-tab title prefix on a topic with an unread note
- 192: indicators cleared after the user opens the notes tab

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant