Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: upgrade frontend-build, patch font-awesome, use React.StrictMode, refactor dashboard tabs #777

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/decisions/0009-patch-font-awesome-calc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 0009. Patch the `font-awesome` NPM package to resolve deprecation warnings

## Context

This micro-frontend relies on `font-awesome` for some icons, either via class names or component-based with imported icons. `font-awesome` is technically deprecated throughout the Open edX platform in favor of relying on the icon set
provided by `@edx/paragon/icons`. That said, `font-awesome` is still used in some places throughout this repository.

While upgrading `@edx/frontend-build` to the latest version (v12.8.57), it was observed that `sass-loader` was upgraded from v12 to v13, which throws Dart Sass `@warn` messages as official Webpack warnings. The warnings are about the need to use `calc()` in some CSS calculations used throughout the `font-awesome` SCSS. These warnings began manifesting as full screen Webpack overlays on the application even though there is no actual error, which will cause confusion and frustration for developers working with this micro-frontend.

`sass-loader` provides an option `warnRuleAsWarning` that may be set to `false` to revert to the previous v12 behavior of only showing the `@warn` messages as console warnings instead of Webpack warnings.

## Decision

Instead of modifying the Webpack configuration to change the default behavior of `sass-loader`'s `warnRuleAsWarning` option, we will instead patch `font-awesome` to resolve the deprecation warnings `sass-loader` outputs by wrapping its previous uses of `/` for division with `calc(...)`, where appropriate. For example:

**Before**

```scss
.#{$fa-css-prefix}-li {
top: (2em / 14);
}
```

**After**

```scss
.#{$fa-css-prefix}-li {
top: calc(2em / 14);
}
```

By doing so, we will no longer see any deprecation warnings related to `font-awesome`, either as Webpack warnings or console warnings.

We are already on the latest version of the `font-awesome` library (v4.7.0), which was last published 7 years ago. Font Awesome has since moved away from `font-awesome` in favor of `@fortawesome/react-fontawesome`. However, given our use of Font Awesome is deprecated and should be replaced with icons from `@edx/paragon/icons` anyways, the effort to migrate from `font-awesome` to `@fortawesome/react-fontawesome` is not justified.

### Creating the patch

In order to create the patch of `font-awesome`, the deprecation warnings were resolved by modifying the appropriate files in the `node_modules/font-awesome` directory and then running:

```shell
npx patch-package font-awesome
```

This command generates a patch file that is automatically applied when running `npm install`, essentially persisting the temporary changes in the `node_modules` directory (i.e., even if the `node_modules` directory gets deleted and re-created).

## Alternatives Considered

* Disable the `warnRuleAsWarning` option in `sass-loader`. This approach would prevent the deprecation warnings from showing as the full screen error overlay; however, the deprecation warnings will continue to show as console warnings when running `npm start` and `npm run build`.
* Migrate from `font-awesome` to `@fortawesome/react-fontawesome`. This approach was discarded as we should generally be moving away from Font Awesome in favor of `@edx/paragon/icons`.
* Move away from `font-awesome` in favor of icons from `@edx/paragon/icons` as part of the changes introduced at the time of this writing. This approach was discarded as the undertaking to identify suitable replacements for all `font-awesome` icons in use throughout this repository is not in scope due to the potential cross-functional collaboration needed with the design team to assist in finding those suitable icon replacements.
2,522 changes: 1,261 additions & 1,261 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
},
"devDependencies": {
"@edx/browserslist-config": "1.1.1",
"@edx/frontend-build": "12.8.17",
"@edx/frontend-build": "12.8.57",
"@tanstack/eslint-plugin-query": "4.29.9",
"@testing-library/jest-dom": "5.11.9",
"@testing-library/react": "11.2.7",
Expand Down
56 changes: 56 additions & 0 deletions patches/font-awesome+4.7.0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
diff --git a/node_modules/font-awesome/scss/_fixed-width.scss b/node_modules/font-awesome/scss/_fixed-width.scss
index b221c98..7102bba 100644
--- a/node_modules/font-awesome/scss/_fixed-width.scss
+++ b/node_modules/font-awesome/scss/_fixed-width.scss
@@ -1,6 +1,6 @@
// Fixed Width Icons
// -------------------------
.#{$fa-css-prefix}-fw {
- width: (18em / 14);
+ width: calc(18em / 14);
text-align: center;
}
diff --git a/node_modules/font-awesome/scss/_larger.scss b/node_modules/font-awesome/scss/_larger.scss
index 41e9a81..d76b240 100644
--- a/node_modules/font-awesome/scss/_larger.scss
+++ b/node_modules/font-awesome/scss/_larger.scss
@@ -3,8 +3,8 @@

