Skip to content

fix(quickstart): make Quick start help menu item clickable - #4021

Open
ciiay wants to merge 1 commit into
redhat-developer:mainfrom
ciiay:rhdhbugs-3489-fix-quickstart-in-help-dropdown
Open

fix(quickstart): make Quick start help menu item clickable#4021
ciiay wants to merge 1 commit into
redhat-developer:mainfrom
ciiay:rhdhbugs-3489-fix-quickstart-in-help-dropdown

Conversation

@ciiay

@ciiay ciiay commented Jul 28, 2026

Copy link
Copy Markdown
Member

Description

The Quick start item in the global-header help dropdown was visible but not clickable, so the drawer never opened. This change renders a real MUI MenuItem via forwardRef (instead of GlobalHeaderMenuItem without a to prop, which used component={Fragment} in global-header 1.21.0 and dropped click handlers), bumps the global-header dependency, and adds unit coverage.

Root cause

GlobalHeaderMenuItem without a to prop rendered MenuItem component={Fragment} in @red-hat-developer-hub/backstage-plugin-global-header@1.21.0, which discarded onClick and role="menuitem".

Fixed

  • RHDHBUGS-3489 — Quick start menu item in global-header help dropdown is not clickable

UI before changes

Before fix

UI after changes

After fix

Test Plan

  • Start the quickstart NFS app (yarn start in workspaces/quickstart)
  • Open the Help (?) dropdown in the global header
  • Verify "Quick start" appears as a menu item
  • Click "Quick start" and verify the quickstart drawer opens on the right
  • Verify no console warning about ref on React.Fragment
  • Verify the sidebar Quick start control still toggles the drawer

Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

Note

This bug fix was identified and implemented using the bug-fix and raise-pr agent skills. Please verify the fix thoroughly before merging.

Made with Cursor

Fixes: https://redhat.atlassian.net/browse/RHDHBUGS-3489
Signed-off-by: Yi Cai <yicai@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@rhdh-gh-app

rhdh-gh-app Bot commented Jul 28, 2026

Copy link
Copy Markdown

Changed Packages

Package Name Package Path Changeset Bump Current Version
app workspaces/quickstart/packages/app none v0.0.0
@red-hat-developer-hub/backstage-plugin-quickstart workspaces/quickstart/plugins/quickstart patch v1.12.2

@rhdh-qodo-merge

Copy link
Copy Markdown

PR Summary by Qodo

Fix Quick start help menu item clickability in global-header dropdown

🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Render Quick start as a real MUI MenuItem with forwardRef to preserve click/role behavior.
• Replace GlobalHeaderMenuItem usage to avoid Fragment rendering that drops handlers.
• Bump global-header dependency and add unit tests covering click + ref behavior.
Diagram

graph TD
  U["User"] --> M["Help dropdown"] --> Q["QuickstartHelpMenuItem"] --> MI["MUI MenuItem (forwardRef)"] --> D["useAppDrawer.toggleDrawer"] --> DR["Quickstart drawer"]
  Q --> C["handleClose (menu)"ذة]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Upstream-only fix (rely on GlobalHeaderMenuItem)
  • ➕ Keeps quickstart plugin code simpler and aligned with global-header API
  • ➕ Centralizes the fix so other consumers benefit automatically
  • ➖ Requires global-header to definitively fix the Fragment/no-to rendering behavior
  • ➖ Still risks regressions if alpha APIs change or ref handling remains inconsistent
2. Use GlobalHeaderMenuItem with a synthetic `to` (e.g., '#') and preventDefault
  • ➕ Minimal code changes; may preserve MenuItem semantics through link rendering
  • ➖ Hacky and can introduce accessibility/URL side effects
  • ➖ Still couples behavior to global-header internal rendering details

Recommendation: Current approach is appropriate: render a real MUI MenuItem and forwardRef explicitly to satisfy MUI menu focus management and preserve onClick/role semantics, while using MenuItemLink for consistent visuals. Keep the dependency bump to pick up global-header fixes, but avoid relying on its conditional rendering behavior for non-navigation items.

Files changed (6) +183 / -68

