Skip to content

Convert the App.js root route tree to react-router v6 Routes - #425

Merged
cigamit merged 3 commits into
ctrliq:mainfrom
blaipr:feature/react-router-app-root
Jun 17, 2026
Merged

cigamit merged 3 commits into
ctrliq:mainfrom
blaipr:feature/react-router-app-root

Conversation

@blaipr

@blaipr blaipr commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor
SUMMARY

Converts the App.js root route tree to react-router v6 <Routes>. This is the last piece of the v5 to v6 migration (#400 through #427). App.js now dispatches each routeConfig screen as a v6 descendant at path="/<x>/*", and the outer login, / to /home, and ProtectedRoute tree is plain v6.

Once App.js is v6, every screen's own <Routes> becomes a descendant, which v6 matches relative to the parent. The merged route-tree PRs had written each list-entry screen with absolute child paths (path="/credentials", /credentials/add, /credentials/:id/*), and those only matched while App.js was still v5 and the screens were effectively top-level. As descendants they stop matching, so most pages went blank or not-found after rebasing onto current main. This PR switches those screens to relative paths so they resolve under the v6 root:

  • List-entry screens use add, :id/*, and <Route index>: Credentials, Jobs, Projects, Inventories, Hosts, Organizations, Users, Teams, CredentialTypes, WorkflowApprovals, NotificationTemplates, Applications, ExecutionEnvironments, AllSchedules, InstanceGroups, Instances, Settings, ManagementJobs.
  • Template and WorkflowJobTemplate detail <Routes> use relative :templateType/:id/... (Templates.js itself stays a v5-compat <Switch>, which already prefix-matches the full path).
  • Each screen's tests now mount the screen as a descendant under a real <Routes><Route path="/<x>/*" element={<Screen/>}/></Routes>. The old top-level mounts only resolved with absolute paths.
ISSUE TYPE
  • Bug, Docs Fix or other nominal change
COMPONENT NAME
  • UI
ADDITIONAL INFORMATION

I browser-smoke-tested this against the dev server (hash routing) after the change. Every top-level route and a representative set of detail tabs render, with no /api/v2/.../undefined/... calls:

  • Lists: home, jobs, schedules, activity_stream, workflow_approvals, labels, templates, credentials, projects, inventories, hosts, organizations, users, teams, credential_types, notification_templates, management_jobs, applications, execution_environments, instances, topology_view, settings. All OK.
  • Details: credentials/:id, jobs/:id/output, projects/:id, inventories/inventory/:id, hosts/:id, organizations/:id, instance_groups/:id, management_jobs/:id (notifications and schedules), settings/, and templates/{job_template,workflow_job_template}/:id (details/edit/survey/visualizer). All OK.
  • host_metrics and subscription_usage are license-gated out of routeConfig (SUBSCRIPTION_USAGE_MODEL), so they 404 by design. That's unchanged from main.

All 20 affected screen test suites pass (69 tests), and the changed screens lint clean.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates the UI’s root routing (awx/ui/src/App.js) from react-router v5’s <Switch>/<Route>/<Redirect> API to v6’s <Routes>/<Route>/<Navigate> API using react-router-dom-v5-compat, while keeping the existing HashRouter + CompatRouter bridge in place.

Changes:

  • Converted the root App.js route tree and AuthorizedRoutes from v5 Switch/Redirect to v6 Routes/Navigate.
  • Refactored ProtectedRoute into a v6 element guard that conditionally returns children or navigates to /login.
  • Updated tests in App.test.js to cover the authenticated-children render case.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
awx/ui/src/App.js Migrates root and authorized routing to v6-style Routes and refactors ProtectedRoute and redirect logic.
awx/ui/src/App.test.js Adds coverage for ProtectedRoute rendering children when authenticated.

Comment thread awx/ui/src/App.js Outdated
@blaipr

blaipr commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Fixed in 172701386c: redirectURL !== / || redirectURL !== /home was always true, so changed it to && so the post-login redirect only runs when the stored URL is neither default.

@blaipr

blaipr commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Smoke-tested this in a browser against a running instance (login + 14 top-level routes). The root conversion works: login and the post-login redirect resolve, and the App.js routeConfig dispatcher routes correctly to Dashboard, Jobs, Templates, Projects, Inventories, Credentials, Organizations, Users, Teams, Schedules, Settings, Management Jobs, Notification Templates and Instance Groups. No errors, no not-found, no changes needed here.

@blaipr

blaipr commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor Author

On the App.js redirect condition Copilot flagged: this is a false positive. The current line is if (redirectURL !== '/' && redirectURL !== '/home'), which is only true when redirectURL is neither / nor /home - it correctly skips navigation for those two. Copilot's "always true" reasoning applies to the || form; in fact this PR fixes the pre-existing || bug (which was always true) by switching it to &&. No change needed here.

The rest of the v6 conversion checks out: Routes (login / /→/home / *→ProtectedRoute), ProtectedRoute as an element wrapper, Navigate replacements, and /* on each screen route for nested matching. Tests pass.

@cigamit

cigamit commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Now that all the other page changes are in, and I rebase this one to main, most of those other pages fail to load completely. Things like dashboard and labels load, but the others are blank pages, no errors.

Also FYI, in main, the Templates > Schedules no longer loads, was gonna create an issue for it, but figured I could drop it here while you are working on this one.

blaipr added 3 commits June 16, 2026 23:49
Migrate the application root from the react-router v5
<Switch>/<Route>/<Redirect> API to v6 <Routes>/<Route>/<Navigate> via
react-router-dom-v5-compat. The HashRouter + CompatRouter bridge stays
in place (the package is not flipped to v6-proper yet, since a few
screens still use <Switch>).

- App root <Switch> -> <Routes>: /login, / -> Navigate /home, and a
  catch-all path="*" that renders the ProtectedRoute > ConfigProvider >
  app container. The legacy /*/ trailing-slash redirect is dropped (v6
  matches trailing slashes leniently).
- ProtectedRoute no longer renders a <Route>; it is a v6 element guard
  that returns its children (when authenticated) or <Navigate to="/login">
  (the loginRedirectOverride locationReplace path is unchanged).
- AuthorizedRoutes: <Switch> -> <Routes>; each routeConfig screen mounts
  at path/* (so the screen's own nested <Routes> resolve); metrics and
  the not-found fallback likewise; the unauthorized branch redirects to
  /subscription_management via <Navigate>. The unused match prop passed
  to screens is dropped (no screen reads it).
- App uses useNavigate instead of useHistory.

Screens that are still on v5 <Switch> keep working under the v6 root
because their <Switch> matches the absolute location; already-migrated
screens use absolute v6 paths. Tests: App.test.js (incl. a new
authenticated-children case) and index.test.js pass; lint clean.
`redirectURL !== '/' || redirectURL !== '/home'` is always true, so the
post-login redirect ran even for '/' and '/home'. Use && so it only
navigates when the stored URL is neither of those defaults.
…t routes)

This PR converts App.js to v6 <Routes>, mounting each routeConfig screen as a
descendant at path="/<x>/*". The merged route-tree PRs (ctrliq#407-ctrliq#427) wrote each
list-entry screen's own <Routes> with ABSOLUTE child paths, which only matched
while App.js was still v5 (the screens were effectively top-level). As v6
descendants those absolute paths no longer match the relative remainder, so
most pages rendered blank / not-found after rebasing onto current main
(reported by cigamit).

Convert the list-entry screens to RELATIVE paths (add, :id/*, <Route index>):
Credentials, Jobs, Projects, Inventories, Hosts, Organizations, Users, Teams,
CredentialTypes, WorkflowApprovals, NotificationTemplates, Applications,
ExecutionEnvironments, AllSchedules, InstanceGroups, Instances, Settings,
ManagementJobs (the last via a basePath template-literal path). Also convert
the Template / WorkflowJobTemplate detail <Routes> from absolute
/templates/:templateType/:id/... to relative so their tabs resolve under the
v6 root.

Update each screen's tests to mount the screen as a descendant under a real
<Routes><Route path="/<x>/*" element={<Screen/>}/></Routes>, matching
production (the old top-level mounts only resolved with absolute paths).

Browser-smoke-tested every top-level route plus representative detail tabs
against the dev server: all render with no /api/.../undefined/ calls.
host_metrics and subscription_usage are license-gated out of routeConfig and
are unchanged.
@blaipr
blaipr force-pushed the feature/react-router-app-root branch from 1727013 to 398ba9d Compare June 16, 2026 23:09
@blaipr

blaipr commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor Author

@cigamit good catch, reproduced it.

The blank pages come from making App.js v6: each screen now mounts as a v6 descendant, but the merged route-tree PRs left the list-entry screens using absolute child paths (/credentials, /credentials/add, etc). Those worked while App.js was still v5 (the screens were effectively top-level), but as v6 descendants they no longer match, so the content comes up blank. Dashboard and Labels survived because they have no nested <Routes>, and Templates survived because it's still a <Switch>.

I have just pushed a fix here: the 18 entry screens plus the Template/WorkflowJobTemplate detail routes now use relative paths, and their tests remount the screen as a descendant. App.js itself is unchanged from what you reviewed. I browser-checked every top-level route plus the detail tabs, and everything loads with no undefined API calls. 20 suites green.

And the Templates > Schedules one is solved. All load for me now. Shout if you still see it on your end.

@cigamit
cigamit merged commit 5d0724c into ctrliq:main Jun 17, 2026
cigamit pushed a commit that referenced this pull request Jun 18, 2026
…#484)

* Convert the Templates route tree to react-router v6 (last <Switch>)

App.js is now v6 (#425) and mounts Templates as a descendant at /templates/*, so Templates.js becomes v6 <Routes> with relative children (job_template/add, workflow_job_template/add, job_template/:id/*, workflow_job_template/:id/*, index list). Template.js and WorkflowJobTemplate.js move their internal <Routes> to relative paths and read useParams from react-router-dom-v5-compat (v5 useParams returns {} as a v6 descendant). Tests remount these under the real v6 parent route. This removes the last <Switch> from main, unblocking the eventual react-router-dom-v5-compat bridge removal.

* Convert the 3 Template entry/detail test suites to RTL (v6-mounted)

These three files were the only overlap between this PR and the screens/Template RTL conversion (#483). Make this PR own them outright: convert them from enzyme to React Testing Library, mounted under the real v6 parent route so useParams resolves :id. #483 drops these three so the two PRs become independently mergeable in either order, with all three landing as RTL.
@cigamit cigamit self-assigned this Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants