Add header-level indicators of unread moderator notes#21
Merged
Conversation
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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-panelplugin outlet) next to the avatar. Visible whenevercurrentUser.mod_note_unread_count > 0; clicking it opens the user menu on the moderator-notes tab.2. Browser tab-title prefix
document.titleis prefixed with(N)when the unread count is > 0, mirroring the bell's behaviour. Implemented as a pureapplyUnreadPrefixhelper (lib/mod-note-unread-title.js) plus a wrapper around thedocument.titlesetter so route transitions never drop the prefix.Live reactivity
currentUser.mod_note_unread_count.currentUser.mod_note_unread_count— the pip (tracked-property render) and the title prefix (property observer) both clear immediately.{ delta: 1 }on a dedicated/mod-note-unread-count/{user_id}MessageBus channel fromnotify_staff_of_note. The client subscribes and bumps the local count.{ reset: true }on the same channel so multi-tab sessions stay in lockstep.Tests
spec/requests/mod_note_header_indicators_spec.rb—mod_note_unread_countacross states + MessageBus publishes on note/reply and onnotes-feed/seen.test/javascripts/unit/mod-note-unread-title-test.js— pureapplyUnreadPrefix/stripUnreadPrefixmatrix.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, andCHANGELOG.md.APIs used
before-header-panelplugin outlet (stable Discourse outlet just before the user-menu panel) —@ember/owner getOwnerlookup ofservice:header/service:header-statefor opening the user menu, with a DOM-click fallback for older builds.document.titleproperty descriptor; observed viacurrentUser.addObserver('mod_note_unread_count', ...)./mod-note-unread-count/{user_id}(independent from/notification-alert/which drives the bell).🤖 Generated with Claude Code