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

Upgrade react-router to v6 #3261

Merged
merged 28 commits into from
Feb 2, 2022
Merged

Upgrade react-router to v6 #3261

merged 28 commits into from
Feb 2, 2022

Conversation

nickclyde
Copy link
Member

@nickclyde nickclyde commented Jan 21, 2022

Related Issue or Background Info

Changes Proposed

  • Update react-router-dom to version 6.2.1. The major version upgrade from v5 to v6 introduced a number of breaking changes that touch a lot of different parts of the app. I followed this upgrade guide, making the following changes:
    • Switch to the hooks API introduced in v5.1 so that we don't have to pass the match prop down to child routes to access things like location and params. This is a huge improvement for code cleanliness!
    • <Route component={SomeComponent}> /> now becomes <Route element={<SomeComponent />} />, which allows us to easily pass props into routes! More info on the benefits of this here
    • Replace all uses of withRouter with hooks
    • Convert all <Redirect> components into <Navigate> components
    • Refactor the <GuardedRoute> and <ProtectedRoute> components into ones that get passed into an element prop of a <Route />, rather than returning a <Route /> component themselves. You can read a little more about why this change was made here.
    • Upgrade all <Switch> elements to <Routes> - see here, but the new <Routes> component allows relative routing!
    • Start using relative routes and links. You may have noticed before that some of our app components like PatientApp used to include an additional <Router> component with a basename prop so that we didn't have to prefix every route with /pxp. With v6 that's no longer needed because <Route> components can now be nested and the paths always include the parent route's path! The same goes for <Link> and <Navigate> components.
    • <Route> paths no longer need a leading slash, and can end in a wildcard * to match all subpaths. More info
    • Convert all uses of useHistory to useNavigate. More info
    • Related to the above, since useHistory is no longer available, we can't pass history into our Application Insights config. However, I don't think it was needed in the first place according to this comment. Since we have enableAutoRouteTracking: true set, it should already record any route changes automatically (see docs here)
    • Remove activeClassName and activeStyle props from Links
    • Last, the react-router team removed support for the <Prompt> component from this release in order to expedite the release. However, I was able to use a reimplementation found in this GH issue to keep that functionality since we use it in a couple places in the app. However, the team plans to readd it at some point, so I will keep an eye out and be sure to switch to the official API when it comes back.
  • These changes broke a lot of our tests, so I had to change a bunch of the tests, especially the ones that use <MemoryRouter>
  • Remove the react-router dependency. The react-router package includes everything from both react-router-dom and react-router-native, but we only use react-router-dom. Also updated all imports across the app to use react-router-dom
  • Added a REACT_APP_DISABLE_MAINTENANCE_BANNER environment variable that disables the maintenance banner, because it was causing issues on the e2e tests.
  • Added a /reload-app route which just redirects back to /. This allows us to retrigger the whoami query (for example after spoofing into an org) without actually refreshing the page and having to reload the bundle.

Additional Information

  • Another change that would be interesting is to use the <Outlet> component (docs here). This would allow us to place all of our <Route> components into a single tree in index.tsx, and then use the <Outlet> component in <Route> elements to refer to the child routes. This would be another big win for code cleanliness!
    • I took a stab at implementing, but wasn't sure how to pass state back up to the parent component, so I'm going to skip this for now.

Screenshots / Demos

Checklist for Author and Reviewer

Infrastructure

  • Consult the results of the terraform-plan job inside the "Terraform Checks" workflow run for this PR. Confirm that there are no unexpected changes!

Design

  • Any UI/UX changes have a designer as a reviewer, and changes have been approved
  • Any large-scale changes have been deployed to test, dev, or pentest and smoke-tested by both the engineering and design teams

Content

  • Any content changes (including new error messages) have been approved by content team

Support

  • Any changes that might generate new support requests have been flagged to the support team
  • Any changes to support infrastructure have been demo'd to support team

Testing

  • Includes a summary of what a code reviewer should verify

