Skip to content

feat: make widget registry to backward compatible#1899

Merged
arbrandes merged 3 commits intoopenedx:masterfrom
awais-ansari:aansari/hide-upsell-backward-comp
Apr 17, 2026
Merged

feat: make widget registry to backward compatible#1899
arbrandes merged 3 commits intoopenedx:masterfrom
awais-ansari:aansari/hide-upsell-backward-comp

Conversation

@awais-ansari
Copy link
Copy Markdown
Contributor

This PR introduces backward compatibility following the rename of the Notifications sidebar widget to Upgrade (ADR 0010). It ensures existing operator configurations, plugin slots, context consumers, and JS constant references continue to work without changes while the platform migrates to the new naming.

Key changes

Widget registry deduplication
getEnabledWidgets() now prevents external SIDEBAR_WIDGETS config from accidentally overriding or duplicating platform-default widgets. External entries with the same ID as a default are ignored (platform default wins); setting enabled: false on a matching ID disables the default entirely.

upgradeWidgetConfig added to DEFAULT_WIDGETS
The Upgrade widget is now a first-class default alongside Discussions, so it appears without any env.config.jsx configuration.

WIDGETS.NOTIFICATIONS deprecated alias
constants.ts adds WIDGETS.NOTIFICATIONS = 'UPGRADE' so legacy checks like currentSidebar === WIDGETS.NOTIFICATIONS resolve correctly against the renamed widget ID.

Plugin slot ID aliases
RightSidebarSlot and RightSidebarTriggerSlot add the old notifications_discussions_sidebar* full IDs to their idAliases, preserving existing plugin configs.

Prop aliases in UpgradePanel
The upgrade panel slot exposes notificationCurrentState / setNotificationCurrentState alongside the new prop names so plugins using the old names still receive values.

Migration guide
docs/upgrade-widget-migration.md documents every renamed identifier, the deprecation timeline, and the copy-paste env.config.jsx examples for operators.

Test Plan

  • Verify Upgrade tab renders on a course with a verified mode without any env.config.jsx changes
  • Verify an operator can disable the Upgrade tab by setting { id: 'UPGRADE', enabled: false } in SIDEBAR_WIDGETS
  • Verify a plugin targeting the old slot ID org.openedx.frontend.learning.notification_tray.v1 still renders inside the Upgrade panel

env.config.js

import React from 'react';
import { PLUGIN_OPERATIONS, DIRECT_PLUGIN } from '@openedx/frontend-plugin-framework';

/**
 * Backward-compatibility test config.
 *
 * Each pluginSlot entry below references a DEPRECATED slot ID (covered by idAliases).
 * If the alias mapping is working, the injected "BC OK" banners will appear inside
 * the corresponding slot in the UI.
 *
 * Alias mappings under test:
 *
 *   Deprecated ID                                                    → Current slot
 *   ───────────────────────────────────────────────────────────────────────────────
 *   org.openedx.frontend.learning.notifications_discussions_sidebar.v1  → RightSidebarSlot
 *   notifications_discussions_sidebar_slot                               → RightSidebarSlot
 *
 *   org.openedx.frontend.learning.notifications_discussions_sidebar_trigger.v1  → RightSidebarTriggerSlot
 *   notifications_discussions_sidebar_trigger_slot                               → RightSidebarTriggerSlot
 *
 *   org.openedx.frontend.learning.notification_tray.v1  → UpgradePanel PluginSlot
 *   notification_tray_slot                               → UpgradePanel PluginSlot
 */

const TestBanner = ({ label, color }) => (
  <div style={{
    background: color,
    color: '#fff',
    padding: '4px 8px',
    fontSize: '11px',
    fontWeight: 'bold',
    borderRadius: '3px',
    margin: '2px 0',
    zIndex: 9999,
  }}>
    {'BC OK: '}
    {label}
  </div>
);

