Notifications: FE prep for real message content - #154
Conversation
- Strip markdown/HTML artifacts from title/description defensively on FE (drawer tiles, /notifications table, browser OS toast); newlines are preserved so the full-text hover tooltip keeps paragraph structure - Use the NATS payload createdAt for live notifications instead of local Date.now(), so live tiles match the stored record after reload - Table: real title leads the first column; the context-derived kind label moved to the details column (it no longer masks real content) - Route table rows through the shared strip/normalization instead of raw Relay edge fields Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughNotification text is sanitized across mapped and live notification paths. Notification timestamps use normalized or payload values. The table displays the actual title and shows the notification type before the description. ChangesNotification normalization and display
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/graphql/notifications/notifications-helpers.ts`:
- Line 241: Update the normalization regex in the notification helper to avoid
treating underscores adjacent to word characters as italic delimiters,
preserving identifiers such as job_status_failed while still stripping valid
underscore-delimited markup. Add coverage for both identifier text and
snake_case content.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 8db850b4-b5d8-4213-a528-b6ac9f56b540
📒 Files selected for processing (4)
src/app/(app)/notifications/components/notifications-columns.tsxsrc/app/(app)/notifications/components/notifications-section.tsxsrc/app/components/notifications/notifications-data-provider.tsxsrc/graphql/notifications/notifications-helpers.ts
…nt ticket nav) BE counterpart (open PRs): openframe-oss-lib#1741, openframe-saas-lib#707, openframe-saas-tenant#2552. - schema.graphql: additive sync with the BE PRs - ticketTitle on ticket-bearing contexts, nullable ticketId/ticketNumber on ClientAiMessageContext, NotificationSettings.contentSuppressed, updateNotificationContentSuppression mutation (refetch via fetch-schema once BE deploys) - drawer/section fragments select ClientAiMessageContext dialogId + ticketId (aliased clientTicketId - relay refuses to merge ID! with ID); the mapper folds it into meta.ticketId - CLIENT_AI_MESSAGE notifications with a ticket now navigate to the ticket's client chat tab (previously no action) - Notification settings modal: tenant-wide "Hide Message Content" switch, visible to ADMIN/OWNER only, saved via the dedicated mutation and only when the value changed Deployment ordering: FE must not deploy before the BE PRs - the new field selections fail GraphQL validation against the old schema. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s schema BE main renamed NotificationSettings.pushEnabled to enabled and added typeSettings (per-type toggles subtask); the old field no longer exists, so the settings query - and with it the new suppression toggle - would fail GraphQL validation. Minimal migration: SDL synced from the BE PR (NotificationSettingGroup enum, NotificationTypeSetting type/input, new updateNotificationSettings signature), query/mutations select enabled, the modal state renamed. typeSettings is intentionally not sent - omitting it keeps the stored group overrides; the per-group checkboxes UI stays in the sibling subtask. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… structure Resolution notes: - schema.graphql: main's freshly fetched SDL as base, with the merged BE PR additions re-applied (ticketTitle on six ticket-bearing contexts, nullable ticketId/ticketNumber/ticketTitle on ClientAiMessageContext, NotificationSettings.contentSuppressed, updateNotificationContentSuppression) - fragments: main moved the shared node selection into notification-fields.ts; the ClientAiMessageContext selection (dialogId + aliased clientTicketId) now lives there, drawer/section relay files taken from main as-is - notifications-helpers: main's generated-type mapper signature kept, the hand-written NotificationNodeShape dropped; markup strip stays - notifications-section rows: main's read-once readNotificationNode structure kept, with stripNotificationMarkup applied to the row title/description - settings surface: main deleted the notification-settings modal, its relay files and the profile-card entry point; the deletion is accepted, including our suppression-toggle UI and master-switch migration - that UI returns as a follow-up per the new Figma design attached to ClickUp 86ajn8hpg Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…_USER The new Figma notification blocks include a first-class escalated-ticket tile, and the context already exists in the schema, but it was neither selected in the shared fragment nor mapped in navigation - the tile rendered its text yet was not clickable and never auto-read on the ticket page, unlike every neighboring ticket tile. Select its ticketId (dialogId stays unselected for the same nullability-merge reason as TicketReopenedContext) and route it to Ticket Details. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The suppression parts of openframe-oss-lib#1741 (contentSuppressed on NotificationSettings, updateNotificationContentSuppression) were removed from the PR before it merged - verified against the merge commit ce246608 - so the hand-patched SDL described an API that does not exist. enabled/typeSettings stay: they are live on BE main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e mapper - schema.graphql taken from main wholesale - it is now freshly introspected from the deployed backend and already carries everything the fragments select (ticketTitle on six contexts, ClientAiMessageContext ticketId/ticketNumber, TicketEscalatedByUserContext) with canonical docstring formatting; correctly has no content-suppression fields - mapper: main made context nullable (context-less rows on the new emission path) - kept its optional chaining and re-applied clientTicketId in the ticket-id chain plus the markup strip on title/description Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ClickUp: https://app.clickup.com/t/86ajn8hpg (parent PSA-loop task 86ajn8hmp)
FE side of "Notifications do not show the real message content". BE counterpart (merged): openframe-oss-lib#1741, openframe-saas-lib#707, openframe-saas-tenant#2552.
What this PR does
Content rendering (BE-independent):
stripNotificationMarkup()innotifications-helpers.tsremoves tags, links/images (keeping their text), bold/italic/strike, code, headings, blockquotes and list markers fromtitle/description. Applied inmapNotificationNode(drawer tiles, popups), the NATS live handler (live tiles + browser OS toast) and the/notificationstable rows. Newlines are preserved so the full-text hover tooltip keeps its paragraph structure.createdAt- live notifications use the payload timestamp instead of stamping localDate.now(); local time remains the fallback.BE schema adoption (per the merged BE PRs):
schema.graphql- additive sync:ticketTitleon ticket-bearing contexts, nullableticketId/ticketNumber/ticketTitleonClientAiMessageContext.notification-fields.ts) selectsClientAiMessageContext { dialogId, clientTicketId: ticketId }(aliased - relay refuses to mergeID!withID); the mapper folds it intometa.ticketId.CLIENT_AI_MESSAGEnotifications with a ticket open the ticket's client chat tab;TICKET_ESCALATED_BY_USER(a first-class tile in the new Figma blocks) now selectsticketIdand routes to Ticket Details.Merge with main (
ee035d5)Main restructured the same area while this branch was open; the merge re-applies the changes onto the new structure (shared
notification-fields.tsfragment,readNotificationNoderead-once rows, generated-type mapper). The notification-settings surface deleted on main stays deleted.Content suppression: dropped by BE before merge
Earlier commits of this branch carried a tenant-wide "Hide Message Content" toggle and its schema. The suppression parts of openframe-oss-lib#1741 were cut from the PR before it merged (verified against merge commit ce246608: no
contentSuppressed, noupdateNotificationContentSuppression, no redactor on main) - BE dropped notification settings "for now". All suppression traces are removed from this PR;enabled/typeSettingsSDL stays as it is live on BE main.Verification (QA, real data)
npm run relay,npm run generate-enums,npm run type-check, Biome - clean. No console errors.🤖 Generated with Claude Code