Skip to content

Commit 55bbd12

Browse files
committed
refactor: getConfig, App, and standalone mode
This does a few things: * Renames APP_* events * Renames getConfig & company into getSiteConfig * Removes standalone mode: we don't foresee an intermediate step in MFE migration, anymore * This means the `appConfig` structure is not needed anymore, so remove it * ... which necessitated a refactor of the `App` type and associated functions
1 parent 18125c0 commit 55bbd12

File tree

65 files changed

+283
-388
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+283
-388
lines changed

docs/decisions/0006-middleware-support-for-http-clients.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ If a consumer chooses not to use ``initialize`` and instead the ``configureAuth`
3535

3636
configureAuth({
3737
loggingService: getLoggingService(),
38-
config: getConfig(),
38+
config: getSiteConfig(),
3939
options: {
4040
middleware: [axiosCaseConverter, (client) => axiosRetry(client, { retries: 3 })]
4141
}

docs/decisions/0008-stylesheet-import-in-site-config.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ The site.config file should then import the top-level SCSS file:
3131
```diff
3232
+ import './site.scss';
3333

34-
const config = {
34+
const siteConfig = {
3535
// config document
3636
}
3737

38-
export default config;
38+
export default siteConfig;
3939
```

docs/how_tos/automatic-case-conversion.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Or, if you choose to use ``configureAuth`` instead::
3232

3333
configureAuth({
3434
loggingService: getLoggingService(),
35-
config: getConfig(),
35+
config: getSiteConfig(),
3636
options: {
3737
middleware: [axiosCaseConverter, (client) => axiosRetry(client, { retries: 3 })]
3838
}

docs/how_tos/i18n.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Load up your translation files
101101

102102
configureI18n({
103103
messages,
104-
config: getConfig(), // environment and languagePreferenceCookieName are required
104+
config: getSiteConfig(), // environment and languagePreferenceCookieName are required
105105
loggingService: getLoggingService(), // An object with logError and logInfo methods
106106
});
107107

docs/how_tos/migrate-frontend-app.md

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,8 @@ With the exception of any custom scripts, replace the `scripts` section of your
127127

128128
```
129129
"scripts": {
130-
"build": "PORT=YOUR_PORT openedx build",
131-
"build:standalone": "openedx build:standalone",
130+
"build": "openedx build",
132131
"dev": "PORT=YOUR_PORT openedx dev",
133-
"dev:standalone": "PORT=YOUR_PORT openedx dev:standalone",
134132
"i18n_extract": "openedx formatjs extract",
135133
"lint": "openedx lint .",
136134
"lint:fix": "openedx lint --fix .",
@@ -305,13 +303,13 @@ module.exports = config;
305303
Merge site.config into config in setupTest.js
306304
=============================================
307305

308-
frontend-platform used environment variables to seed the configuration object, meaning it had default values at the time code is loaded based on `process.env` variables. frontend-base has a hard-coded, minimal configuration object that _must_ be augmented by a valid site config file at initialization time. This means that any tests that rely on configuration (e.g., via `getConfig()`) must first initialize the configuration object. This can be done for tests by adding these lines to `setupTest.js`:
306+
frontend-platform used environment variables to seed the configuration object, meaning it had default values at the time code is loaded based on `process.env` variables. frontend-base has a hard-coded, minimal configuration object that _must_ be augmented by a valid site config file at initialization time. This means that any tests that rely on configuration (e.g., via `getSiteConfig()`) must first initialize the configuration object. This can be done for tests by adding these lines to `setupTest.js`:
309307

310308
```
311309
import siteConfig from 'site.config';
312-
import { mergeConfig } from '@openedx/frontend-base';
310+
import { mergeSiteConfig } from '@openedx/frontend-base';
313311
314-
mergeConfig(siteConfig);
312+
mergeSiteConfig(siteConfig);
315313
316314
```
317315

@@ -413,7 +411,7 @@ Replace all imports from @edx/frontend-platform with @openedx/frontend-base
413411
- import { logInfo } from '@edx/frontend-platform/logging';
414412
- import { FormattedMessage } from '@edx/frontend-platform/i18n';
415413
+ import {
416-
+ getConfig,
414+
+ getSiteConfig,
417415
+ logInfo,
418416
+ FormattedMessage
419417
+ } from '@openedx/frontend-base';
@@ -520,6 +518,7 @@ Note that the .env files and env.config.js files also include a number of URLs f
520518
```
521519
// Creating a route role with for 'example' in an App
522520
const app: App = {
521+
...
523522
routes: [{
524523
path: '/example',
525524
id: 'example.page',
@@ -537,17 +536,16 @@ const examplePageUrl = getUrlForRouteRole('example');
537536
App-specific config values
538537
--------------------------
539538

540-
App-specific configuration can be expressed by adding a `standalone` section to SiteConfig which allows arbitrary config variables.
539+
App-specific configuration can be expressed by adding an `config` section to the app, allowing arbitrary variables:
541540

542541
```
543-
const config: SiteConfig = {
544-
// ... Other config
545-
546-
standalone: {
542+
const app: App = {
543+
...
544+
config: {
547545
appId: 'myapp',
548546
myCustomVariableName: 'my custom variable value',
549-
}
550-
}
547+
},
548+
};
551549
```
552550

553551
These variables can be used in code with the `getAppConfig` function:
@@ -556,16 +554,16 @@ These variables can be used in code with the `getAppConfig` function:
556554
getAppConfig('myapp').myCustomVariableName
557555
```
558556

559-
If you have fully converted your app over to the new architecture, you can add custom variables to the `config` object in your `App` definition and they will be available via `getAppConfig`.
557+
Or via `useAppConfig()` (with no need to specify the appId), if `AppProvider` is wrapping your app.
560558

561559

562560
Replace the .env.test file with configuration in site.config.test.tsx file
563561
==========================================================================
564562

565-
We're moving away from .env files because they're not expressive enough (only string types!) to configure an Open edX frontend. Instead, the test suite has been configured to expect a `site.config.test.tsx` file. If you're initializing an application in your tests, `frontend-base` will pick up this configuration and make it available to `getConfig()`, etc. If you need to manually access the variables, you can import `site.config` in your test files:
563+
We're moving away from .env files because they're not expressive enough (only string types!) to configure an Open edX frontend. Instead, the test suite has been configured to expect a `site.config.test.tsx` file. If you're initializing an application in your tests, `frontend-base` will pick up this configuration and make it available to `getSiteConfig()`, etc. If you need to manually access the variables, you can import `site.config` in your test files:
566564

567565
```diff
568-
+ import config from 'site.config';
566+
+ import siteConfig from 'site.config';
569567
```
570568

571569
The Jest configuration has been set up to find `site.config` in a `site.config.test.tsx` file.
@@ -577,26 +575,37 @@ A sample `site.config.test.tsx` file:
577575
```
578576
import { SiteConfig } from '@openedx/frontend-base';
579577
580-
const config: SiteConfig = {
581-
apps: [],
582-
accessTokenCookieName: 'edx-jwt-cookie-header-payload',
578+
const siteConfig: SiteConfig = {
579+
siteId: 'test',
580+
siteName: 'localhost',
583581
baseUrl: 'http://localhost:8080',
584-
csrfTokenApiPath: '/csrf/api/v1/token',
585-
languagePreferenceCookieName: 'openedx-language-preference',
586582
lmsBaseUrl: 'http://localhost:18000',
587583
loginUrl: 'http://localhost:18000/login',
588584
logoutUrl: 'http://localhost:18000/logout',
585+
environment: 'dev',
586+
apps: [{
587+
appId: 'test-app',
588+
routes: [{
589+
path: '/app1',
590+
element: (
591+
<div>Test App 1</div>
592+
),
593+
handle: {
594+
role: 'test-app-1'
595+
}
596+
}]
597+
}],
598+
accessTokenCookieName: 'edx-jwt-cookie-header-payload',
599+
csrfTokenApiPath: '/csrf/api/v1/token',
600+
languagePreferenceCookieName: 'openedx-language-preference',
589601
refreshAccessTokenApiPath: '/login_refresh',
590602
segmentKey: '',
591-
siteId: 'test',
592-
siteName: 'localhost',
593603
userInfoCookieName: 'edx-user-info',
594-
environment: 'dev',
595604
ignoredErrorRegex: null,
596605
publicPath: '/',
597606
};
598607
599-
export default config;
608+
export default siteConfig;
600609
```
601610

602611

@@ -642,11 +651,11 @@ You must then import this new stylesheet into your `site.config` file:
642651
```diff
643652
+ import './site.scss';
644653

645-
const config: SiteConfig = {
654+
const siteConfig: SiteConfig = {
646655
// config document
647656
}
648657

649-
export default config;
658+
export default siteConfig;
650659
```
651660

652661
This file will be ignored via `.gitignore`, as it is part of your 'site', not the module library.

runtime/analytics/interface.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
*
1010
* ```
1111
* import {
12-
* getConfig,
12+
* getSiteConfig,
1313
* getAuthenticatedHttpClient,
1414
* getLoggingService,
1515
* configureAnalytics,
1616
* SegmentAnalyticsService
1717
* } from '@openedx/frontend-base';
1818
*
1919
* configureAnalytics(SegmentAnalyticsService, {
20-
* config: getConfig(),
20+
* config: getSiteConfig(),
2121
* loggingService: getLoggingService(),
2222
* httpClient: getAuthenticatedHttpClient(),
2323
* });

runtime/auth/AxiosJwtAuthService.test.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import axios from 'axios';
33
import MockAdapter from 'axios-mock-adapter';
44
import Cookies from 'universal-cookie';
5-
import { getConfig } from '../config';
5+
import { getSiteConfig } from '../config';
66
import AxiosJwtAuthService from './AxiosJwtAuthService';
77

88
const mockLoggingService = {
@@ -12,7 +12,7 @@ const mockLoggingService = {
1212
};
1313

1414
const authOptions = {
15-
config: getConfig(),
15+
config: getSiteConfig(),
1616
loggingService: mockLoggingService,
1717
};
1818

runtime/auth/MockAuthService.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,22 @@ const optionsPropTypes = {
4545
* you could do the following to set up a MockAuthService for your test:
4646
*
4747
* ```
48-
* import { getConfig, mergeConfig, configureAuth, MockAuthService } from '@openedx/frontend-base';
48+
* import { getSiteConfig, mergeSiteConfig, configureAuth, MockAuthService } from '@openedx/frontend-base';
4949
* import MockAdapter from 'axios-mock-adapter';
5050
*
5151
* const mockLoggingService = {
5252
* logInfo: jest.fn(),
5353
* logError: jest.fn(),
5454
* };
55-
* mergeConfig({
55+
* mergeSiteConfig({
5656
* authenticatedUser: {
5757
* userId: 'abc123',
5858
* username: 'Mock User',
5959
* roles: [],
6060
* administrator: false,
6161
* },
6262
* });
63-
* configureAuth(MockAuthService, { config: getConfig(), loggingService: mockLoggingService });
63+
* configureAuth(MockAuthService, { config: getSiteConfig(), loggingService: mockLoggingService });
6464
* const mockAdapter = new MockAdapter(getAuthenticatedHttpClient());
6565
* // Mock calls for your tests. This configuration can be done in any sort of test setup.
6666
* mockAdapter.onGet(...);

runtime/auth/interface.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
* configureAuth,
1414
* fetchAuthenticatedUser,
1515
* getAuthenticatedHttpClient,
16-
* getConfig,
16+
* getSiteConfig,
1717
* getLoggingService
1818
* } from '@openedx/frontend-base';
1919
*
2020
* configureAuth({
2121
* loggingService: getLoggingService(),
22-
* config: getConfig(),
22+
* config: getSiteConfig(),
2323
* });
2424
*
2525
* const authenticatedUser = await fetchAuthenticatedUser(); // validates and decodes JWT token

runtime/config/getExternalLinkUrl.test.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import { getExternalLinkUrl, setConfig } from '.';
1+
import { getExternalLinkUrl, setSiteConfig } from '.';
22

33
describe('getExternalLinkUrl', () => {
44
afterEach(() => {
55
// Reset config after each test to avoid cross-test pollution
6-
setConfig({});
6+
setSiteConfig({});
77
});
88

99
it('should return the url passed in when externalLinkUrlOverrides is not set', () => {
10-
setConfig({});
10+
setSiteConfig({});
1111
const url = 'https://foo.example.com';
1212
expect(getExternalLinkUrl(url)).toBe(url);
1313
});
1414

1515
it('should return the url passed in when externalLinkUrlOverrides does not have the url mapping', () => {
16-
setConfig({
16+
setSiteConfig({
1717
externalLinkUrlOverrides: {
1818
'https://bar.example.com': 'https://mapped.example.com',
1919
},
@@ -25,39 +25,39 @@ describe('getExternalLinkUrl', () => {
2525
it('should return the mapped url when externalLinkUrlOverrides has the url mapping', () => {
2626
const url = 'https://foo.example.com';
2727
const mappedUrl = 'https://mapped.example.com';
28-
setConfig({ externalLinkUrlOverrides: { [url]: mappedUrl } });
28+
setSiteConfig({ externalLinkUrlOverrides: { [url]: mappedUrl } });
2929
expect(getExternalLinkUrl(url)).toBe(mappedUrl);
3030
});
3131

3232
it('should handle empty externalLinkUrlOverrides object', () => {
33-
setConfig({ externalLinkUrlOverrides: {} });
33+
setSiteConfig({ externalLinkUrlOverrides: {} });
3434
const url = 'https://foo.example.com';
3535
expect(getExternalLinkUrl(url)).toBe(url);
3636
});
3737

3838
it('should guard against empty string argument', () => {
3939
const fallbackResult = '#';
40-
setConfig({ externalLinkUrlOverrides: { foo: 'bar' } });
40+
setSiteConfig({ externalLinkUrlOverrides: { foo: 'bar' } });
4141
expect(getExternalLinkUrl(undefined)).toBe(fallbackResult);
4242
});
4343

4444
it('should guard against non-string argument', () => {
4545
const fallbackResult = '#';
46-
setConfig({ externalLinkUrlOverrides: { foo: 'bar' } });
46+
setSiteConfig({ externalLinkUrlOverrides: { foo: 'bar' } });
4747
expect(getExternalLinkUrl(null)).toBe(fallbackResult);
4848
expect(getExternalLinkUrl(42)).toBe(fallbackResult);
4949
});
5050

5151
it('should not throw if externalLinkUrlOverrides is not an object', () => {
52-
setConfig({ externalLinkUrlOverrides: null });
52+
setSiteConfig({ externalLinkUrlOverrides: null });
5353
const url = 'https://foo.example.com';
5454
expect(getExternalLinkUrl(url)).toBe(url);
55-
setConfig({ externalLinkUrlOverrides: 42 });
55+
setSiteConfig({ externalLinkUrlOverrides: 42 });
5656
expect(getExternalLinkUrl(url)).toBe(url);
5757
});
5858

5959
it('should work with multiple mappings', () => {
60-
setConfig({
60+
setSiteConfig({
6161
externalLinkUrlOverrides: {
6262
'https://a.example.com': 'https://mapped-a.example.com',
6363
'https://b.example.com': 'https://mapped-b.example.com',

0 commit comments

Comments
 (0)