Skip to content

Commit a6755e2

Browse files
committed
fix: use getConfig in order to support runtime configuration
Before, gradebook was reading config from `process.env` directly, which locked the app into using only static (build-time) configuration. In order to enable dynamic (runtime) configuration, we update gradebook to use frontend-platform's standard configuration interface: `mergeConfig()` and `getConfig()`. Bump version from 1.5.0 to 1.6.0. (I would normally just do a patch release for a fix, but the version was hasn't been bumped for a while, so adding in full runtime configuration support seemed like it warranted a proper minor version bump.)
1 parent 50bf7d2 commit a6755e2

File tree

9 files changed

+37
-33
lines changed

9 files changed

+37
-33
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@edx/frontend-app-gradebook",
3-
"version": "1.5.0",
3+
"version": "1.6.0",
44
"description": "edx editable gradebook-ui to manipulate grade overrides on subsections",
55
"repository": {
66
"type": "git",

src/components/GradebookHeader/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import { connect } from 'react-redux';
44

5+
import { getConfig } from '@edx/frontend-platform';
56
import { FormattedMessage } from '@edx/frontend-platform/i18n';
67
import { Button } from '@edx/paragon';
78

8-
import { configuration } from 'config';
99
import { views } from 'data/constants/app';
1010
import actions from 'data/actions';
1111
import selectors from 'data/selectors';
@@ -25,7 +25,7 @@ export class GradebookHeader extends React.Component {
2525
}
2626

2727
lmsInstructorDashboardUrl = courseId => (
28-
`${configuration.LMS_BASE_URL}/courses/${courseId}/instructor`
28+
`${getConfig().LMS_BASE_URL}/courses/${courseId}/instructor`
2929
);
3030

3131
handleToggleViewClick() {

src/config/index.js

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/data/services/lms/urls.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import { getConfig } from '@edx/frontend-platform';
12
import { StrictDict } from 'utils';
2-
import { configuration } from 'config';
33
import { historyRecordLimit } from './constants';
44
import { filterQuery, stringifyUrl } from './utils';
55

6-
const baseUrl = `${configuration.LMS_BASE_URL}`;
6+
const baseUrl = `${getConfig().LMS_BASE_URL}`;
77

88
const courseId = window.location.pathname.split('/').filter(Boolean).pop() || '';
99

src/data/store.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProductio
44
import { createLogger } from 'redux-logger';
55
import { createMiddleware } from 'redux-beacon';
66
import Segment from '@redux-beacon/segment';
7+
import { getConfig } from '@edx/frontend-platform';
78

89
import actions from './actions';
910
import selectors from './selectors';
1011
import reducers from './reducers';
1112
import eventsMap from './services/segment/mapping';
12-
import { configuration } from '../config';
1313

1414
export const createStore = () => {
1515
const loggerMiddleware = createLogger();
1616

1717
const middleware = [thunkMiddleware, loggerMiddleware];
1818
// Conditionally add the segmentMiddleware only if the SEGMENT_KEY environment variable exists.
19-
if (configuration.SEGMENT_KEY) {
19+
if (getConfig().SEGMENT_KEY) {
2020
middleware.push(createMiddleware(eventsMap, Segment()));
2121
}
2222
const store = redux.createStore(

src/data/store.test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProductio
44
import { createLogger } from 'redux-logger';
55
import { createMiddleware } from 'redux-beacon';
66
import Segment from '@redux-beacon/segment';
7+
import { getConfig } from '@edx/frontend-platform';
78

89
import actions from './actions';
910
import selectors from './selectors';
1011
import reducers from './reducers';
1112
import eventsMap from './services/segment/mapping';
12-
import { configuration } from '../config';
1313

1414
import exportedStore, { createStore } from './store';
1515

@@ -22,10 +22,10 @@ jest.mock('redux-logger', () => ({
2222
createLogger: () => 'logger',
2323
}));
2424
jest.mock('redux-thunk', () => 'thunkMiddleware');
25-
jest.mock('../config', () => ({
26-
configuration: {
25+
jest.mock('@edx/frontend-platform', () => ({
26+
getConfig: () => ({
2727
SEGMENT_KEY: 'a-fake-segment-key',
28-
},
28+
}),
2929
}));
3030
jest.mock('redux-beacon', () => ({
3131
createMiddleware: jest.fn((map, model) => ({ map, model })),
@@ -60,17 +60,17 @@ describe('store aggregator module', () => {
6060
});
6161
});
6262
describe('if no SEGMENT_KEY', () => {
63-
const key = configuration.SEGMENT_KEY;
63+
const key = getConfig().SEGMENT_KEY;
6464
beforeEach(() => {
65-
configuration.SEGMENT_KEY = false;
65+
getConfig().SEGMENT_KEY = false;
6666
});
6767
it('exports thunk and logger middleware, composed and applied with dev tools', () => {
6868
expect(createStore().middleware).toEqual(
6969
composeWithDevTools(applyMiddleware(thunkMiddleware, createLogger())),
7070
);
7171
});
7272
afterEach(() => {
73-
configuration.SEGMENT_KEY = key;
73+
getConfig().SEGMENT_KEY = key;
7474
});
7575
});
7676
});

src/index.jsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ReactDOM from 'react-dom';
77
import {
88
APP_READY,
99
initialize,
10+
mergeConfig,
1011
subscribe,
1112
} from '@edx/frontend-platform';
1213
import { messages as headerMessages } from '@edx/frontend-component-header';
@@ -20,6 +21,22 @@ subscribe(APP_READY, () => {
2021
});
2122

2223
initialize({
24+
handlers: {
25+
config: () => {
26+
mergeConfig({
27+
BASE_URL: process.env.BASE_URL,
28+
LMS_BASE_URL: process.env.LMS_BASE_URL,
29+
LOGIN_URL: process.env.LOGIN_URL,
30+
LOGOUT_URL: process.env.LOGOUT_URL,
31+
CSRF_TOKEN_API_PATH: process.env.CSRF_TOKEN_API_PATH,
32+
REFRESH_ACCESS_TOKEN_ENDPOINT: process.env.REFRESH_ACCESS_TOKEN_ENDPOINT,
33+
DATA_API_BASE_URL: process.env.DATA_API_BASE_URL,
34+
SECURE_COOKIES: process.env.NODE_ENV !== 'development',
35+
SEGMENT_KEY: process.env.SEGMENT_KEY,
36+
ACCESS_TOKEN_COOKIE_NAME: process.env.ACCESS_TOKEN_COOKIE_NAME,
37+
});
38+
},
39+
},
2340
messages: [
2441
appMessages,
2542
headerMessages,

src/index.test.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,13 @@ describe('app registry', () => {
4646
ReactDOM.render(<App />, document.getElementById('root')),
4747
);
4848
});
49-
test('initialize is called with footerMessages and requireAuthenticatedUser', () => {
49+
test('initialize is called with requireAuthenticatedUser, messages, and a config handler', () => {
5050
expect(initialize).toHaveBeenCalledWith({
5151
messages: [appMessages, headerMessages, footerMessages],
5252
requireAuthenticatedUser: true,
53+
handlers: {
54+
config: expect.any(Function),
55+
},
5356
});
5457
});
5558
});

src/segment.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// The code in this file is from Segment's website:
22
// https://segment.com/docs/sources/website/analytics.js/quickstart/
3-
import { configuration } from './config';
3+
import { getConfig } from '@edx/frontend-platform';
44

55
(function () {
66
// Create a queue, but don't obliterate an existing one!
@@ -81,5 +81,5 @@ import { configuration } from './config';
8181

8282
// Load Analytics.js with your key, which will automatically
8383
// load the tools you've enabled for your account. Boosh!
84-
analytics.load(configuration.SEGMENT_KEY);
84+
analytics.load(getConfig().SEGMENT_KEY);
8585
}());

0 commit comments

Comments
 (0)