const config = {
  pluginSlots: {

    // ── RightSidebarSlot ──────────────────────────────────────────────────────
    // Test 1: old formal dotted ID
    'org.openedx.frontend.learning.notifications_discussions_sidebar.v1': {
      plugins: [{
        op: PLUGIN_OPERATIONS.Insert,
        widget: {
          id: 'bc-right-sidebar-formal-id',
          type: DIRECT_PLUGIN,
          priority: 1,
          RenderWidget: () => (
            <TestBanner
              label="RightSidebarSlot via notifications_discussions_sidebar.v1"
              color="#0a3055"
            />
          ),
        },
      }],
    },

    // Test 2: old short string alias
    notifications_discussions_sidebar_slot: {
      plugins: [{
        op: PLUGIN_OPERATIONS.Insert,
        widget: {
          id: 'bc-right-sidebar-short-alias',
          type: DIRECT_PLUGIN,
          priority: 2,
          RenderWidget: () => (
            <TestBanner
              label="RightSidebarSlot via notifications_discussions_sidebar_slot"
              color="#0075b2"
            />
          ),
        },
      }],
    },

    // ── RightSidebarTriggerSlot ───────────────────────────────────────────────
    // Test 3: old formal dotted ID
    'org.openedx.frontend.learning.notifications_discussions_sidebar_trigger.v1': {
      plugins: [{
        op: PLUGIN_OPERATIONS.Insert,
        widget: {
          id: 'bc-trigger-formal-id',
          type: DIRECT_PLUGIN,
          priority: 1,
          RenderWidget: () => (
            <TestBanner
              label="RightSidebarTriggerSlot via notifications_discussions_sidebar_trigger.v1"
              color="#1d5e1d"
            />
          ),
        },
      }],
    },

    // // Test 4: old short string alias
    notifications_discussions_sidebar_trigger_slot: {
      plugins: [{
        op: PLUGIN_OPERATIONS.Insert,
        widget: {
          id: 'bc-trigger-short-alias',
          type: DIRECT_PLUGIN,
          priority: 2,
          RenderWidget: () => (
            <TestBanner
              label="RightSidebarTriggerSlot via notifications_discussions_sidebar_trigger_slot"
              color="#005a23"
            />
          ),
        },
      }],
    },

    // // ── UpgradePanel PluginSlot ───────────────────────────────────────────────
    // // Test 5: old formal dotted ID
    'org.openedx.frontend.learning.notification_tray.v1': {
      plugins: [{
        op: PLUGIN_OPERATIONS.Insert,
        widget: {
          id: 'bc-notification-tray-formal-id',
          type: DIRECT_PLUGIN,
          priority: 1,
          RenderWidget: () => (
            <TestBanner
              label="UpgradePanel slot via notification_tray.v1"
              color="#7a1a00"
            />
          ),
        },
      }],
    },

    // // Test 6: old short string alias
    notification_tray_slot: {
      plugins: [{
        op: PLUGIN_OPERATIONS.Insert,
        widget: {
          id: 'bc-notification-tray-short-alias',
          type: DIRECT_PLUGIN,
          priority: 2,
          RenderWidget: () => (
            <TestBanner
              label="UpgradePanel slot via notification_tray_slot"
              color="#b23000"
            />
          ),
        },
      }],
    },

  },
};

export default config;



@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.30%. Comparing base (59113b0) to head (9169360).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1899      +/-   ##
==========================================
+ Coverage   91.28%   91.30%   +0.02%     
==========================================
  Files         343      343              
  Lines        5770     5775       +5     
  Branches     1388     1390       +2     
==========================================
+ Hits         5267     5273       +6     
+ Misses        484      483       -1     
  Partials       19       19              

☔ 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 awais-ansari requested a review from arbrandes April 17, 2026 13:11
Copy link
Copy Markdown
Contributor

@arbrandes arbrandes left a comment

Choose a reason for hiding this comment

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

For a plugin author working against the documented contact points — targeting a slot via env.config.jsx, consuming pluginProps, comparing against WIDGETS.NOTIFICATIONS — the BC layer covers all three and nothing has to change on the plugin side: old slot ids resolve via idAliases, old prop names are emitted alongside the new ones, and the WIDGETS.NOTIFICATIONS constant now resolves to 'UPGRADE'.

The things this PR does not shim (literal 'NOTIFICATIONS' string comparisons, reads of old notification* properties on SidebarContext, and direct localStorage reads) are past the documented API, and for the SidebarContext case in particular there is no non-redundant use case: the two upgrade-flow values an external plugin could plausibly want are already delivered to it at the slot boundary via pluginProps, and the remaining three are the upgrade widget's own "has the learner seen this yet" bookkeeping, which no other widget should be touching. So: not a BC concern.

That said, we need to think about when this is eventually deprecated, which brings me to the first issue:

1. Removability of the deprecated surface

Removal eventually has to go through OEP-21, which requires a DEPR issue listing what's being removed, the replacement, and the deprecation window. The ADR (once item #3 folds the migration guide into it) is the natural place to stage that inventory so a future DEPR filer can lift it directly rather than reconstructing it from git archaeology. For example:

Deprecated identifiers