Bug fix (1) +41 / -19
QuickstartHelpMenuItem.tsxRender Quick start help entry as a forwardRef MUI MenuItem +41/-19

Render Quick start help entry as a forwardRef MUI MenuItem

• Replaces GlobalHeaderMenuItem (alpha) with a MUI MenuItem wrapper using forwardRef and MenuItemLink content, ensuring click handlers and menuitem role are preserved. Keeps behavior to toggle the quickstart drawer and optionally close the menu.

workspaces/quickstart/plugins/quickstart/src/QuickstartHelpMenuItem.tsx

Tests (1) +88 / -0
QuickstartHelpMenuItem.test.tsxAdd unit tests for help menu item role, click, and ref forwarding +88/-0

Add unit tests for help menu item role, click, and ref forwarding

• Adds tests verifying the Quick start entry renders as a proper menuitem, toggles the drawer and closes the menu on click, and forwards a ref to the underlying MenuItem element.

workspaces/quickstart/plugins/quickstart/src/QuickstartHelpMenuItem.test.tsx

Documentation (1) +5 / -0
clickable-menu-refix.mdAdd changeset for Quick start help menu click fix +5/-0

Add changeset for Quick start help menu click fix

• Introduces a patch changeset for the quickstart plugin describing the help dropdown click regression fix.

workspaces/quickstart/.changeset/clickable-menu-refix.md

Other (3) +49 / -49
package.jsonBump global-header dependency in quickstart app workspace +1/-1

Bump global-header dependency in quickstart app workspace

• Updates @red-hat-developer-hub/backstage-plugin-global-header from ^1.21.0 to ^1.21.2 for the quickstart app package.

workspaces/quickstart/packages/app/package.json

package.jsonBump global-header dependency in quickstart plugin workspace +1/-1

Bump global-header dependency in quickstart plugin workspace

• Updates @red-hat-developer-hub/backstage-plugin-global-header from ^1.21.0 to ^1.21.2 for the quickstart plugin package.

workspaces/quickstart/plugins/quickstart/package.json

yarn.lockRefresh lockfile for global-header upgrade and transitive bumps +47/-47

Refresh lockfile for global-header upgrade and transitive bumps

• Updates yarn.lock to reflect the global-header version change (resolving to 1.22.1) and related transitive dependency updates (Backstage packages, scalprum).

workspaces/quickstart/yarn.lock

@sonarqubecloud

Copy link
Copy Markdown

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.81%. Comparing base (eb13368) to head (e9c3e9e).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4021   +/-   ##
=======================================
  Coverage   57.80%   57.81%           
=======================================
  Files        2393     2393           
  Lines       95919    95921    +2     
  Branches    26776    26776           
=======================================
+ Hits        55448    55455    +7     
+ Misses      38935    38930    -5     
  Partials     1536     1536           
Flag Coverage Δ *Carryforward flag
adoption-insights 84.54% <ø> (ø) Carriedforward from eb13368
ai-integrations 69.06% <ø> (ø) Carriedforward from eb13368
app-defaults 69.79% <ø> (ø) Carriedforward from eb13368
augment 46.67% <ø> (ø) Carriedforward from eb13368
boost 75.92% <ø> (ø) Carriedforward from eb13368
bulk-import 72.55% <ø> (ø) Carriedforward from eb13368
cost-management 13.55% <ø> (ø) Carriedforward from eb13368
dcm 60.72% <ø> (ø) Carriedforward from eb13368
extensions 56.48% <ø> (ø) Carriedforward from eb13368
global-floating-action-button 71.18% <ø> (ø) Carriedforward from eb13368
global-header 62.17% <ø> (ø) Carriedforward from eb13368
homepage 47.54% <ø> (ø) Carriedforward from eb13368
install-dynamic-plugins 56.77% <ø> (ø) Carriedforward from eb13368
intelligent-assistant 74.06% <ø> (ø) Carriedforward from eb13368
konflux 91.98% <ø> (ø) Carriedforward from eb13368
lightspeed 69.02% <ø> (ø) Carriedforward from eb13368
mcp-integrations 83.40% <ø> (ø) Carriedforward from eb13368
orchestrator 66.79% <ø> (ø) Carriedforward from eb13368
quickstart 66.15% <100.00%> (+1.10%) ⬆️
sandbox 79.56% <ø> (ø) Carriedforward from eb13368
scorecard 84.94% <ø> (ø) Carriedforward from eb13368
theme 83.89% <ø> (ø) Carriedforward from eb13368
translations 5.12% <ø> (ø) Carriedforward from eb13368
x2a 79.31% <ø> (ø) Carriedforward from eb13368

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eb13368...e9c3e9e. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@its-mitesh-kumar

