Port latest master to frontend-base (incl. Redux-to-React-Query migration)#801
Open
arbrandes wants to merge 25 commits intoopenedx:frontend-basefrom
Open
Port latest master to frontend-base (incl. Redux-to-React-Query migration)#801arbrandes wants to merge 25 commits intoopenedx:frontend-basefrom
arbrandes wants to merge 25 commits intoopenedx:frontend-basefrom
Conversation
Co-authored-by: Adolfo R. Brandes <adolfo@axim.org>
Co-authored-by: Deborah Kaplan <deborahgu@users.noreply.github.com> Co-authored-by: Adolfo R. Brandes <adolfo@axim.org>
…extra repositories (openedx#752) Co-authored-by: Adolfo R. Brandes <adolfo@axim.org>
Co-authored-by: Adolfo R. Brandes <adolfo@axim.org>
Co-authored-by: Adolfo R. Brandes <adolfo@axim.org>
Co-authored-by: Adolfo R. Brandes <adolfo@axim.org>
1b7091b to
39b38c8
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## frontend-base #801 +/- ##
================================================
Coverage ? 90.38%
================================================
Files ? 152
Lines ? 1290
Branches ? 267
================================================
Hits ? 1166
Misses ? 119
Partials ? 5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Use 'test' string literal instead of EnvironmentTypes.TEST and import only the type to avoid circular dependency when mocking @openedx/frontend-base itself. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f574820 to
55f36bb
Compare
55f36bb to
83dd294
Compare
Remove all Redux files and packages. Add React Query hooks, Context providers, typed API layer, data transformers, and tests. Migrate all components including CourseCard, CourseCardBanners, CourseFilterControls, CoursesPanel, Dashboard, modals, and remaining widgets. Reconcile masquerade implementations with frontend-base providers.ts architecture. Co-Authored-By: Jacobo Dominguez <jacobo.dominguez@wgu.edu> Co-Authored-By: Claude <noreply@anthropic.com>
useInitializeLearnerHome() is consumed by 15+ components, and with staleTime defaulting to 0, every mount and window focus triggered a redundant background refetch. Set staleTime to 5 minutes since dashboard data rarely changes while the user is viewing it. Co-Authored-By: Claude <noreply@anthropic.com>
The useUnenrollFromCourse mutation already calls invalidateQueries on success, which triggers a refetch automatically. The manual refetch() call in closeAndRefresh caused the API to be called twice. Co-Authored-By: Claude <noreply@anthropic.com>
The fallback enrollment date was frozen when the module first loaded. If the app stayed open across midnight, courses with null lastEnrolled would get a stale timestamp. Co-Authored-By: Claude <noreply@anthropic.com>
Previously, modals closed immediately after firing mutations via mutate(), giving no feedback on failure. Now the close action is passed as an onSuccess callback so the modal stays open if the mutation fails. Co-Authored-By: Claude <noreply@anthropic.com>
Auto-fixed stylistic issues (indentation, semicolons, brace style, type→interface, Array<T>→T[]) and manually fixed display-name errors (named wrapper functions), @ts-ignore→@ts-expect-error, and Function→explicit signature. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert GlobalDataContext.jsx to .tsx with proper interface so setEmailConfirmation and setPlatformSettings are typed as Dispatch<SetStateAction<T>> | null instead of literal null. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The tsconfig declares "types": ["jest"] but @types/jest was not installed, so TypeScript treated jest as a namespace rather than a value. Adding the matching type definitions lets the webpack type-checker process test files without errors. Also bump frontend-base to fix the @src alias in jest config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
83dd294 to
4cb9aa3
Compare
Previously, each useCourseData(cardId) call independently transformed the full course list via getTransformedCourseDataList just to find one item. With N course cards, this ran N times per render cycle. Now the transformation runs once in the queryFn, stored as coursesByCardId on the cached data. useCourseData does an O(1) lookup and CoursesPanel reads directly from the pre-transformed data. Co-Authored-By: Claude <noreply@anthropic.com>
The masquerade fallback data was maintained in a separate context provider, duplicating what React Query already caches. Now when masquerading fails, the normal user's data is read directly from the query cache via queryClient.getQueryData(). This eliminates BackedDataProvider and its associated useEffect sync. Co-Authored-By: Claude <noreply@anthropic.com>
Mutations were invalidating with initialize() which produces a key with trailing undefined, relying on React Query implementation details for prefix matching. Added initializeBase() that produces a clean prefix key ['learner-dashboard', 'initialize'] for unambiguous invalidation of all initialize queries regardless of masquerade user. Co-Authored-By: Claude <noreply@anthropic.com>
… errors Client errors (4xx) won't resolve on retry, so skip them. Server errors (5xx) and network failures get up to 3 retries with React Query's default exponential backoff. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split learnerDashboardQueryKeys into distinct query and mutation key factories for clearer semantics. Mutation keys now live in learnerDashboardMutationKeys while query invalidation still uses learnerDashboardQueryKeys. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MasqueradeProvider and FiltersProvider used useReducer with action type enums for what are simple value states. Replaced with useState for less boilerplate while preserving the same public API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verifies the basic flow: API is called without masquerade user, data is returned with coursesByCardId transformation applied. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port of master PR openedx#738 to frontend-base. Differences from master: - Config added to src/app.ts instead of .env files and src/config/index.js (frontend-base convention) - Uses useAppConfig() hook instead of importing configuration object directly (idiomatic for code running inside the provider tree) - Default is false (master defaults to true) Co-Authored-By: Adolfo R. Brandes <adolfo@opencraft.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…s/ dirs Move the asset copy step before tsc-alias so that .svg and .png files exist in dist/ when tsc-alias resolves @src path aliases. Also restrict image file copying to files under assets/ directories, excluding screenshots in slots/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This does what it says on the tin: the main intent is to port the latest master into frontend-base land. However, since these are ports, fixes and improvements related to the changes were added beyond what's in master, as seen below. These show as separate commits so we can decide whether to backport them later.
Headliners
mastercommits to thefrontend-basebranch: dependency cleanups, translation support, unenrollment improvements, credit purchase URL logic, documentation fixes, and new unenrollment survey toggle variablemaster, adapting it tofrontend-baseconventions (@src/imports,@openedx/frontend-baseAPIs, slots/widgets structure)site.config.test.tsxthat broke the entire test suite (corresponding PR to docs)tsc-aliasonly after copying assets to/dist/, otherwise SVG imports are not converted to relative pathsstaleTime(5 min) to prevent excessive refetching across 15+ consuming componentsinvalidateQuerieshandles it)Date.now()per call instead of at module load (was producing stale timestamps)LLM usage notice
Built with assistance from Claude models (mostly Opus 4.6).
Work Log
Porting master commits
Six pre-existing
mastercommits were cherry-picked ontofrontend-basein a prior session, forming the base of thefrontend-base-master-portsbranch:d62b5d3feat: added a generic creditPurchase URL logic (feat: added a generic creditPurchase Url logic #675)51f93a0mubbsharanwar/unenrollment process improvement (mubbsharanwar/unenrollment process improvement #704)96c1c44feat: added the ability for instances to use local translations from extra repositories (feat: added the ability for instances to use local translations from extra repositories #752)ae52f75fix(deps): remove filesize dependency (fix(deps): remove filesize dependency #767)b03407dfix: update react-share to v5 (fix: update react-share to v5 #795)1d97ed6fix(docs): use correct image for custom course banner (fix(docs): use correct image for custom course banner #796)Circular dependency fix (
site.config.test.tsx)Running
npm run testrevealed that every test suite failed withEnvironmentTypesbeing undefined. Root cause:site.config.test.tsximported{ EnvironmentTypes }from@openedx/frontend-base, creating a circular dependency chain (initialize.js→site.config→@openedx/frontend-base→ still loading). Fixed by usingimport type { SiteConfig }(erased at compile time) and the string literal'test'instead ofEnvironmentTypes.TEST.Redux to React Query migration port
The large migration commit from
masterwas ported and adapted tofrontend-baseconventions:@edx/frontend-platformreferences with@openedx/frontend-baseequivalents'utils'imports to use@src/utilsuseAuthenticatedUser()hook instead of the removedAppContextpatterncontainers/→widgets/)Fixing 13 failing test suites
After porting the migration, 13 test suites (43 tests) failed. Issues were categorized and fixed:
AppWrapper/index.test.tsx(no source file); movedConfirmEmailBanner/hooks.test.jsxto correctwidgets/pathjest.mock('@openedx/frontend-plugin-framework')fromCoursesPanelandDashboardLayouttests@src/asset resolution (2 suites): Post-processedjest.config.jsto prepend@src/-prefixed.svg/.pngpatterns before the@srcpath resolver (webpack-merge ordering issue)<MemoryRouter>(2 suites): AddedMemoryRouterwrapper forSlotcomponent'suseLocation()dependency in 4 test filesAppContextnot in frontend-base (1 suite): ChangedCreditBanner/views/hooks.jsfromAppContext+useContext()touseAuthenticatedUser()hookjest.mock(1 suite): Merged twojest.mock('@openedx/frontend-base')calls inSelectSessionModal/hooks.test.jsx'utils'import (1 suite): Fixed 4 files to use'@src/utils'api.test.tsxto provide mock values injest.mock()factoriesuseMasquerade/useBackedDatachecks fromcontext/index.test.tsx(those providers aren't inContextProviders)Also fixed
DashboardLayout.test.jsxSlot assertion —Slotrenders children directly without a wrapper div.Bug fixes from code review
A holistic code review of the migration identified 14 issues, including by not limited to:
4ec911e): Added 5-minutestaleTimeto the main query to prevent redundant refetches when 15+ components mount with the same query498f182): Removed manualqueryClient.invalidateQueries()+refetch()on unenroll — React Query's mutationonSuccesswithinvalidateQueriesalready handles thisDate.now()(1126c07):Date.now()was computed once at module load and reused for all API calls, producing stale timestamps. Changed to compute per call2126010): Modals were closed on form submit before knowing if the mutation succeeded. Moved close logic to the mutation'sonSuccesscallbackCommit-by-commit test verification
Each commit was tested individually by stepping through the history with
git checkout. One test failure was found and fixed: the masquerade fallback test usedgcTime: 0in its testQueryClient, which caused pre-seeded cache data to be garbage collected beforequeryClient.getQueryData()could read it. Fixed by removinggcTime: 0from that specific test'sQueryClient.