Deprecated Replacement Deprecated since Planned removal
Slot id org.openedx.frontend.learning.notification_tray.v1 (and notification_tray_slot) org.openedx.frontend.learning.upgrade_panel.v1 release including PR #1899 TBD — one full deprecation cycle after deprecation ships
Slot id org.openedx.frontend.learning.notifications_discussions_sidebar.v1 (and notifications_discussions_sidebar_slot) org.openedx.frontend.learning.right_sidebar.v1 / right_sidebar_slot release including PR #1899 TBD
Slot id org.openedx.frontend.learning.notifications_discussions_sidebar_trigger.v1 (and notifications_discussions_sidebar_trigger_slot) org.openedx.frontend.learning.right_sidebar_trigger.v1 / right_sidebar_trigger_slot release including PR #1899 TBD
pluginProps keys notificationCurrentState / setNotificationCurrentState on the upgrade panel slot upgradeCurrentState / setUpgradeCurrentState release including PR #1899 TBD
WIDGETS.NOTIFICATIONS (value now 'UPGRADE') ID exported from @src/widgets/upgrade/src (widget owns its id) release including PR #1899 TBD

Default-behavior change

upgradeWidgetConfig is currently included in DEFAULT_WIDGETS. A future release will remove it, after which operators who want the Upgrade panel visible must add it to SIDEBAR_WIDGETS in env.config.jsx. Target release: TBD.

2. Annotate every alias site with @deprecated

Only WIDGETS.NOTIFICATIONS carries a @deprecated JSDoc today; the four other shim sites do not:

A one-line JSDoc or inline comment per site is enough; grep -R '@deprecated' should then enumerate all five without needing the ADR.

3. docs/upgrade-widget-migration.md should be folded into ADR 0010

Fold the migration guide into ADR 0010 as a "Migration" / "Backward compatibility" section, and retarget the README link there. Keeping them separate invites drift between the decision and its compat story.

4. Errors in the migration content (carry forward when folding into the ADR)

Two bugs in docs/upgrade-widget-migration.md that need fixing wherever the content ends up living:

  • L87 — heading `WIDGETS.NOTIFICATIONS` → `WIDGETS.NOTIFICATIONS` (deprecated alias) has the same identifier on both sides of the arrow. Either write out the value change ('NOTIFICATIONS''UPGRADE') or drop the arrow.

  • L136-L143 — localStorage key table lists one rename but the pre-ADR code (NotificationTrigger.jsx at 0664dc38^) wrote three. The two missing rows:

    Old key New key
    upgradeNotificationLastSeen.${courseId} upgradeWidgetLastSeen.${courseId}
    upgradeNotificationCurrentState.${courseId} upgradeWidgetState.${courseId}

5. .gitignore: keep env.config.jsx ignored

.gitignore lines 28-30 (diff)

Restore the env.config.jsx line; it must stay ignored.

6. src/plugin-slots/README.md: misleading wording, missing entry, broken links

Three problems on src/plugin-slots/README.md#L16:

  • "removed" is factually wrong. The entry reads ~~notification_tray.v1~~ _(removed; aliased to the upgrade panel...)_. It isn't removed — it still resolves via idAliases. A plugin author reading this would reasonably conclude their plugin has stopped working. Use "deprecated / renamed" or "aliased" instead of "removed".
  • The replacement slot isn't listed. org.openedx.frontend.learning.upgrade_panel.v1 is a real, plugin-targetable slot introduced by this PR, but it doesn't appear in the README's slot list at all — only in the strikethrough breadcrumb for the old id. Since the slot lives under src/widgets/upgrade/ rather than under src/plugin-slots/<Name>Slot/, the list entry will have to point somewhere other than a ./UpgradePanelSlot/ directory (e.g., src/widgets/upgrade/README.md or the ADR), but it needs to be findable from here.
  • Both doc links are 404s. From src/plugin-slots/README.md, ../docs/ resolves to src/docs/, which does not exist. Correct prefix is ../../docs/.

7. Commit hygiene

The commit message test: updete breaking test cases has a typo ("updete"). Non-blocking, but easy to fix via a rebase if you're pushing another round.

@awais-ansari awais-ansari force-pushed the aansari/hide-upsell-backward-comp branch from 81031c1 to 9169360 Compare April 17, 2026 18:48
@awais-ansari awais-ansari requested a review from arbrandes April 17, 2026 18:54
Copy link
Copy Markdown
Contributor

@arbrandes arbrandes 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 for doing this so quickly!

@arbrandes arbrandes merged commit c0966a5 into openedx:master Apr 17, 2026
7 checks passed
@arbrandes
Copy link
Copy Markdown
Contributor

@pdpinch, do you mind checking whether this unbreaks your build?

@pdpinch
Copy link
Copy Markdown

pdpinch commented Apr 23, 2026

Thanks @arbrandes -- yes, this did unbreak our build. And our pluginslots are working again.

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