Copy link
Copy Markdown
Member

/fs-review

@rhdh-qodo-merge

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (2) 📜 Skill insights (0)

Context used
⚠️ Tickets: not configured — ticket URL found in PR but could not be fetched — check ticket provider credentials
✅ Compliance rules (platform): 11 rules
✅ Cross-repo context
  Explored: repo: redhat-developer/rhdh (sha: 6bcb0141)
  Not relevant to this PR: redhat-developer/rhdh-chart
  Not relevant to this PR: redhat-developer/rhdh-operator
  Not relevant to this PR: redhat-developer/rhdh-local

Grey Divider


Remediation recommended

1. Global-header version skew 🔗 Cross-repo conflict ☼ Reliability
Description
The quickstart plugin now depends on @red-hat-developer-hub/backstage-plugin-global-header as
^1.21.2, and in this repo that range already resolves to 1.22.1; meanwhile RHDH’s dynamic-plugin
wrapper pins global-header to 1.21.5. When RHDH upgrades quickstart, this can lead to
global-header minor-version skew unless RHDH constrains/dedupes the version (risking dynamic-plugin
runtime/load issues if two copies or incompatible transitive deps are pulled).
Code

workspaces/quickstart/plugins/quickstart/package.json[R48-50]

    "@red-hat-developer-hub/backstage-plugin-app-react": "^0.1.0",
-    "@red-hat-developer-hub/backstage-plugin-global-header": "^1.21.0",
+    "@red-hat-developer-hub/backstage-plugin-global-header": "^1.21.2",
    "@red-hat-developer-hub/backstage-plugin-theme": "^0.14.11",
Relevance

⭐⭐⭐ High

Team commonly accepts dependency range alignment/dedupe to prevent duplicate versions and runtime
skew.

PR-#3929
PR-#2547

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR quickstart declares ^1.21.2 and the PR lockfile resolves that range to global-header 1.22.1,
while RHDH pins its global-header wrapper dependency to 1.21.5, demonstrating a concrete
cross-repo version skew risk upon integration.

