Skip to content

feat: move discussion topic prefetch from trigger to widget config lifecycle#1897

Merged
arbrandes merged 3 commits intoopenedx:masterfrom
awais-ansari:aansari/clean-up-hide-upsell
Apr 14, 2026
Merged

feat: move discussion topic prefetch from trigger to widget config lifecycle#1897
arbrandes merged 3 commits intoopenedx:masterfrom
awais-ansari:aansari/clean-up-hide-upsell

Conversation

@awais-ansari
Copy link
Copy Markdown
Contributor

Summary

Moves data-fetching logic (getCourseDiscussionTopics dispatch) out of DiscussionsTrigger and into a new prefetch field on the widget config. SidebarContextProvider now runs widget.prefetch() for all enabled widgets on mount and when course metadata changes, ensuring Redux store data is populated before isAvailable checks and component rendering.

Motivation

Previously, DiscussionsTrigger was responsible for both rendering and fetching discussion topics. This created a coupling between the trigger component and the data lifecycle. The trigger had to mount before data was available, causing timing issues with widget availability checks. Moving prefetch to the framework level ensures data is ready before any widget logic runs.

Changes

Code (5 files)

  • SidebarContextProvider.jsx: Added useDispatch + useEffect that iterates enabledWidgets and calls widget.prefetch({ courseId, course, dispatch }) when course metadata changes.
  • DiscussionsTrigger.jsx: Removed useDispatch, useEffect, getCourseDiscussionTopics, courseHomeMeta tabs lookup, and getConfig().DISCUSSIONS_MFE_BASE_URL check. Now a pure render component that only reads the discussionTopics model.
  • widgetConfig.js: Added discussionsPrefetch function and prefetch field to the discussions widget config.
  • SidebarContextProvider.test.jsx: Added react-redux mock, enriched useModel mock for courseHomeMeta, updated UC7 toggle tests to reflect mobile behavior (no auto-open).
  • DiscussionsTrigger.test.jsx: Added executeThunk(getCourseDiscussionTopics(...)) in beforeEach to pre-populate the store.

