Skip to content

feat!: bundle only real defaults in app config - #156

Merged
arbrandes merged 3 commits into
openedx:masterfrom
arbrandes:arbrandes/bundled-app-config-cleanup
Aug 29, 2026
Merged

feat!: bundle only real defaults in app config#156
arbrandes merged 3 commits into
openedx:masterfrom
arbrandes:arbrandes/bundled-app-config-cleanup

Conversation

@arbrandes

@arbrandes arbrandes commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Description

Every key an app declares in its own config is a key commonAppConfig can never supply, since app config is the highest-precedence layer. Catalog declared ten, so values an operator set platform-wide through MFE_CONFIG silently lost to bundled defaults. Only HOMEPAGE_COURSE_MAX: 9 is a real default, so it moves to App.defaultConfig (frontend-base ADR 0017, added by openedx/frontend-base#298), which resolves below commonAppConfig; the other nine were no-ops against already-guarded reads or empty-string placeholders that now live at the point of use.

LEARNING_BASE_URL is required config with no default that can work, so getLearningHomePageUrl returns null when it is unset and the course-about "View course" buttons are gated on a resolved URL. An operator who never set it now gets no button rather than one pointing at catalog's own origin.

The peer dependency moves to @openedx/frontend-base 2.0.0-alpha.4, the first release carrying App.defaultConfig. Lint, tsc, build, and all 387 tests pass against it. The second commit is a mechanical lint:fix for a rule frontend-base 2.0 enables.

LLM usage notice

Built with assistance from Claude.

@arbrandes
arbrandes force-pushed the arbrandes/bundled-app-config-cleanup branch from 2e7684b to 0dacaba Compare August 28, 2026 16:47
@arbrandes
arbrandes marked this pull request as ready for review August 28, 2026 16:48
@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.55%. Comparing base (b8834b5) to head (1212202).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #156   +/-   ##
=======================================
  Coverage   99.54%   99.55%           
=======================================
  Files         100      100           
  Lines         666      671    +5     
  Branches      167      168    +1     
=======================================
+ Hits          663      668    +5     
  Misses          2        2           
  Partials        1        1           

☔ 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.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks great!

One non-blocking nit for consistency (inline comment written by claude) in how we're getting strings out of the config.

I specifically flagged not loving the "cast to string | undefined" pattern to claude and the result of the conversation is in that inline comment.

Comment thread src/catalog/CatalogPage.tsx Outdated
// @ts-expect-error frontend-base ErrorPage declares message?: null but renders the prop as text. Remove when typing is fixed upstream.
message={intl.formatMessage(messages.errorMessage, {
supportEmail: getAppConfig(appId).INFO_EMAIL as string,
supportEmail: (getAppConfig(appId).INFO_EMAIL as string | undefined) ?? '',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit / readability — this is behavior-preserving and the cast is doing the right thing now that the key can actually be absent.

Dropping the bundled defaults turns "read a string out of app config" into a recurring shape. It shows up as a cast in four places:

  • src/catalog/CatalogPage.tsx:85
  • src/course-about/CourseAboutPage.tsx:41
  • src/home/components/courses-list/CoursesList.tsx:66
  • src/course-about/course-sidebar/sidebar-social/utils.ts:29 (COURSE_ABOUT_TWITTER_ACCOUNT)

...and a fifth time as a hand-written narrow in getLearningHomePageUrl:

const learningBaseUrl = getAppConfig(appId).LEARNING_BASE_URL;
return typeof learningBaseUrl === 'string' && learningBaseUrl
  ? `${learningBaseUrl}/course/${courseId}/home`
  : null;

One accessor would cover all five:

// src/config.ts
import { getAppConfig } from '@openedx/frontend-base';
import { appId } from '@src/constants';

export const getStringConfig = (key: string, fallback = ''): string => {
  const value = getAppConfig(appId)[key];
  return typeof value === 'string' ? value : fallback;
};

The cast sites lose the cast and the parens:

supportEmail: getStringConfig('INFO_EMAIL'),

and getLearningHomePageUrl keeps its null-when-unset contract without restating the narrow, since the '' fallback is falsy:

const learningBaseUrl = getStringConfig('LEARNING_BASE_URL');
return learningBaseUrl ? `${learningBaseUrl}/course/${courseId}/home` : null;

Behavior is identical at all five sites either way — it's just one implementation of "string or fall back" instead of two spellings of it.

Entirely reasonable to skip if you'd rather not add an indirection for this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Actually, I love it. Thanks!

@arbrandes arbrandes linked an issue Aug 29, 2026 that may be closed by this pull request
@arbrandes arbrandes linked an issue Aug 29, 2026 that may be closed by this pull request
arbrandes and others added 2 commits August 29, 2026 11:14
Every key an app declares in config is one commonAppConfig can never
supply, so move the single genuine default, HOMEPAGE_COURSE_MAX, to
App.defaultConfig and drop the other nine as no-ops or placeholders.

BREAKING CHANGE: requires @openedx/frontend-base 2.0.0-alpha.4, the
first release with App.defaultConfig, and an unset LEARNING_BASE_URL
now renders no "View course" button.

Co-Authored-By: Claude <noreply@anthropic.com>
Mechanical npm run lint:fix for a rule frontend-base 2.0 enables.

Co-Authored-By: Claude <noreply@anthropic.com>
@arbrandes
arbrandes force-pushed the arbrandes/bundled-app-config-cleanup branch from 2ce6c01 to 3da71b2 Compare August 29, 2026 14:14
Dropping the bundled defaults made "string or fall back" a recurring
shape, spelled as a cast in five places and as a hand-written narrow in
getLearningHomePageUrl. getStringConfig replaces both spellings.

Co-Authored-By: Claude <noreply@anthropic.com>
@arbrandes
arbrandes merged commit 05a939d into openedx:master Aug 29, 2026
6 checks passed
@arbrandes
arbrandes deleted the arbrandes/bundled-app-config-cleanup branch August 29, 2026 16:33
@openedx-semantic-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 1.0.0-alpha.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade to frontend-base 2.0

3 participants