Skip to content

[Notifications] Move notification settings into the Notifications widget - #4084

Open
idaiv wants to merge 4 commits into
2026.xfrom
notifications-settings-section
Open

[Notifications] Move notification settings into the Notifications widget#4084
idaiv wants to merge 4 commits into
2026.xfrom
notifications-settings-section

Conversation

@idaiv

@idaiv idaiv commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

What

Notification settings were a second top-level widget, reachable only from a gear icon in the user menu. They are now a section of the Notifications widget, next to the inbox.

Why this shape

Studio already does section tabs inside a widget — user-detail-tab.tsx (settings / workspaces / key-bindings / references), robots-txt, perspective-editor, classification-store-config. The alternatives were worse fits for this content:

  • Sidebar entry — the settings matrix wants ~700px (the table caps at 900px, channel columns are 110–130px, descriptions run to 52ch) against SIDEBAR_CONTENT_WIDTHS.large of 432px. It would have needed a redesign into a narrow vertical form, not a move.
  • Modal — settings is a deliberate save/discard surface with a dirty draft; Studio's modals here are one-shot actions, and backdrop/Esc dismissal fights unsaved changes.

The deciding constraint was toolbars: the inbox pages and clears, settings saves and discards. So each section renders its own ContentLayout, and only the title and Send button are shared. The filter sidebar stays scoped to the inbox.

Notable details

  • Panes stay mounted — deliberately no destroyInactiveTabPane (the opposite of the user-detail-tab precedent), because destroying the settings pane on a tab switch silently discards an unsaved draft.
  • No layout migration. A persisted tab whose id has no registered restorer is dropped on both persist and restore (widget-manager-persistence.ts, widget-restorer.tsx), so users with the old Notification Settings tab open have it closed for them.
  • Section deep links go through notifications-ui-slice, not widget config — openMainWidget only selects an existing node and won't push new attributes into an open widget. This mirrors the existing requestExpandNotification pattern and its comment. The popup's "View" now also requests the inbox, so a notification can't expand on a hidden section.
  • NOTIFICATION_SETTINGS is removed from the module barrel. Nothing in studio-ui, collab-bundle or copilot-bundle referenced it, but it was a public export — flagging in case a third-party bundle consumes it.

Design-system alignment

  • Title + Send grouped in a Flex so Send sits beside the title, matching Bookmark Lists, Collections, Predefined Properties and Document Types. Header defaults justify to space-between, which is why two direct children pushed apart.
  • Channel warning icon aligned with its label and coloured via Icon's colorToken prop with colorWarning — the token already used for warning icons in modal.styles.tsx. Its wrapper span needed inline-flex because the tooltip's ref-holding span isn't a flex container, so the 16px icon div fell to the text baseline.
  • Spacing moved onto the token scale: marginSM for the avatar's top margin, paddingSM (12px) for the list's top padding.

Testing

  • 4 new reducer tests for the section request (token progression, independence from the expand request); 56 tests pass across the notifications module.
  • Verified in a running instance: gear-free user menu, deep link landing on Settings, a dirty draft surviving an Inbox↔Settings round trip, save round-tripping to the DB, and pagination across 47 seeded notifications (20/20/7, size changer, disabled arrows at the bounds).

Note on local verification: the full-project npm run lint and tsc --noEmit are OOM-killed in my dev container (6 GiB cgroup with the Pimcore stack resident) — both exit 137. Lint on every changed file is clean, the notifications suite passes, and npm run build-app succeeds. CI is the real gate for the two full-project checks.

Notification settings used to be a second top-level widget, reachable only
from a gear icon in the user menu. It is now a section of the Notifications
widget itself, alongside the inbox.

- Add a tabbed widget shell (Inbox / Settings). Each section renders its own
  ContentLayout, because their toolbars have nothing in common (the inbox
  pages and clears, settings saves and discards) and the filter sidebar
  belongs to the inbox alone. Panes stay mounted so switching sections
  cannot drop an unsaved settings draft.
- Drop the standalone `notification-settings` widget and its
  NOTIFICATION_SETTINGS config. Persisted layouts referencing it are closed
  automatically by the widget restorer, so no migration is needed.
- Request a section through notifications-ui-slice rather than widget config:
  an already-open widget keeps its original config. The user menu row opens
  the inbox and the popup's "View" does too, so a notification can no longer
  expand on a hidden section.
- Remove the user-menu gear; settings are reached from the widget's own
  Settings tab.
- Align the channel warning icon with its label and colour it with the
  colorWarning token via Icon's colorToken prop.
- Header and spacing corrections: group the title and Send button in a Flex
  so Send sits beside the title (matching Bookmark Lists, Collections,
  Document Types), drop the header's bottom padding, and give the list 12px
  top padding via the marginSM/paddingSM scale.