Documentation (4 files)

  • ARCHITECTURE.md: Documented the prefetch lifecycle and updated provider responsibilities.
  • README.md: Added prefetch to the widget structure definition and usage guide.
  • USE_CASE_VERIFICATION.md: Added Prefetch Effect (effect #0) to the architecture diagram.
  • discussions/README.md: Added discussionsPrefetch export and data prefetch documentation.

Widget Config API Addition

The prefetch field is a new optional field on the widget config:

{
  id: 'MY_WIDGET',
  prefetch: ({ courseId, course, dispatch }) => {
    dispatch(fetchMyData(courseId));
  },
  // ... other fields
}

@awais-ansari awais-ansari requested a review from arbrandes April 13, 2026 18:57
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.28%. Comparing base (0664dc3) to head (acc6ee6).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1897   +/-   ##
=======================================
  Coverage   91.27%   91.28%           
=======================================
  Files         343      343           
  Lines        5766     5770    +4     
  Branches     1387     1388    +1     
=======================================
+ Hits         5263     5267    +4     
  Misses        484      484           
  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.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR moves Discussions data loading (getCourseDiscussionTopics) out of the DiscussionsTrigger component and into a new optional prefetch hook on sidebar widget configs, executed by SidebarContextProvider when the provider mounts and when course metadata updates.

Changes:

  • Add widget.prefetch({ courseId, course, dispatch }) execution in SidebarContextProvider.
  • Introduce discussionsPrefetch + prefetch in the discussions widget config; simplify DiscussionsTrigger to render-only.
  • Update tests and docs to reflect the new widget prefetch lifecycle; add a new unit test file for Sidebar.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/courseware/course/sidebar/SidebarContextProvider.jsx Runs prefetch for enabled widgets via a new effect.
src/widgets/discussions/widgetConfig.js Adds discussionsPrefetch and wires it into the widget config.
src/widgets/discussions/DiscussionsTrigger.jsx Removes fetching logic; now reads the model and renders conditionally.
src/widgets/discussions/DiscussionsTrigger.test.jsx Pre-populates the store by executing the thunk in beforeEach.
src/courseware/course/sidebar/SidebarContextProvider.test.jsx Mocks useDispatch/useModel and adjusts UC7 toggle expectations.
src/courseware/course/sidebar/Sidebar.test.jsx Adds unit tests for Sidebar rendering/switching behavior.
src/courseware/course/sidebar/README.md Documents the new prefetch widget config field.
src/courseware/course/sidebar/ARCHITECTURE.md Documents the provider’s prefetch responsibility and lifecycle.
src/courseware/course/sidebar/USE_CASE_VERIFICATION.md Updates the architecture diagram to include a prefetch effect.
src/widgets/discussions/README.md Documents discussions-specific prefetch behavior and exports.
Comments suppressed due to low confidence (1)

src/widgets/discussions/DiscussionsTrigger.jsx:13

  • DiscussionsTrigger no longer reads DISCUSSIONS_MFE_BASE_URL, but it still calls ensureConfig(['DISCUSSIONS_MFE_BASE_URL']) at module load. This keeps an import-time hard dependency on that config even when the trigger is meant to be a pure render component. Consider moving the ensureConfig call to where the config is actually used now (e.g., discussionsPrefetch and/or DiscussionsSidebar) and removing it from the trigger.
import { ensureConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Icon } from '@openedx/paragon';
import { QuestionAnswer } from '@openedx/paragon/icons';
import PropTypes from 'prop-types';
import { useContext } from 'react';
import { useModel } from '@src/generic/model-store';
import { WIDGETS } from '@src/constants';
import SidebarTriggerBase from '@src/courseware/course/sidebar/common/TriggerBase';
import SidebarContext from '@src/courseware/course/sidebar/SidebarContext';
import messages from './messages';

ensureConfig(['DISCUSSIONS_MFE_BASE_URL']);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/courseware/course/sidebar/README.md Outdated
Comment thread src/courseware/course/sidebar/ARCHITECTURE.md Outdated
Comment thread src/courseware/course/sidebar/SidebarContextProvider.jsx Outdated
Comment thread src/courseware/course/sidebar/SidebarContextProvider.jsx
Comment thread src/courseware/course/sidebar/SidebarContextProvider.test.jsx Outdated
Comment thread src/widgets/discussions/README.md Outdated
Comment thread src/courseware/course/sidebar/USE_CASE_VERIFICATION.md Outdated
Comment thread src/courseware/course/sidebar/SidebarContextProvider.jsx Outdated
Comment thread src/widgets/discussions/widgetConfig.js
Comment thread src/courseware/course/sidebar/SidebarContextProvider.test.jsx Outdated
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.

At first glance this makes a lot of sense: centralizing data prefetch in the provider so that isAvailable checks can rely on pre-populated Redux state. But there's an issue:

The prefetch effect at SidebarContextProvider.jsx#L89-L96 includes coursewareMeta and courseHomeMeta in its dependency array. The two models settle in separate React batches during initial load, which causes the effect to fire twice after the guard in discussionsPrefetch starts passing.

I confirmed this produces duplicate requests to both GET /api/discussion/v1/courses/{courseId} and GET /api/discussion/v2/course_topics/{courseId} on every page load - two requests to each endpoint returning identical data (thunks.js#L268-L286).

The old code in DiscussionsTrigger avoided this because its effect depended on [courseId, baseUrl, edxProvider, dispatch], all of which were stable after the initial render.

A simple fix might be to remove coursewareMeta and courseHomeMeta from the dependency array. The effect only needs to run once per courseId - the course object is only used inside discussionsPrefetch to check tabs, and that check can happen with the latest value via a ref or by passing the models lazily.

@awais-ansari awais-ansari requested a review from arbrandes April 13, 2026 20:22
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.

Ok, the ref workaround solves it, but it's a bit hacky. The real solution is going to be moving to React Query, later on.

Let's worry about that later, though! 👍🏼

@arbrandes arbrandes merged commit 59113b0 into openedx:master Apr 14, 2026
7 checks passed
arbrandes added a commit to arbrandes/frontend-app-learning that referenced this pull request Apr 16, 2026
arbrandes added a commit to arbrandes/frontend-app-learning that referenced this pull request Apr 16, 2026
Reverts the following two commits:

- 59113b0 feat: move discussion topic prefetch from trigger to widget
  config lifecycle (openedx#1897)
- 0664dc3 feat: decouple notifications panel using widget registry
  mechanism (openedx#1885)

Co-Authored-By: Claude <noreply@anthropic.com>
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