Skip to content

refactor: convert profile to frontend-base - #1408

Open
arbrandes wants to merge 12 commits into
arbrandes/react-queryfrom
arbrandes/frontend-base
Open

arbrandes wants to merge 12 commits into
arbrandes/react-queryfrom
arbrandes/frontend-base

Conversation

@arbrandes

Copy link
Copy Markdown
Contributor

Description

Converts the Profile micro-frontend into an @openedx/frontend-base application: a library that plugs into the Open edX frontend shell instead of bundling its own webpack build, header and footer. Follows frontend-base's migration how-to, with openedx/frontend-app-account#1470 as the closest peer.

The app is published as @openedx/frontend-app-profile and mounts at profile, with the page at profile/u/:username. Configuration moves to the app's defaultConfig under the operator's config, keeping the names DISABLE_VISIBILITY_EDITING and CREDENTIALS_BASE_URL; ACCOUNT_SETTINGS_URL becomes the account route role. COLLECT_YEAR_OF_BIRTH and ENABLE_SKILLS_BUILDER_PROFILE go, unread for years. The additional-fields slot takes its ADR 0009 name and is configured through site.config, with no aliases kept; the footer slot, the document head and the not-found routes are the shell's now. The stylesheet is scoped to the app, and the page lines up with the header's container.

Second PR in the stack described in #1246, on top of #1407. #1406 covers landing and publishing; registering the app downstream is openedx/frontend-template-site#37, overhangio/tutor-mfe#356 and openedx/openedx-translations#82239.

Closes #1405.

LLM usage notice

Built with assistance from Claude.

arbrandes and others added 6 commits September 23, 2026 09:53
Replaces frontend-build, the .env files and the index.jsx entry point with
frontend-base's tooling and the App/routes/Main structure, and publishes the
app as @openedx/frontend-app-profile.

The tree does not build or test green on its own: the feature code still
imports frontend-platform, which the next commit rewrites.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every frontend-platform import becomes one from frontend-base. Config now
comes from getSiteConfig and getAppConfig, the authenticated user from the
mock/real auth service rather than AppContext, and the account settings link
resolves the account route role, falling back to the LMS page.

Country and language lists come from i18n-iso-countries and
@cospired/i18n-iso-languages, in the locale the intl context reports.
PluginSlot becomes Slot, keeping its id for now; the avatar SVG becomes an
<img>, since SVGR is gone; and the local camelCase/snakeCase helpers give way
to frontend-base's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
plugin-slots becomes slots, and the additional-fields slot takes its ADR 0009
id and is configured through site.config. No aliases are kept, and FooterSlot
goes: the footer is the shell's.

index.scss and profile/index.scss become style.scss and sass/_profile.scss,
scoped under the .profile-app class Main puts on <main>. A lazy chunk's
stylesheet stays injected after a soft navigation away, so the unscoped .btn
overrides and helper classes would otherwise restyle other apps.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Describes the app as a frontend-base library rather than a micro-frontend:
branches and releases, running the dev server on the host, workspaces against
a local frontend-base, the two config keys and where the rest of the values now
come from, slots, and the project layout. ADR 0002, on npm-alias branding, is
marked Superseded: branding belongs to the composing site.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Main was the one new file without a suite: it covers the document title, the
main landmark and its scoping class, and the page event PageWrap sends in
AuthenticatedPageRoute's place. The slot gains the two cases its callbacks
default through: a refresh with no username, and a save with no cached account.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The page's fixed gutters matched the shell header's container at one viewport
width and nowhere else. The banner and the certificates band stay full-bleed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@arbrandes
arbrandes added this pull request to stack #1409 September 23, 2026 14:21
@arbrandes arbrandes linked an issue Sep 23, 2026 that may be closed by this pull request
@codecov

codecov Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.72131% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.72%. Comparing base (5c773a8) to head (2c066cc).

Files with missing lines Patch % Lines
src/profile/ProfilePage.jsx 89.18% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@                    Coverage Diff                    @@
##           arbrandes/react-query    #1408      +/-   ##
=========================================================
+ Coverage                  87.17%   88.72%   +1.54%     
=========================================================
  Files                         47       52       +5     
  Lines                        772      798      +26     
  Branches                     219      219              
=========================================================
+ Hits                         673      708      +35     
+ Misses                        95       86       -9     
  Partials                       4        4              

☔ View full report in Codecov by Harness.
📢 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.

arbrandes and others added 3 commits September 23, 2026 15:34
…ient

/profile matched the parent route on its own and rendered the layout with an
empty outlet; an index route answers it with the not-found page. The account
settings link resolved a route role into an href, which ignores the site's
basename and forces a new tab, so it now goes through getLinkProps and only
opens a new tab for the LMS's own page.

Config is read through useAppConfig, so a component follows a config change;
the test wrapper gains the CurrentAppProvider that makes it work and loses an
unused site-context option.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The conversion turned the placeholder avatar into an <img>, which cannot resolve
the currentColor fill or stretch a viewBox-only SVG to its container, so it
rendered black and overflowed the circle. The icon is a component again, since
frontend-base has no SVGR loader to import one with.

The account route resolver now hands back whether the URL is internal instead of
making the caller work it out again, the slot's form components stop being
rebuilt on every render, and three stale references to the old plugin slots and
config API are corrected.

Co-Authored-By: Claude <noreply@anthropic.com>
The lazy route imports, asset and stylesheet imports, and the i18n messages
re-export stay relative because the build tooling matches them by their
literal paths.

Co-Authored-By: Claude <noreply@anthropic.com>
arbrandes and others added 3 commits September 23, 2026 16:16
Both headings shared profile.profile.information with different default
messages, so extraction warned and translators saw only one of them. The
desktop string keeps the id the translations are filed under.

Drops an avatar icon prop that was never unset and an asset nothing imports.

Co-Authored-By: Claude <noreply@anthropic.com>
Both apps read the learner's account and preferences from the LMS but cache
them under keys of their own, and the shell's query client outlives a
navigation between them, so coming back to this page showed the record as it
was before the edit until a refetch landed. Neither query is kept past the
page now.

Co-Authored-By: Claude <noreply@anthropic.com>
A container centres itself with auto margins, which an inline-flex box ignores,
so the two lower sections sat flush against the viewport instead of lining up
with the header. The flex classes they carried did nothing else: nothing on
them laid out children.

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

Status: No status

Development

Successfully merging this pull request may close these issues.

Convert to frontend-base

1 participant