/* makes the font 33% larger relative to the icon container */
.#{$fa-css-prefix}-lg {
- font-size: (4em / 3);
- line-height: (3em / 4);
+ font-size: calc(4em / 3);
+ line-height: calc(3em / 4);
vertical-align: -15%;
}
.#{$fa-css-prefix}-2x { font-size: 2em; }
diff --git a/node_modules/font-awesome/scss/_list.scss b/node_modules/font-awesome/scss/_list.scss
index 7d1e4d5..30bdd5a 100644
--- a/node_modules/font-awesome/scss/_list.scss
+++ b/node_modules/font-awesome/scss/_list.scss
@@ -11,9 +11,9 @@
position: absolute;
left: -$fa-li-width;
width: $fa-li-width;
- top: (2em / 14);
+ top: calc(2em / 14);
text-align: center;
&.#{$fa-css-prefix}-lg {
- left: -$fa-li-width + (4em / 14);
+ left: -$fa-li-width + calc(4em / 14);
}
}
diff --git a/node_modules/font-awesome/scss/_variables.scss b/node_modules/font-awesome/scss/_variables.scss
index 498fc4a..e04c68e 100644
--- a/node_modules/font-awesome/scss/_variables.scss
+++ b/node_modules/font-awesome/scss/_variables.scss
@@ -9,7 +9,7 @@ $fa-css-prefix: fa !default;
$fa-version: "4.7.0" !default;
$fa-border-color: #eee !default;
$fa-inverse: #fff !default;
-$fa-li-width: (30em / 14) !default;
+$fa-li-width: calc(30em / 14) !default;

$fa-var-500px: "\f26e";
$fa-var-address-book: "\f2b9";
77 changes: 51 additions & 26 deletions src/components/dashboard/DashboardPage.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {
useContext, useEffect, useMemo,
useContext, useEffect, useMemo, useState,
} from 'react';
import { Helmet } from 'react-helmet';
import { useHistory, useLocation } from 'react-router-dom';
Expand Down Expand Up @@ -28,6 +28,9 @@ const DashboardPage = () => {
const history = useHistory();
const { enterpriseConfig, authenticatedUser } = useContext(AppContext);
const { subscriptionPlan, showExpirationNotifications } = useContext(UserSubsidyContext);

const [activeTabKey, setActiveTabKey] = useState('courses');

// TODO: Create a context provider containing these 2 data fetch hooks to future proof when we need to use this data
const [learnerProgramsListData, programsFetchError] = useLearnerProgramsListData(enterpriseConfig.uuid);
const [pathwayProgressData, pathwayFetchError] = useInProgressPathwaysData(enterpriseConfig.uuid);
Expand All @@ -46,6 +49,51 @@ const DashboardPage = () => {
}, [history, state]);

const userFirstName = useMemo(() => authenticatedUser?.name.split(' ').shift(), [authenticatedUser]);