Changes are Backwards Compatible

  • Database changes are submitted as a separate PR
    • Any new tables that do not contain PII are accompanied by a GRANT SELECT to the no-PHI user
    • Any changes to tables that have custom no-PHI views are accompanied by changes to those views
      (including re-granting permission to the no-PHI user if need be)
    • Liquibase rollback has been tested locally using ./gradlew liquibaseRollbackSQL or liquibaseRollback
    • Each new changeset has a corresponding tag
  • GraphQL schema changes are backward compatible with older version of the front-end

Security

  • Changes with security implications have been approved by a security engineer (changes to authentication, encryption, handling of PII, etc.)
  • Any dependencies introduced have been vetted and discussed

Cloud

  • DevOps team has been notified if PR requires ops support
  • If there are changes that cannot be tested locally, this has been deployed to our Azure test, dev, or pentest environment for verification

@nickclyde nickclyde temporarily deployed to Test January 26, 2022 00:26 Inactive
Copy link
Contributor

@emmastephenson emmastephenson left a comment

Choose a reason for hiding this comment

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

Overall LGTM, thanks for putting so much work into this! Just a couple questions and comments.

<ProtectedRoute
requiredPermissions={appPermissions.people.canView}
userPermissions={data.whoami.permissions}
element={<ManagePatientsContainer />}
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if it's worth defining this protected route as a variable, since it's repeated under the regular patients route too.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah not a bad idea! The reason I had to duplicate this route is because v5 supported optional URL params like /patients/:pageNumber? which would match both /patients and /patients/1, but v6 no longer supports that. Hence the need for two routes. But I will definitely DRY it up

Copy link
Member Author

Choose a reason for hiding this comment

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

Soooo I tried to do this, and for some reason it broke the patients page. It kept throwing "The operation is insecure", and I couldn't figure out why 🤔 so I reverted for now.

element={
<ProtectedRoute
requiredPermissions={appPermissions.settings.canView}
userPermissions={data.whoami.permissions}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we may want to extract this data.whoami.permissions out to a variable

Copy link
Member Author

Choose a reason for hiding this comment

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

Same as above - moving to a shorter named const seemed to cause issues, so I reverted

@@ -31,11 +30,6 @@ const createTelemetryService = () => {
enableAutoRouteTracking: true,
loggingLevelTelemetry: 2,
maxBatchInterval: 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you deploy this to one of the lower environments and double-check that the telemetry still works as anticipated?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good call, I will do that today.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! Can you let me know what the outcome was?

Copy link
Member Author

Choose a reason for hiding this comment

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

Just messed around in dev and checked app insights, looks like we are still receiving everything, let me know if there's anything in particular I should look for, but it's still recording all requests and our custom events:
image

<Redirect
push
to={{
pathname: `${window.location.pathname.split("/uac")[1]}/verify`,
Copy link
Contributor

Choose a reason for hiding this comment

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

so happy to see these gone!

@@ -108,6 +108,14 @@ const Header: React.FC<{}> = () => {
);
};

const activeNavItem = "active-nav-item prime-nav-link";
Copy link
Contributor

Choose a reason for hiding this comment

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

nice 👍

element={
<GuardedRoute auth={auth} element={<AoEPatientFormContainer />} />
}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we might be able to kill this route, AFAIK we removed the ability for patients to fill out the AoE.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's true, but I think @zdeveloper may be working on cleaning these routes out in another PR IIRC.

Copy link
Contributor

@fzhao99 fzhao99 left a comment

Choose a reason for hiding this comment

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

thanks again for walking me through everything!

frontend/src/app/commonComponents/Header.tsx Outdated Show resolved Hide resolved
@nickclyde nickclyde temporarily deployed to Dev January 27, 2022 22:03 Inactive
@nickclyde nickclyde mentioned this pull request Jan 28, 2022
17 tasks
@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 3 Code Smells

81.4% 81.4% Coverage
0.0% 0.0% Duplication

@nickclyde nickclyde merged commit 46bb4cd into main Feb 2, 2022
@nickclyde nickclyde deleted the nick/upgrade-react-router branch February 2, 2022 02:07
zdeveloper added a commit that referenced this pull request Feb 2, 2022
nickclyde pushed a commit that referenced this pull request Feb 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants