Skip to content

Commit 8785e30

Browse files
feat: add external links override support
1 parent b76b003 commit 8785e30

10 files changed

Lines changed: 108 additions & 19 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
Override External URLs
2+
======================
3+
4+
What is getExternalLinkUrl?
5+
---------------------------
6+
7+
The `getExternalLinkUrl` function is a utility from `@edx/frontend-platform` that allows for centralized management of external URLs. It enables the override of external links through configuration, making it possible to customize external references without modifying the source code directly.
8+
9+
URLs wrapped with getExternalLinkUrl
10+
------------------------------------
11+
Use cases:
12+
13+
1. **Accessibility Page** (`src/accessibility-page/AccessibilityPage.jsx`)
14+
- `COMMUNITY_ACCESSIBILITY_LINK` - Points to community accessibility resources: https://www.edx.org/accessibility
15+
16+
2. **Course Outline** (if applicable)
17+
- Documentation links
18+
- Help resources
19+
20+
3. **Other pages** (search for `getExternalLinkUrl` usage across the codebase)
21+
- Help documentation
22+
- External tool integrations
23+
24+
Currently, the following external URLs are wrapped with `getExternalLinkUrl` in the authoring application:
25+
26+
- 'https://www.edx.org/accessibility'
27+
- 'https://docs.openedx.org/en/latest/educators/concepts/exercise_tools/about_multi_select.html'
28+
- 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_multi_select.html'
29+
- 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_dropdown.html'
30+
- 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/manage_numerical_input_problem.html'
31+
- 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_text_input.html'
32+
- 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/social_sharing.html'
33+
- 'https://docs.openedx.org/en/latest/educators/references/course_development/exercise_tools/guide_problem_types.html#advanced-problem-types'
34+
- 'https://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/developing_course/course_components.html#components-that-contain-other-components'
35+
- 'https://openai.com/api-data-privacy'
36+
- 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/create_new_library.html'
37+
- 'https://bigbluebutton.org/privacy-policy/'
38+
- 'https://creativecommons.org/about'
39+
40+
How to Override External URLs
41+
-----------------------------
42+
43+
To override external URLs, you can use the frontend platform's configuration system.
44+
This object should be added to the config object defined in the env.config.[js,jsx,ts,tsx], and must be named externalLinkUrlOverrides.
45+
46+
1. **Environment Configuration**
47+
Add the URL overrides to your environment configuration:
48+
49+
.. code-block:: javascript
50+
51+
const config = {
52+
// Other config options...
53+
externalLinkUrlOverrides: {
54+
'https://www.edx.org/accessibility': 'https://your-custom-domain.com/accessibility',
55+
// Add other URL overrides here
56+
}
57+
};
58+
59+
Examples
60+
--------
61+
62+
**Original URL:** Default community accessibility link
63+
**Override:** Your institution's accessibility policy page
64+
65+
.. code-block:: javascript
66+
67+
// In your app configuration
68+
getExternalLinkUrl('https://www.edx.org/accessibility')
69+
// Returns: 'https://your-custom-domain.com/accessibility'
70+
// Instead of the default Open edX community link
71+
72+
Benefits
73+
--------
74+
75+
- **Customization**: Institutions can point to their own resources
76+
- **Maintainability**: URLs can be changed without code modifications
77+
- **Consistency**: Centralized URL management across the application
78+
- **Flexibility**: Different environments can have different external links