const dashboardTabs = useMemo(() => {
const tabs = [
<Tab eventKey="courses" title="Courses" key="dashboard-tab-courses">
<CoursesTabComponent canOnlyViewHighlightSets={canOnlyViewHighlightSets} />
</Tab>,
<Tab eventKey="programs" title="Programs" disabled={learnerProgramsListData.length === 0} key="dashboard-tab-programs">
<ProgramListingPage
canOnlyViewHighlightSets={canOnlyViewHighlightSets}
programsListData={learnerProgramsListData}
programsFetchError={programsFetchError}
/>
</Tab>,
];

if (features.FEATURE_ENABLE_PATHWAY_PROGRESS) {
tabs.push(
<Tab eventKey="pathways" title="Pathways" disabled={pathwayProgressData.length === 0} key="dashboard-tab-pathways">
<PathwayProgressListingPage
canOnlyViewHighlightSets={canOnlyViewHighlightSets}
pathwayProgressData={pathwayProgressData}
pathwayFetchError={pathwayFetchError}
/>
</Tab>,
);
}

if (features.FEATURE_ENABLE_MY_CAREER) {
tabs.push(
<Tab eventKey="my-career" title="My Career" key="dashboard-tab-my-career">
{activeTabKey === 'my-career' && <MyCareerTab />}
</Tab>,
);
}

return tabs;
}, [
activeTabKey,
canOnlyViewHighlightSets,
learnerProgramsListData,
pathwayFetchError,
pathwayProgressData,
programsFetchError,
]);

const PAGE_TITLE = `Dashboard - ${enterpriseConfig.name}`;

return (
Expand All @@ -56,31 +104,8 @@ const DashboardPage = () => {
{userFirstName ? `Welcome, ${userFirstName}!` : 'Welcome!'}
</h2>
<EnterpriseLearnerFirstVisitRedirect />
<Tabs defaultActiveKey="courses">
<Tab eventKey="courses" title="Courses">
<CoursesTabComponent canOnlyViewHighlightSets={canOnlyViewHighlightSets} />
</Tab>
<Tab eventKey="programs" title="Programs" disabled={learnerProgramsListData.length === 0}>
<ProgramListingPage
canOnlyViewHighlightSets={canOnlyViewHighlightSets}
programsListData={learnerProgramsListData}
programsFetchError={programsFetchError}
/>
</Tab>
{features.FEATURE_ENABLE_PATHWAY_PROGRESS && (
<Tab eventKey="pathways" title="Pathways" disabled={pathwayProgressData.length === 0}>
<PathwayProgressListingPage
canOnlyViewHighlightSets={canOnlyViewHighlightSets}
pathwayProgressData={pathwayProgressData}
pathwayFetchError={pathwayFetchError}
/>
</Tab>
)}
{features.FEATURE_ENABLE_MY_CAREER && (
<Tab eventKey="my-career" title="My Career">
<MyCareerTab />
</Tab>
)}
<Tabs activeKey={activeTabKey} onSelect={(tabKey) => setActiveTabKey(tabKey)}>
{dashboardTabs}
</Tabs>
{enterpriseConfig.showIntegrationWarning && <IntegrationWarningModal isOpen />}
{subscriptionPlan && showExpirationNotifications && <SubscriptionExpirationModal />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ export const useCourseUpgradeData = ({
setSubsidyForCourse(getSubsidyToApplyForCourse({ applicableCouponCode: couponSubsidy }));
setCouponUpgradeUrl(url);
setCourseRunPrice(courseRunDetails.firstEnrollablePaidSeatPrice);
return;
}
} catch (error) {
logError(error);
Expand Down
2 changes: 1 addition & 1 deletion src/components/my-career/MyCareerTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const MyCareerTab = () => {
return (
<div>
<SearchData>
{ !learnerCurrentJobID ? (
{!learnerCurrentJobID ? (
<AddJobRole submitClickHandler={setLearnerProfileState} />
) : (
<VisualizeCareer jobId={learnerCurrentJobID} submitClickHandler={setLearnerProfileState} />
Expand Down
14 changes: 12 additions & 2 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,21 @@ import { App } from './components/app';
import './index.scss';

subscribe(APP_READY, () => {
ReactDOM.render(<App />, document.getElementById('root'));
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
);
});

subscribe(APP_INIT_ERROR, (error) => {
ReactDOM.render(<ErrorPage message={error.message} />, document.getElementById('root'));
ReactDOM.render(
<React.StrictMode>
<ErrorPage message={error.message} />
</React.StrictMode>,
document.getElementById('root'),
);
});

initialize({
Expand Down