Skip to content

feat: Add HeaderNotificationsSlot to enable notifications tray default ON#663

Merged
brian-smith-tcril merged 10 commits intoopenedx:masterfrom
awais-ansari:aansari/notifications-79
Apr 9, 2026
Merged

feat: Add HeaderNotificationsSlot to enable notifications tray default ON#663
brian-smith-tcril merged 10 commits intoopenedx:masterfrom
awais-ansari:aansari/notifications-79

Conversation

@awais-ansari
Copy link
Copy Markdown
Contributor

@awais-ansari awais-ansari commented Mar 6, 2026

Ticket

Summery
Adds a new HeaderNotificationsSlot that renders NotificationsTray (from @edx/frontend-plugin-notifications) by default across Desktop, Learning, and Studio headers. This makes notifications available out-of-the-box for every Open edX instance, while allowing operators to disable or customize them via plugin slot configuration or the existing backend waffle flag.

Motivation
Currently, notifications in the header are enabled through tutor-contrib-platform-notifications, which injects NotificationsTray into 3 separate plugin slots:

Slots
org.openedx.frontend.layout.header_desktop_secondary_menu.v1 (Desktop Header)
org.openedx.frontend.layout.studio_header_search_button_slot.v1 (Studio Header)
org.openedx.frontend.layout.header_learning_help.v1 (Learning Header)

Problems with already implemented tutor-contrib-platform-notifications approach:

  • Not default-on. Community instances must install and configure tutor-contrib-platform-notifications.
  • Non-Tutor deployments need manual env.config.jsx wiring.
  • Mobile headers are missed. Neither LMS Mobile nor Studio Mobile has a notification bell.
  • 3 separate slot configs for one feature. Each slot is semantically unrelated to notifications.

Implementation

New slot

  • Slot ID: org.openedx.frontend.layout.header_notifications_tray.v1
  • Alias: header_notifications_tray
  • Default content: NotificationsTray from @edx/frontend-plugin-notifications

v1/v2 split on three parent slots
Rather than embedding HeaderNotificationsSlot directly as a second child of an existing slot (which would break operators using the widget.content.* Modify pattern. React.isValidElement only works for single children), each affected slot is split into a v1/v2 pair.

Slot hierarchy

Desktop Header
└── header_desktop_secondary_menu.v2
    ├── header_notifications_tray.v1  ← new
    └── header_desktop_secondary_menu.v1  (menu items)

Learning Header
└── learning_header_actions.v2
    ├── header_notifications_tray.v1  ← new
    └── learning_header_actions.v1  (help link)

Studio Header
└── studio_header_actions.v2
    ├── header_notifications_tray.v1  ← new
    └── studio_header_actions.v1  (search button)

v2 is the default export consumed by header components.

How Operators Can Disable Notifications

Option 1: Plugin slot config (env.config.jsx)

import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
  pluginSlots: {
    'org.openedx.frontend.layout.header_notifications_tray.v1': {
      keepDefault: false,
      plugins: [],
    },
  },
};
export default config;

Option 2:
Backend waffle flag - NotificationsTray is self-gating. It returns empty when the backend waffle flag is True. DISABLE_NOTIFICATIONS: True. Backend openedx/openedx-platform#38073

Backward Compatibility

  • The v1 slot IDs (and their aliases) are unchanged. Existing operator configs continue to work.
  • The desktop_secondary_menu_slot alias is preserved on v1.
  • Operators using PLUGIN_OPERATIONS.Modify with widget.content.menu on v1 are unaffected.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.97%. Comparing base (af6fe9f) to head (c58ccd6).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #663      +/-   ##
==========================================
+ Coverage   72.22%   72.97%   +0.75%     
==========================================
  Files          56       60       +4     
  Lines         504      518      +14     
  Branches      108      108              
==========================================
+ Hits          364      378      +14     
  Misses        137      137              
  Partials        3        3              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@awais-ansari
Copy link
Copy Markdown
Contributor Author

I have tested it on LMS, Studio, and Mobile View.

Screenshot 2026-03-09 at 4 13 38 PM Screenshot 2026-03-09 at 4 13 47 PM Screenshot 2026-03-09 at 4 14 08 PM Screenshot 2026-03-09 at 4 14 52 PM

@brian-smith-tcril
Copy link
Copy Markdown
Contributor

I'd like to break down the problems listed with the current approach a bit:

Mobile headers are missed entirely. Neither the LMS Mobile Header nor the Studio Mobile Header have notifications, so users on narrow viewports don't see the notification bell.

I think this part should be a separate PR. I'm not sure if adding a bell to the already very limited space in the mobile header makes sense. It'd be good to get some design/product opinions on this feature.

Not default-on. Community instances must install and configure tutor-contrib-platform-notifications to get notifications. Non-Tutor deployments require manual env.config.jsx configuration.

It is my understanding that this is the main motivation for this change. Overall I agree with this PR's approach as a solution to this.