- Use the marginSM token for the profile avatar's top margin.

Adds notifications.tab.inbox / notifications.tab.settings in all 7 locales
and four reducer tests for the new section request.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 4, 2026 11:35
@idaiv idaiv added this to the 2026.3.0 milestone Sep 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The public settings export needs a compatibility plan, and the new tab-request consumer lacks component-level coverage.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Moves notification settings into a tabbed Notifications widget alongside the inbox.

Changes:

  • Adds Inbox/Settings tabs and section-request state.
  • Consolidates widget registration, header, and send action.
  • Updates translations, styling, popup navigation, and tests.
File summaries
File Description
translations/studio.sv.yaml Adds Swedish tab labels.
translations/studio.no.yaml Adds Norwegian tab labels.
translations/studio.it.yaml Adds Italian tab labels.
translations/studio.fr.yaml Adds French tab labels.
translations/studio.es.yaml Adds Spanish tab labels.
translations/studio.en.yaml Adds English tab labels.
translations/studio.de.yaml Adds German tab labels.
assets/js/src/core/modules/notifications/widget-configs.ts Removes the standalone settings widget config.
assets/js/src/core/modules/notifications/user-menu-item.tsx Removes the settings gear and opens Inbox.
assets/js/src/core/modules/notifications/settings/notification-settings.styles.ts Aligns warning icons.
assets/js/src/core/modules/notifications/settings/notification-settings-view.tsx Applies warning color and alignment.
assets/js/src/core/modules/notifications/settings/notification-settings-container.tsx Removes the redundant settings heading.
assets/js/src/core/modules/notifications/notifications-widget.tsx Adds the consolidated tabbed widget.
assets/js/src/core/modules/notifications/notifications-view.tsx Moves shared header and modal outward.
assets/js/src/core/modules/notifications/notifications-ui-slice.ts Adds section navigation requests.
assets/js/src/core/modules/notifications/notifications-ui-slice.test.ts Tests section-request reducer behavior.
assets/js/src/core/modules/notifications/notification-popup/notification-popup-content.tsx Selects Inbox before expanding notifications.
assets/js/src/core/modules/notifications/index.tsx Registers only the consolidated widget.
assets/js/src/core/modules/app/base-layout/left-sidebar-view.styles.ts Uses tokenized avatar spacing.
Review details
  • Files reviewed: 19/19 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

import { NOTIFICATIONS } from './widget-configs'

export { NOTIFICATIONS, NOTIFICATION_SETTINGS } from './widget-configs'
export { NOTIFICATIONS } from './widget-configs'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this and it isn't source-breaking — NOTIFICATION_SETTINGS was never reachable by third-party bundles, so a compatibility shim would be dead code.

The public federated entry point is ./modules/notificationsjs/src/sdk/modules/notifications/index.ts (rsbuild.sdk.config.ts:144). That SDK barrel exports the notification list, the API slice, the dynamic-type definitions/registries and the payload utils — it has never re-exported widget-configs or this core index.tsx. NOTIFICATION_SETTINGS lived only in the internal core barrel behind the @Pimcore/* alias, which is resolved inside studio-ui's own build and is not available to bundles (collab-bundle, for example, has no @Pimcore alias in its rsbuild/tsconfig and imports exclusively from @pimcore/studio-ui-bundle/*).

So the removal is internal-only. Keeping the config as a deprecated alias would actually be worse than removing it: it is a WidgetManagerTabConfig pointing at component notification-settings, which is no longer registered, so openMainWidget(NOTIFICATION_SETTINGS) would hit the "Widget not found" path in widget-manager-factory.tsx rather than degrade gracefully.

Happy to reconsider if the SDK barrel is meant to re-export it — that would make it public and this a genuine break.

Comment on lines +51 to +55
useEffect(() => {
if (sectionRequest !== null) {
setActiveSection(sectionRequest.section)
dispatch(clearNotificationsSectionRequest())
}
Comment on lines +49 to +50
// Deep link from elsewhere in the app (the user menu's gear). An already-open widget keeps its
// original config, so a section cannot be requested through it — this signal is read live.
idaiv and others added 3 commits September 4, 2026 11:48
…mment

Addresses the Copilot review:

- Add a NotificationsWidget component test. The reducer tests covered the
  slice but nothing exercised the consumer, so selecting the requested
  section and acknowledging the request could regress silently. The Tabs
  stub honours destroyInactiveTabPane, so the round-trip test fails if that
  prop is ever added here — verified by injecting it.
- The section-request comment described the user menu's gear, which this
  branch removes; describe section requests generically instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Sep 4, 2026

Copy link
Copy Markdown

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.

2 participants