plugins/course-apps/live/BBBSettings.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, useState } from 'react';
2-
import { getConfig } from '@edx/frontend-platform';
2+
import { getConfig, getExternalLinkUrl } from '@edx/frontend-platform';
33
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
44
import { Form, Hyperlink } from '@openedx/paragon';
55
import PropTypes from 'prop-types';
@@ -93,7 +93,7 @@ const BbbSettings = ({
9393
<span data-testid="free-plan-message">
9494
{intl.formatMessage(messages.freePlanMessage)}
9595
<Hyperlink
96-
destination="https://bigbluebutton.org/privacy-policy/"
96+
destination={getExternalLinkUrl('https://bigbluebutton.org/privacy-policy/')}
9797
target="_blank"
9898
rel="noopener noreferrer"
9999
showLaunchIcon

plugins/course-apps/xpert_unit_summary/settings-modal/SettingsModal.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useIntl } from '@edx/frontend-platform/i18n';
2+
import { getExternalLinkUrl } from '@edx/frontend-platform';
23
import {
34
ActionRow,
45
Alert,
@@ -276,7 +277,7 @@ const SettingsModal = ({
276277
<div className="py-1">
277278
<Hyperlink
278279
className="text-primary-500"
279-
destination="https://openai.com/api-data-privacy"
280+
destination={getExternalLinkUrl('https://openai.com/api-data-privacy')}
280281
target="_blank"
281282
rel="noreferrer noopener"
282283
>

src/accessibility-page/AccessibilityPage.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import { useIntl } from '@edx/frontend-platform/i18n';
3+
import { getExternalLinkUrl } from '@edx/frontend-platform';
34
import { Helmet } from 'react-helmet';
45
import { Container } from '@openedx/paragon';
56
import { StudioFooterSlot } from '@edx/frontend-component-footer';
@@ -25,7 +26,10 @@ const AccessibilityPage = () => {
2526
<Header isHiddenMainMenu />
2627
<Container size="xl" classNamae="px-4">
2728
<AccessibilityBody
28-
{...{ email: ACCESSIBILITY_EMAIL, communityAccessibilityLink: COMMUNITY_ACCESSIBILITY_LINK }}
29+
{...{
30+
email: ACCESSIBILITY_EMAIL,
31+
communityAccessibilityLink: getExternalLinkUrl(COMMUNITY_ACCESSIBILITY_LINK),
32+
}}
2933
/>
3034
<AccessibilityForm accessibilityEmail={ACCESSIBILITY_EMAIL} />
3135
</Container>

src/course-unit/sidebar/SplitTestSidebarInfo.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import { Card, Hyperlink, Stack } from '@openedx/paragon';
33
import { useIntl } from '@edx/frontend-platform/i18n';
4+
import { getExternalLinkUrl } from '@edx/frontend-platform';
45

56
import messages from './messages';
67

@@ -44,7 +45,7 @@ const SplitTestSidebarInfo = () => {
4445
<hr className="course-split-test-sidebar-devider my-4" />
4546
<Hyperlink
4647
showLaunchIcon={false}
47-
destination="https://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/developing_course/course_components.html#components-that-contain-other-components"
48+
destination={getExternalLinkUrl('https://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/developing_course/course_components.html#components-that-contain-other-components')}
4849
className="btn btn-outline-primary btn-sm"
4950
target="_blank"
5051
>

src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '@openedx/paragon';
1313
import { ArrowBack } from '@openedx/paragon/icons';
1414
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
15+
import { getExternalLinkUrl } from '@edx/frontend-platform';
1516
import {
1617
AdvancedProblemType,
1718
AdvanceProblems,
@@ -91,7 +92,7 @@ const AdvanceTypeSelect: React.FC<Props> = ({
9192
</Form.RadioSet>
9293
</Form.Group>
9394
<Hyperlink
94-
destination="https://docs.openedx.org/en/latest/educators/references/course_development/exercise_tools/guide_problem_types.html#advanced-problem-types"
95+
destination={getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/references/course_development/exercise_tools/guide_problem_types.html#advanced-problem-types')}
9596
target="_blank"
9697
>
9798
<FormattedMessage {...messages.learnMoreAdvancedButtonLabel} />

src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
44
import {
55
FormattedMessage,
66
} from '@edx/frontend-platform/i18n';
7+
import { getExternalLinkUrl } from '@edx/frontend-platform';
78
import {
89
Stack,
910
Hyperlink,
@@ -30,7 +31,7 @@ const LicenseDisplay = ({
3031
{license === LicenseTypes.creativeCommons && (
3132
<Hyperlink
3233
className="text-primary-500 x-small"
33-
destination="https://creativecommons.org/about"
34+
destination={getExternalLinkUrl('https://creativecommons.org/about')}
3435
target="_blank"
3536
>
3637
<FormattedMessage {...messages.viewLicenseDetailsLabel} />

src/editors/containers/VideoEditor/components/VideoSettingsModal/components/SocialShareWidget/index.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
FormattedMessage,
66
useIntl,
77
} from '@edx/frontend-platform/i18n';
8+
import { getExternalLinkUrl } from '@edx/frontend-platform';
89
import {
910
Hyperlink,
1011
Form,
@@ -30,7 +31,7 @@ const SocialShareWidget = ({
3031
const intl = useIntl();
3132
const isSetByCourse = allowVideoSharing.level === 'course';
3233
const videoSharingEnabled = isLibrary ? videoSharingEnabledForAll : videoSharingEnabledForCourse;
33-
const learnMoreLink = videoSharingLearnMoreLink || 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/social_sharing.html';
34+
const learnMoreLink = videoSharingLearnMoreLink || getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/social_sharing.html');
3435
const onSocialSharingCheckboxChange = hooks.useTrackSocialSharingChange({ updateField });
3536

3637
const getSubtitle = () => {

src/editors/data/constants/problem.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getExternalLinkUrl } from '@edx/frontend-platform';
12
import { StrictDict } from '../../utils';
23
import singleSelect from '../images/singleSelect.png';
34
import multiSelect from '../images/multiSelect.png';
@@ -41,7 +42,7 @@ export const getProblemTypes = (formatMessage) => ({
4142
preview: singleSelect,
4243
previewDescription: formatMessage(problemMessages.singleSelectDescription),
4344
description: formatMessage(problemMessages.singleSelectInstruction),
44-
helpLink: 'https://docs.openedx.org/en/latest/educators/concepts/exercise_tools/about_multi_select.html',
45+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/concepts/exercise_tools/about_multi_select.html'),
4546
prev: ProblemTypeKeys.TEXTINPUT,
4647
next: ProblemTypeKeys.MULTISELECT,
4748
template: basicProblemTemplates.singleSelect.olx,
@@ -52,7 +53,7 @@ export const getProblemTypes = (formatMessage) => ({
5253
preview: multiSelect,
5354
previewDescription: formatMessage(problemMessages.multiSelectDescription),
5455
description: formatMessage(problemMessages.multiSelectInstruction),
55-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_multi_select.html',
56+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_multi_select.html'),
5657
next: ProblemTypeKeys.DROPDOWN,
5758
prev: ProblemTypeKeys.SINGLESELECT,
5859
template: basicProblemTemplates.multiSelect.olx,
@@ -63,7 +64,7 @@ export const getProblemTypes = (formatMessage) => ({
6364
preview: dropdown,
6465
previewDescription: formatMessage(problemMessages.dropdownDescription),
6566
description: formatMessage(problemMessages.dropdownInstruction),
66-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_dropdown.html',
67+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_dropdown.html'),
6768
next: ProblemTypeKeys.NUMERIC,
6869
prev: ProblemTypeKeys.MULTISELECT,
6970
template: basicProblemTemplates.dropdown.olx,
@@ -74,7 +75,7 @@ export const getProblemTypes = (formatMessage) => ({
7475
preview: numericalInput,
7576
previewDescription: formatMessage(problemMessages.numericalInputDescription),
7677
description: formatMessage(problemMessages.numericalInputInstruction),
77-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/manage_numerical_input_problem.html',
78+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/manage_numerical_input_problem.html'),
7879
next: ProblemTypeKeys.TEXTINPUT,
7980
prev: ProblemTypeKeys.DROPDOWN,
8081
template: basicProblemTemplates.numeric.olx,
@@ -85,7 +86,7 @@ export const getProblemTypes = (formatMessage) => ({
8586
preview: textInput,
8687
previewDescription: formatMessage(problemMessages.textInputDescription),
8788
description: formatMessage(problemMessages.textInputInstruction),
88-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_text_input.html',
89+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_text_input.html'),
8990
prev: ProblemTypeKeys.NUMERIC,
9091
next: ProblemTypeKeys.SINGLESELECT,
9192
template: basicProblemTemplates.textInput.olx,
@@ -105,7 +106,7 @@ export const ProblemTypes = StrictDict({
105106
preview: singleSelect,
106107
previewDescription: 'Learners must select the correct answer from a list of possible options.',
107108
description: 'Enter your single select answers below and select which choices are correct. Learners must choose one correct answer.',
108-
helpLink: 'https://docs.openedx.org/en/latest/educators/concepts/exercise_tools/about_multi_select.html',
109+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/concepts/exercise_tools/about_multi_select.html'),
109110
prev: ProblemTypeKeys.TEXTINPUT,
110111
next: ProblemTypeKeys.MULTISELECT,
111112
template: basicProblemTemplates.singleSelect.olx,
@@ -116,7 +117,7 @@ export const ProblemTypes = StrictDict({
116117
preview: multiSelect,
117118
previewDescription: 'Learners must select all correct answers from a list of possible options.',
118119
description: 'Enter your multi select answers below and select which choices are correct. Learners must choose all correct answers.',
119-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_multi_select.html',
120+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_multi_select.html'),
120121
next: ProblemTypeKeys.DROPDOWN,
121122
prev: ProblemTypeKeys.SINGLESELECT,
122123
template: basicProblemTemplates.multiSelect.olx,
@@ -127,7 +128,7 @@ export const ProblemTypes = StrictDict({
127128
preview: dropdown,
128129
previewDescription: 'Learners must select the correct answer from a list of possible options',
129130
description: 'Enter your dropdown answers below and select which choice is correct. Learners must select one correct answer.',
130-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_dropdown.html',
131+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_dropdown.html'),
131132
next: ProblemTypeKeys.NUMERIC,
132133
prev: ProblemTypeKeys.MULTISELECT,
133134
template: basicProblemTemplates.dropdown.olx,
@@ -138,7 +139,7 @@ export const ProblemTypes = StrictDict({
138139
preview: numericalInput,
139140
previewDescription: 'Specify one or more correct numeric answers, submitted in a response field.',
140141
description: 'Enter correct numerical input answers below. Learners must enter one correct answer.',
141-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/manage_numerical_input_problem.html',
142+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/manage_numerical_input_problem.html'),
142143
next: ProblemTypeKeys.TEXTINPUT,
143144
prev: ProblemTypeKeys.DROPDOWN,
144145
template: basicProblemTemplates.numeric.olx,
@@ -149,7 +150,7 @@ export const ProblemTypes = StrictDict({
149150
preview: textInput,
150151
previewDescription: 'Specify one or more correct text answers, including numbers and special characters, submitted in a response field.',
151152
description: 'Enter your text input answers below and select which choices are correct. Learners must enter one correct answer.',
152-
helpLink: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_text_input.html',
153+
helpLink: getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/add_text_input.html'),
153154
prev: ProblemTypeKeys.NUMERIC,
154155
next: ProblemTypeKeys.SINGLESELECT,
155156
template: basicProblemTemplates.textInput.olx,

src/studio-home/tabs-section/libraries-v2-tab/WelcomeLibrariesV2Alert.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Alert, Button, Hyperlink } from '@openedx/paragon';
22
import { FormattedMessage } from '@edx/frontend-platform/i18n';
3+
import { getExternalLinkUrl } from '@edx/frontend-platform';
34
import { useNavigate } from 'react-router-dom';
45

56
import { useLibrariesV1Data } from '@src/studio-home/data/apiHooks';
@@ -10,7 +11,7 @@ const libraryDocsLink = (
1011
<Hyperlink
1112
target="_blank"
1213
showLaunchIcon={false}
13-
destination="https://docs.openedx.org/en/latest/educators/how-tos/course_development/create_new_library.html"
14+
destination={getExternalLinkUrl('https://docs.openedx.org/en/latest/educators/how-tos/course_development/create_new_library.html')}
1415
>
1516
<FormattedMessage {...messages.alertLibrariesDocLinkText} />
1617
</Hyperlink>

0 commit comments

Comments
 (0)