3 separate slot configs. Operators must configure 3 different slot IDs to enable one feature, and each slot is semantically unrelated to notifications (secondary menu, search button, help link).

I understand why this is frustrating, but the overall vision for slots is that they refer to places things can be put, not the default content in those places. I also know that isn't currently the case for quite a few existing slots (including org.openedx.frontend.layout.studio_header_search_button_slot.v1 and org.openedx.frontend.layout.header_learning_help.v1).

One of the reasons for this is that "where it goes" gives site operators more granular control over how each page/part of a page looks, instead of having one slot change how multiple pages/parts of pages look.

With that in mind, I think there's a way to get the best of both worlds here:

  • org.openedx.frontend.layout.header_desktop_secondary_menu.v1
    • Add the notifications slot to the default content of the desktop secondary menu slot, before the existing default content (to match the behavior of the tutor plugin that uses priority 10). This will make it so site operators can remove the notification bell from this menu specifically if desired using org.openedx.frontend.layout.header_desktop_secondary_menu.v1. By putting HeaderNotificationsSlot in here instead of NotificationsTray directly, the "one slot for notifications" functionality can be preserved.
const DesktopSecondaryMenuSlot = ({
  menu,
}) => (
  <PluginSlot
    id="org.openedx.frontend.layout.header_desktop_secondary_menu.v1"
    idAliases={['desktop_secondary_menu_slot']}
    slotOptions={{
      mergeProps: true,
    }}
  >
+  <HeaderNotificationsSlot />
    <DesktopHeaderMainOrSecondaryMenu menu={menu} />
  </PluginSlot>
);
  • org.openedx.frontend.layout.studio_header_search_button_slot.v1
    • For this one, I think it would make sense to make a new slot that wraps both the search button slot and the new notifications slot. This would ensure anyone currently using org.openedx.frontend.layout.studio_header_search_button_slot.v1 can continue to do so, the new notifications slot will work as intended, and site operators will have the option to modify the area with the search and notification buttons in studio only without touching the LMS if they'd like.
  • org.openedx.frontend.layout.header_learning_help.v1
    • Same idea here as the search button slot.

Hopefully these thoughts/suggestions make sense! Please let me know if you have any questions!

@bmtcril bmtcril requested review from brian-smith-tcril and removed request for brian-smith-tcril March 11, 2026 14:14
@awais-ansari
Copy link
Copy Markdown
Contributor Author

I'd like to break down the problems listed with the current approach a bit:

Mobile headers are missed entirely. Neither the LMS Mobile Header nor the Studio Mobile Header have notifications, so users on narrow viewports don't see the notification bell.

I think this part should be a separate PR. I'm not sure if adding a bell to the already very limited space in the mobile header makes sense. It'd be good to get some design/product opinions on this feature.

Not default-on. Community instances must install and configure tutor-contrib-platform-notifications to get notifications. Non-Tutor deployments require manual env.config.jsx configuration.

It is my understanding that this is the main motivation for this change. Overall I agree with this PR's approach as a solution to this.

3 separate slot configs. Operators must configure 3 different slot IDs to enable one feature, and each slot is semantically unrelated to notifications (secondary menu, search button, help link).

I understand why this is frustrating, but the overall vision for slots is that they refer to places things can be put, not the default content in those places. I also know that isn't currently the case for quite a few existing slots (including org.openedx.frontend.layout.studio_header_search_button_slot.v1 and org.openedx.frontend.layout.header_learning_help.v1).

One of the reasons for this is that "where it goes" gives site operators more granular control over how each page/part of a page looks, instead of having one slot change how multiple pages/parts of pages look.

With that in mind, I think there's a way to get the best of both worlds here:

  • org.openedx.frontend.layout.header_desktop_secondary_menu.v1

    • Add the notifications slot to the default content of the desktop secondary menu slot, before the existing default content (to match the behavior of the tutor plugin that uses priority 10). This will make it so site operators can remove the notification bell from this menu specifically if desired using org.openedx.frontend.layout.header_desktop_secondary_menu.v1. By putting HeaderNotificationsSlot in here instead of NotificationsTray directly, the "one slot for notifications" functionality can be preserved.
const DesktopSecondaryMenuSlot = ({
  menu,
}) => (
  <PluginSlot
    id="org.openedx.frontend.layout.header_desktop_secondary_menu.v1"
    idAliases={['desktop_secondary_menu_slot']}
    slotOptions={{
      mergeProps: true,
    }}
  >
+  <HeaderNotificationsSlot />
    <DesktopHeaderMainOrSecondaryMenu menu={menu} />
  </PluginSlot>
);
  • org.openedx.frontend.layout.studio_header_search_button_slot.v1

    • For this one, I think it would make sense to make a new slot that wraps both the search button slot and the new notifications slot. This would ensure anyone currently using org.openedx.frontend.layout.studio_header_search_button_slot.v1 can continue to do so, the new notifications slot will work as intended, and site operators will have the option to modify the area with the search and notification buttons in studio only without touching the LMS if they'd like.
  • org.openedx.frontend.layout.header_learning_help.v1

    • Same idea here as the search button slot.