workspaces/quickstart/plugins/quickstart/package.json[36-52]
workspaces/quickstart/yarn.lock[9882-9888]
External repo: redhat-developer/rhdh, dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-global-header/package.json [30-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Quickstart now permits a newer `@red-hat-developer-hub/backstage-plugin-global-header` minor than what RHDH pins in its wrapper (RHDH: `1.21.5`, quickstart range: `^1.21.2`, which can resolve to `1.22.x`). This creates a cross-repo integration risk when RHDH upgrades quickstart: dependency resolution may drift and produce unexpected global-header versions in the dynamic-plugin set.

## Issue Context
- In this PR repo, the lockfile already resolves `^1.21.2` to `1.22.1`, demonstrating that the caret range will float.
- In RHDH, the global-header wrapper is pinned to `1.21.5`, so RHDH upgrades should either (a) deliberately align to `1.22.1` (or higher) in a coordinated change, or (b) constrain quickstart/global-header resolution to keep a single compatible version.

## Fix Focus Areas
- workspaces/quickstart/plugins/quickstart/package.json[48-50]
- workspaces/quickstart/yarn.lock[9882-9888]
- dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-global-header/package.json[30-33]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. Wrapper version not updated 🔗 Cross-repo conflict ⚙ Maintainability
Description
This PR will publish a patch release of @red-hat-developer-hub/backstage-plugin-quickstart, but
RHDH’s dynamic-plugin wrapper is pinned to quickstart 1.9.6. RHDH will not receive this fix until
a follow-up change bumps the wrapper dependency (and lockfile) in redhat-developer/rhdh.
Code

workspaces/quickstart/.changeset/clickable-menu-refix.md[R1-5]

+---
+'@red-hat-developer-hub/backstage-plugin-quickstart': patch
+---
+
+Fix Quick start help menu item not responding to clicks in the global-header dropdown
Relevance

⭐ Low

Cross-repo wrapper bump/note requests have been rejected as out-of-scope for this repo’s PRs.

PR-#3896

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR adds a changeset indicating a new patch release of the quickstart package, while RHDH’s
dynamic-plugin wrapper remains pinned to 1.9.6, so RHDH will not consume the fix until it updates
that wrapper dependency.

workspaces/quickstart/.changeset/clickable-menu-refix.md[1-5]
External repo: redhat-developer/rhdh, dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-quickstart/package.json [45-48]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The quickstart fix will ship in a new patch release, but RHDH pins its dynamic-plugin quickstart wrapper to `@red-hat-developer-hub/backstage-plugin-quickstart@1.9.6`. Without updating that wrapper, RHDH deployments will continue to use the old quickstart plugin version.

## Issue Context
This is not a defect in the PR itself, but it is a required downstream coordination step for the fix to land in RHDH.

## Fix Focus Areas
- workspaces/quickstart/.changeset/clickable-menu-refix.md[1-5]
- dynamic-plugins/wrappers/red-hat-developer-hub-backstage-plugin-quickstart/package.json[45-48]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 28, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:25 AM UTC · Completed 3:42 AM UTC
Commit: e9c3e9e · View workflow run →

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

Low

  • [architectural-coherence] workspaces/quickstart/plugins/quickstart/src/QuickstartHelpMenuItem.tsx — The PR bypasses the existing GlobalHeaderMenuItem abstraction and manually composes MenuItem + MenuItemLink. This is justified because GlobalHeaderMenuItem does not support forwardRef (needed for MUI Menu focus management), and the quickstart component is registered as type: 'component' in the blueprint system requiring its own MenuItem wrapping. Long-term, adding forwardRef support to GlobalHeaderMenuItem would let consumers use the abstraction.

  • [click-event-swallowing] workspaces/quickstart/plugins/quickstart/src/QuickstartHelpMenuItem.tsx:60MenuItemLink from the main entry point is a createComponentExtension lazy-loaded component. In practice, the global-header plugin chunk is already loaded before any dropdown can be opened (the header renders on every page), so the lazy-load race is not a real concern. The outer MenuItem's onClick is independent of the inner component's load state.

  • [mock-reset-idiom] workspaces/quickstart/plugins/quickstart/src/QuickstartHelpMenuItem.test.tsx:33 — Uses mockToggleDrawer.mockClear() instead of jest.clearAllMocks(), which is the predominant idiom in sibling test files (7 of 8 use clearAllMocks).
    Remediation: Replace mockToggleDrawer.mockClear() with jest.clearAllMocks() in the beforeEach block.

sx={{ py: 0.5, color: 'inherit', textDecoration: 'none' }}
>
<MenuItemLink to="" title="Quick start" icon="waving_hand" />
</MenuItem>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] click-event-swallowing

MenuItemLink from the main entry point is a createComponentExtension lazy-loaded component. In practice, the global-header plugin chunk is already loaded before any dropdown can be opened (the header renders on every page), so the lazy-load race is not a real concern. The outer MenuItems onClick is independent of the inner components load state.

openDrawer: jest.fn(),
closeDrawer: jest.fn(),
}),
}));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] mock-reset-idiom

Uses mockToggleDrawer.mockClear() instead of jest.clearAllMocks(), which is the predominant idiom in sibling test files (7 of 8 use clearAllMocks).

Suggested fix: Replace mockToggleDrawer.mockClear() with jest.clearAllMocks() in the beforeEach block.

@fullsend-ai-review fullsend-ai-review Bot added the ready-for-merge All reviewers approved — ready to merge label Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix ready-for-merge All reviewers approved — ready to merge Tests workspace/quickstart

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants