Skip to content

fix: nodes stat drill-down crash and error page UX (#5902)#5909

Merged
clubanderson merged 1 commit intomainfrom
fix/5902-nodes-drill-error
Apr 10, 2026
Merged

fix: nodes stat drill-down crash and error page UX (#5902)#5909
clubanderson merged 1 commit intomainfrom
fix/5902-nodes-drill-error

Conversation

@clubanderson
Copy link
Copy Markdown
Collaborator

Summary

Fixes #5902. Clicking the nodes stat block on the My Clusters dashboard
navigated to /compute and immediately hit the AppErrorBoundary with
can't access property "replace", cardType is undefined, and the recovery
UI itself had three UX bugs.

Root cause

ensureCardInDashboard() in Compute.tsx (and Security.tsx) injected cards
into saved layouts using the legacy cardType field, but DashboardCard uses
the snake_case card_type field. When the renderer called
formatCardTitle(card.card_type) the value was undefined and crashed the
whole dashboard.

Fixes

  • Compute.tsx / Security.tsx: pass card_type (snake_case) to
    ensureCardInDashboard so injected cards match the DashboardCard shape.
  • migrateStorageKey.ts: normalize stored layouts on read. Any entries
    written by older builds with the legacy cardType field are repaired to
    card_type automatically so users who already hit the crash recover
    without clearing localStorage. The helper still accepts cardType on the
    injected-card argument for back-compat.
  • formatCardTitle.ts: defensive guard against null/undefined input
    so a single bad card can never crash the whole dashboard again.
  • AppErrorBoundary.tsx:
    • Try again now bumps a resetKey used as a React key on the
      children subtree, forcing a full remount instead of re-rendering with
      the same broken props. Previously the button appeared unresponsive
      because the same error re-threw immediately.
    • Added a distinct Go to dashboard button so "Try again" and
      "Reload page" no longer look like synonyms.
    • Error text uses break-words + whitespace-pre-wrap instead of
      break-all, so long tokens like undefined stop wrapping mid-word
      (the reported "d" on its own line).
  • PageErrorBoundary.tsx: same break-words fix for consistency.
  • Tests: new regression tests for the undefined guard in
    formatCardTitle and for legacy-cardType normalization in
    ensureCardInDashboard.

Test plan

  • npm run build passes
  • npx vitest run src/lib/__tests__/formatCardTitle.test.ts src/lib/dashboards/__tests__/migrateStorageKey.test.ts - 33/33 pass
  • Manually verify clicking the nodes stat block on My Clusters navigates to /compute without error
  • Manually verify stale layouts previously written with cardType load cleanly after the fix
  • Manually verify the AppErrorBoundary error text no longer breaks mid-word and the Try again / Go to dashboard / Reload page buttons all work

Clicking the "nodes" stat block on the My Clusters dashboard navigated
to /compute and immediately hit the AppErrorBoundary with
"can't access property 'replace', cardType is undefined".

Root cause: ensureCardInDashboard() in Compute.tsx (and Security.tsx)
injected cards into saved layouts using the legacy `cardType` field,
but DashboardCard uses the snake_case `card_type` field. When the
renderer called formatCardTitle(card.card_type) the value was undefined
and crashed the whole dashboard.

Fixes:
- Compute.tsx / Security.tsx: pass card_type (snake_case) to
  ensureCardInDashboard so injected cards match the DashboardCard shape.
- migrateStorageKey.ts: normalize stored layouts on read — any entries
  written by older builds with the legacy cardType field are repaired
  to card_type automatically, so users who already hit the crash
  recover without clearing localStorage. The helper still accepts
  cardType on the injected-card argument for back-compat.
- formatCardTitle.ts: defensive guard against null/undefined input so
  a single bad card can never crash the whole dashboard again.
- AppErrorBoundary.tsx:
  - "Try again" now bumps a resetKey that the children subtree uses as
    a React key, forcing a full remount instead of re-rendering with
    the same broken props. Previously the button appeared unresponsive
    because the same error re-threw immediately.
  - Added a distinct "Go to dashboard" button so "Try again" and
    "Reload page" no longer look like synonyms.
  - Error text uses break-words + whitespace-pre-wrap instead of
    break-all, so long tokens like "undefined" stop wrapping mid-word
    (the reported "d" on its own line).
- PageErrorBoundary.tsx: same break-words fix for consistency.
- Tests: new regression tests for the undefined guard in
  formatCardTitle and for the legacy cardType normalization in
  ensureCardInDashboard.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
@clubanderson clubanderson added the ai-generated Pull request generated by AI label Apr 10, 2026
Copilot AI review requested due to automatic review settings April 10, 2026 04:06
@kubestellar-prow kubestellar-prow bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Apr 10, 2026
@kubestellar-prow
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign clubanderson for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@github-actions
Copy link
Copy Markdown
Contributor

👋 Hey @clubanderson — thanks for opening this PR!

🤖 This project is developed exclusively using AI coding assistants.

Please do not attempt to code anything for this project manually.
All contributions should be authored using an AI coding tool such as:

This ensures consistency in code style, architecture patterns, test coverage,
and commit quality across the entire codebase.


This is an automated message.

@kubestellar-prow kubestellar-prow bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 10, 2026
@netlify
Copy link
Copy Markdown

netlify bot commented Apr 10, 2026

Deploy Preview for kubestellarconsole ready!

Name Link
🔨 Latest commit a5b7f69
🔍 Latest deploy log https://app.netlify.com/projects/kubestellarconsole/deploys/69d8772c201e360008e37858
😎 Deploy Preview https://deploy-preview-5909.console-deploy-preview.kubestellar.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@clubanderson clubanderson merged commit 9a1bcdb into main Apr 10, 2026
21 of 23 checks passed
@kubestellar-prow kubestellar-prow bot deleted the fix/5902-nodes-drill-error branch April 10, 2026 04:08
@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

Check out what's new:

Stay connected: Slack #kubestellar-dev | Multi-Cluster Survey

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a runtime crash when navigating to the Compute dashboard from the “nodes” stat block due to legacy dashboard layout entries using cardType instead of the canonical card_type, and improves the recovery UX of the app/page error boundaries.

Changes:

  • Hardened formatCardTitle() against null/undefined card types so a single corrupt card can’t crash the dashboard.
  • Updated ensureCardInDashboard() to normalize stored layouts (cardTypecard_type) and adjusted Compute/Security injected-card definitions to use card_type.
  • Improved error boundary UX: “Try again” now forces a subtree remount, added “Go to dashboard”, and fixed long-token wrapping.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
web/src/lib/formatCardTitle.ts Adds a safe fallback for missing/invalid card types to prevent crashes.
web/src/lib/dashboards/migrateStorageKey.ts Normalizes legacy stored layouts and injected cards to the canonical card_type field.
web/src/lib/dashboards/tests/migrateStorageKey.test.ts Adds regression coverage for legacy cardType normalization and back-compat injected cards.
web/src/lib/tests/formatCardTitle.test.ts Adds regression tests for null/undefined guard behavior.
web/src/components/security/Security.tsx Updates injected card shape to use card_type.
web/src/components/compute/Compute.tsx Updates injected card shape to use card_type.
web/src/components/PageErrorBoundary.tsx Fixes error-message wrapping to avoid mid-word breaks.
web/src/components/AppErrorBoundary.tsx Improves recovery UX (remount on retry, adds “Go to dashboard”, fixes wrapping).

@github-actions
Copy link
Copy Markdown
Contributor

❌ Post-Merge Verification: failed

Commit: 9a1bcdbe7c22dcaa61852443991cac11fc73e48e
Specs run: smoke.spec.ts
Report: https://github.com/kubestellar/console/actions/runs/24225873500

@github-actions
Copy link
Copy Markdown
Contributor

Post-merge build verification passed

Both Go and frontend builds compiled successfully against merge commit 9a1bcdbe7c22dcaa61852443991cac11fc73e48e.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-generated Pull request generated by AI dco-signoff: yes Indicates the PR's author has signed the DCO. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clicking on "nodes" stat block in stats overview on the My Clusters dashboard gives an error

2 participants