Hopefully these thoughts/suggestions make sense! Please let me know if you have any questions!

@brian-smith-tcril Thank you for your detailed review and feedback. I have made the suggested changes. Please review it and let me know.

Copy link
Copy Markdown
Contributor

@brian-smith-tcril brian-smith-tcril left a comment

Choose a reason for hiding this comment

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

Thank you so much for addressing my previous comments! I'm very happy with this new structure!

I left quite a few comments, but they're pretty much all just README suggestions.

Comment thread src/plugin-slots/LearningHeaderActionsSlot/index.jsx Outdated
Comment thread src/plugin-slots/LearningHeaderActionsSlot/README.md Outdated
Comment thread src/plugin-slots/HeaderNotificationsSlot/index.jsx Outdated
Comment thread src/plugin-slots/LearningHeaderActionsSlot/README.md Outdated
Comment thread src/plugin-slots/LearningHeaderActionsSlot/README.md Outdated
Comment thread src/plugin-slots/HeaderNotificationsSlot/README.md Outdated
Comment thread src/plugin-slots/HeaderNotificationsSlot/README.md Outdated
Comment thread src/plugin-slots/DesktopSecondaryMenuSlot/README.md Outdated
Comment thread src/plugin-slots/DesktopSecondaryMenuSlot/README.md
Comment thread src/plugin-slots/DesktopSecondaryMenuSlot/README.md Outdated
@awais-ansari
Copy link
Copy Markdown
Contributor Author

@brian-smith-tcril, I have incorporated all suggestions and included a screenshot. Please conduct a final review. Thank you.

Copy link
Copy Markdown
Contributor

@brian-smith-tcril brian-smith-tcril left a comment

Choose a reason for hiding this comment

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

Thanks for addressing my previous review comments! It looks like you added screenshots but didn't update the READMEs to include them. Once that's sorted out this should be good to go!

Comment thread src/plugin-slots/DesktopSecondaryMenuSlot/README.md
Comment thread src/plugin-slots/HeaderNotificationsSlot/README.md
Comment thread src/plugin-slots/LearningHeaderActionsSlot/README.md
Comment thread src/plugin-slots/StudioHeaderActionsSlot/README.md
@brian-smith-tcril
Copy link
Copy Markdown
Contributor

Thanks again for all the work on this!

I noticed a couple things with the most recent changes.

In bad7e4c you split the following slots into v1/v2

  • LearningHeaderActionsSlot
    • v1 of this just wraps LearningHelpSlot, not sure what double-wrapping that adds.
  • StudioHeaderActionsSlot
    • v1 of this just wraps StudioHeaderSearchButtonSlot, not sure what double wrapping that adds.
  • DesktopSecondaryMenuSlot
    • This one makes perfect sense to split. v1 directly wraps DesktopHeaderMainOrSecondaryMenu (not a slot), so the split is needed for backwards compatibility.

I also feel like the changes to DektopSecondaryMenuSlot/README.md are a bit confusing. I think following the other v1/v2 split pattern of just linking to the v1 doc from the v2 doc makes it easier to follow than the combined README.

@awais-ansari awais-ansari force-pushed the aansari/notifications-79 branch from 88a1940 to 99a6366 Compare April 3, 2026 12:29
Comment thread src/plugin-slots/DesktopSecondaryMenuSlot/v2/README.md Outdated
Copy link
Copy Markdown
Contributor

@brian-smith-tcril brian-smith-tcril left a comment

Choose a reason for hiding this comment

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

I gave this another pass. Thanks again for your patience throughout this review process. I know I've been focusing heavily on the READMEs for these slots. The reason for that focus is that site operators rely on these examples when using these slots, so having clear and accurate documentation is key.

Comment thread src/plugin-slots/DesktopSecondaryMenuSlot/v2/README.md
Comment thread src/plugin-slots/HeaderNotificationsSlot/README.md Outdated
Comment thread src/plugin-slots/LearningHeaderActionsSlot/README.md
Comment thread src/plugin-slots/StudioHeaderActionsSlot/README.md
Copy link
Copy Markdown
Contributor

@brian-smith-tcril brian-smith-tcril left a comment

Choose a reason for hiding this comment

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

This looks great! It's like 99.9% ready to land. There's one last tiny docs thing to clean up but once that's sorted this should be good to go!

Thanks again for working through the review process with me. I'm very happy with how this is coming together.

Comment thread src/plugin-slots/DesktopSecondaryMenuSlot/v1/README.md
Copy link
Copy Markdown
Contributor

@brian-smith-tcril brian-smith-tcril left a comment

Choose a reason for hiding this comment

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

Thank you so much for working with me throughout the review process! This looks great!

@brian-smith-tcril brian-smith-tcril merged commit b040bb2 into openedx:master Apr 9, 2026
6 checks passed
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.

3 participants