fix: make the workflow job selector show and switch the right job - #760
fix: make the workflow job selector show and switch the right job#760blaipr wants to merge 2 commits into
Conversation
The selector in the job tab bar always read "Workflow Job 1/X", whatever task you were on, and picking another task did nothing. Closes ctrliq#742. Three separate defects, only the first of which was in the selector's own counter: - The position was the literal 1, and the list it counted excluded the job on screen, so a four task workflow read 1/3 on every one of its tasks. Count every node that ran a job, the current one included, and report where in that list the job on screen sits. - Picking a task did nothing because the selector is registered in Job.js as a tab with no link, so that it sits in the tab bar. The click bubbles to the PatternFly tab, and RoutedTabs called navigate(undefined) for it, landing back on the current url and undoing the navigation the selector had just performed. RoutedTabs now leaves link-less tabs alone. - RoutedTabs passed href={!tab.hasstyle && `#${tab.link}`}, which is the boolean false for exactly that tab. React rejects false as an href. Two more found while testing the above: - With a status filter applied, the toggle rendered a Label with a close button inside the toggle's own button. Nested buttons are invalid, and that close button was unclickable for the same bubbling reason. The filter is cleared by picking the same status again. - The menu seeded useState from the first render, so after moving between jobs it still offered the list belonging to the page you came from. The list is derived now. The old component test mocked out the component under test and asserted against the mock, which is why none of this was caught. It is replaced by twelve tests against the real component, plus two on RoutedTabs covering tabs that host a control.
129812b to
fd7f92d
Compare
The selector's label changed, so its message id changed with it, and a
production build renders an id it has no catalog entry for. The tab read
"-t1kzb" rather than "Workflow Job 2/4" until the catalogs were extracted
again. The jest suite does not see this, and neither does the development
server, which compiles catalogs on the way up; only a built UI shows it.
The two new messages are named rather than positional,
"Workflow Job {currentPosition}/{total}" instead of leaving translators a
bare {0}.
Extraction also picks up three messages that were already in the source
and missing from the catalogs, and refreshes the source line references
throughout, which is what makes the diff large. The Spanish, French and
other translations of the old "Workflow Job 1/{0}" are dropped, as they
have to be: that string no longer exists.
There was a problem hiding this comment.
Pull request overview
This PR fixes the “workflow job selector” control shown in the Job output tab bar so it (a) reports the correct position/total for the workflow job nodes, (b) correctly navigates when selecting a different node, and (c) stops generating console errors caused by invalid href values / link-less tabs triggering navigate(undefined). It does so by correcting the selector’s node counting and selection model, and by hardening RoutedTabs to treat tabs with no link as non-navigational (so embedded controls don’t get overridden by tab selection).
Changes:
- Fix
WorkflowOutputNavigationto count all navigable workflow job nodes (including the current one), compute the correct on-screen position, and navigate using a stable node identifier/value rather than label text. - Update
RoutedTabsto ignore selection of tabs that have nolink, and avoid passing invalidhrefvalues. - Replace the previous mocked selector test with a comprehensive set of real component tests; add coverage for the new
RoutedTabsbehavior.
Reviewed changes
Copilot reviewed 4 out of 22 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| awx/ui/src/locales/en/messages.js | Updates extracted/en locale messages to include the new/updated selector strings. |
| awx/ui/src/components/WorkflowOutputNavigation/WorkflowOutputNavigation.js | Corrects workflow node counting/positioning, selection handling, filtering behavior, and URL construction. |
| awx/ui/src/components/WorkflowOutputNavigation/WorkflowOutputNavigation.test.js | Replaces mock-based tests with real behavioral tests covering counting, navigation, filtering, and selection state. |
| awx/ui/src/components/RoutedTabs/RoutedTabs.js | Prevents navigate(undefined) by treating link-less tabs as non-navigational; fixes href to never be false. |
| awx/ui/src/components/RoutedTabs/RoutedTabs.test.js | Adds regression tests ensuring link-less “control tabs” don’t navigate while normal tabs still do. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

SUMMARY
Fixes the workflow job selector in the job tab bar. Closes #742.
The report is two symptoms, and they turned out to have three separate causes, only one of them in the selector's own code.
The counter was the literal
1.WorkflowOutputNavigationrenderedt`Workflow Job 1/${relevantResults.length}`, andrelevantResultsfiltered out the job you were looking at, so the total was short by one too. A four task workflow read1/3on every one of its tasks. It now counts every node that ran a job, the current one included, and reports where in that list the job on screen sits.Picking a task did nothing, and that is not a bug in the selector. The selector is registered in
Job.jsas a tab withlink: undefined, so that it can sit in the tab bar:A click inside it bubbles up to the PatternFly tab,
RoutedTabs.handleTabSelectmatched tab id 2, and rannavigate(undefined). That resolves to the current url, so it landed you back where you were and undid the navigation the selector had just performed.RoutedTabsnow leaves a tab with no link alone.href={!tab.hasstyle &&#${tab.link}}isfalsefor that tab, and React rejectsfalseas an href value. It was loggingReceived 'false' for a non-boolean attribute 'href'on every job page.Two more came out of writing the tests:
LabelwithonClose, which is a close<button>inside the toggle's own<button>. Invalid HTML, and that close button was unclickable for the same bubbling reason. The filter is cleared by picking the same status again.useStatefrom the first render, so after moving between jobs it still offered the list belonging to the page you came from.ad_hoc_commandwas also missing from the type to url-segment map, which would have built/jobs/undefined/<id>/outputfor an ad hoc command node.ISSUE TYPE
COMPONENT NAME
ASCENDER VERSION
ADDITIONAL INFORMATION
On the tests. The existing
WorkflowOutputNavigation.test.jsmocked out the component under test and asserted against the mock, so it exercised none of this code and passed throughout. It is replaced by twelve tests against the real component, plus two onRoutedTabsfor tabs that host a control.Worth knowing for review: jsdom passes the navigation case that a real browser fails. The bug lives in event bubbling through nested buttons, which jsdom does not model faithfully, so the jest test for "picking a job navigates" went green against the broken code. I only found the real cause by driving a headless browser against a running instance. That is the argument for end-to-end coverage, raised in #761 and built in #762, whose regression specs are cover for exactly this bug: they fail five ways against this branch's parent and pass once it lands.
Verified against a running instance, workflow job 951, four job nodes:
RoutedTabsis used by 46 screens, so tab navigation was checked in the browser too, and none of it changes:Full UI suite after the change:
Not fixed here, and worth a follow-up. Rendering a control inside a tab's
<button>is invalid HTML whatever else is done, and it is the reason these clicks misbehaved in the first place. OnlyJob.jsdoes it, onehasstyleusage in the whole tree, so moving that control out of the tab list would remove the whole class rather than guarding each symptom. I kept this change to the reported bug.