Skip to content

fix: tolerate partial dashboard payloads#365

Open
NgoQuocViet2001 wants to merge 1 commit into
rohitg00:mainfrom
NgoQuocViet2001:fix/347-dashboard-shape
Open

fix: tolerate partial dashboard payloads#365
NgoQuocViet2001 wants to merge 1 commit into
rohitg00:mainfrom
NgoQuocViet2001:fix/347-dashboard-shape

Conversation

@NgoQuocViet2001

@NgoQuocViet2001 NgoQuocViet2001 commented May 14, 2026

Copy link
Copy Markdown

Summary

  • Normalize dashboard API collections before rendering so malformed or missing arrays fall back to empty lists.
  • Avoid crashing Recent Sessions when a session is missing both project and id; render unknown instead.
  • Add a viewer regression test for partial dashboard payloads.

Fixes #347.
Refs #340.

Why

Windows users reported the Dashboard tab failing to load with Cannot read properties of undefined (reading 'slice') after v0.9.12. The viewer assumed several dashboard payload fields were always arrays and that every session had an id, so one partial record could stop the whole dashboard from rendering.

Tests

  • npx vitest run test/viewer-dashboard.test.ts test/viewer-security.test.ts
  • npm run build with npm_config_script_shell="C:\\Program Files\\Git\\bin\\bash.exe" on Windows because the package build script uses POSIX shell commands
  • npm test was also attempted locally; the new viewer test passed, but the full suite still has unrelated local Windows failures in existing path/Python-dependent tests (compress-file, obsidian-export, integration-plaintext-http).

Summary by CodeRabbit

  • Bug Fixes
    • Improved viewer dashboard resilience to missing or malformed API data, ensuring sessions, first-run/recent sections, session labels, procedure steps, semantic/procedural/relations panels, alerts, notes, and token-savings estimates render reliably with inconsistent payloads.
  • Tests
    • Added a dashboard rendering test that executes the embedded viewer script in a sandbox with intentionally incomplete data, validating that rendering succeeds and key sections populate (including recovered unknown sessions and procedures).

@vercel

vercel Bot commented May 14, 2026

Copy link
Copy Markdown

@NgoQuocViet2001 is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3c965973-a6dd-424e-aaa4-64420b94445c

📥 Commits

Reviewing files that changed from the base of the PR and between d90246d and 911873e.

📒 Files selected for processing (2)
  • src/viewer/index.html
  • test/viewer-dashboard.test.ts
💤 Files with no reviewable changes (2)
  • test/viewer-dashboard.test.ts
  • src/viewer/index.html

📝 Walkthrough

Walkthrough

This PR hardens the viewer dashboard against null/undefined or unexpected API response shapes by adding normalization helpers, normalizing dashboard state fields during load, updating rendering to use filtered normalized arrays, and adding a sandboxed Vitest that verifies rendering with malformed data.

Changes

Dashboard rendering resilience

Layer / File(s) Summary
Normalization utilities and dashboard state shape
src/viewer/index.html
Extends dashboard state with semantic, procedural, and relations collections and introduces asArray(), firstArray(), and asString() helpers to normalize null/undefined/non-array values into consistent shapes.
Safe data loading with normalized helpers
src/viewer/index.html
loadDashboard() uses normalization helpers to safely populate sessions, memories, recentAudit, semantic, procedural, relations, lessons, and crystals into consistent array/string forms with first-array fallbacks.
Resilient dashboard rendering with normalized data
src/viewer/index.html
renderDashboard() derives all metrics, stat cards, token-savings, alerts/notes sections, recent sessions/activity, and semantic/procedural/relations panels from normalized and filtered arrays; procedural steps are normalized and treated as empty when missing.
Test infrastructure, sandbox, and validation
test/viewer-dashboard.test.ts
Adds a Vitest test that extracts and runs the embedded viewer script in a Node VM sandbox with mocked DOM and globals, seeds malformed dashboard state, asserts renderDashboard() does not throw, and verifies expected UI markers render.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through nulls and broken arrays,
Stitched safe nets for dashboard displays,
Sessions no longer vanish in mist,
Tests sang "Recovered procedure" on my list,
A cheerful rabbit bakes resilient delays.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: tolerate partial dashboard payloads' is concise, specific, and directly summarizes the main change—adding defensive handling for incomplete API responses in the dashboard.
Linked Issues check ✅ Passed The PR fully addresses issue #347's objectives: normalizing dashboard collections to handle missing arrays, gracefully handling sessions without id/project fields via sessionDisplayName helper, and preventing 'Cannot read properties of undefined' errors.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing dashboard payload handling: defensive array normalization in the viewer HTML and a focused regression test for partial payloads.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rohitg00

Copy link
Copy Markdown
Owner

Thanks — the defensive normalization (asArray, firstArray, asString) is exactly the right shape for closing #347 / #340.

This branch now conflicts with main after #366 (#366) landed earlier today. #366 added session-id null-guard helpers (sessionId, sessionDisplayName, sessionLabel) in the same viewer file, so there's overlap at the sessionDisplayName(s) callsite and the dashboard state default object.

Could you rebase against main and resolve? The two patches are complementary — yours handles missing-array fields, #366 handles missing-id session records. Likely the merged shape is: keep your asArray/firstArray for collection defaults, drop your inline s.id || s.project || 'unknown' and use #366's sessionDisplayName(s) helper instead.

I'll merge once it rebases clean + tests pass against current main (956 baseline).

@NgoQuocViet2001 NgoQuocViet2001 force-pushed the fix/347-dashboard-shape branch from 73ac45e to 486f07f Compare May 17, 2026 10:22

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
test/viewer-dashboard.test.ts (1)

39-42: ⚡ Quick win

Harden script bootstrap stripping to avoid brittle test failures.

This replacement only works when those three calls appear in the exact order/format at EOF. A small bootstrap edit can make the test execute real init paths unintentionally.

Proposed diff
-  return match[1].replace(
-    /\s+loadTab\('dashboard'\);\s+connectWs\(\);\s+startDashboardAutoRefresh\(\);\s*$/,
-    "\n",
-  );
+  return match[1].replace(
+    /\n?\s*(loadTab\('dashboard'\)|connectWs\(\)|startDashboardAutoRefresh\(\));\s*$/gm,
+    "\n",
+  );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/viewer-dashboard.test.ts` around lines 39 - 42, The current replace uses
a brittle regex anchored to a specific order of loadTab('dashboard');
connectWs(); startDashboardAutoRefresh(); at EOF (match[1].replace(...)), which
breaks if bootstrap ordering/whitespace changes; update the replacement to
robustly strip those init calls regardless of order/spacing by either performing
three separate replaces on match[1] (e.g., remove
/\s*loadTab\('dashboard'\);\s*/g, /\s*connectWs\(\);\s*/g,
/\s*startDashboardAutoRefresh\(\);\s*/g) or use a single regex that matches any
combination/order before EOF (e.g.,
replace(/(?:\s*(?:loadTab\('dashboard'\)|connectWs\(\)|startDashboardAutoRefresh\(\));?)+\s*$/,'\n')),
so the test no longer depends on exact call order or formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/viewer-dashboard.test.ts`:
- Around line 39-42: The current replace uses a brittle regex anchored to a
specific order of loadTab('dashboard'); connectWs();
startDashboardAutoRefresh(); at EOF (match[1].replace(...)), which breaks if
bootstrap ordering/whitespace changes; update the replacement to robustly strip
those init calls regardless of order/spacing by either performing three separate
replaces on match[1] (e.g., remove /\s*loadTab\('dashboard'\);\s*/g,
/\s*connectWs\(\);\s*/g, /\s*startDashboardAutoRefresh\(\);\s*/g) or use a
single regex that matches any combination/order before EOF (e.g.,
replace(/(?:\s*(?:loadTab\('dashboard'\)|connectWs\(\)|startDashboardAutoRefresh\(\));?)+\s*$/,'\n')),
so the test no longer depends on exact call order or formatting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4b3c2fea-c63e-4c84-81c4-8d8dd49625d5

📥 Commits

Reviewing files that changed from the base of the PR and between 73ac45e and 486f07f.

📒 Files selected for processing (2)
  • src/viewer/index.html
  • test/viewer-dashboard.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/viewer/index.html

@NgoQuocViet2001 NgoQuocViet2001 force-pushed the fix/347-dashboard-shape branch from 486f07f to d90246d Compare May 17, 2026 10:26
@NgoQuocViet2001

Copy link
Copy Markdown
Author

Thanks! I rebased this branch onto current main and resolved the overlap with #366.

I kept the asArray / firstArray collection normalization from this PR, switched the recent session label back to #366's sessionDisplayName(s) helper, and also addressed CodeRabbit's follow-up nit in the dashboard test bootstrap stripping.

Validation: npx vitest run test/viewer-dashboard.test.ts test/viewer-session-id.test.ts passes locally.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
test/viewer-dashboard.test.ts (1)

120-167: 💤 Low value

Consider asserting no console errors to catch silent failures.

The test correctly verifies renderDashboard doesn't throw and renders expected content. Adding an assertion that console.error wasn't called would strengthen confidence that malformed data is handled gracefully without silent errors.

♻️ Optional improvement
     expect(() => (sandbox.renderDashboard as () => void)()).not.toThrow();
+    expect(sandbox.console.error).not.toHaveBeenCalled();
     const dashboard = elements.get("view-dashboard");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/viewer-dashboard.test.ts` around lines 120 - 167, The test should also
assert that no console errors were emitted when rendering malformed dashboard
data: before calling (sandbox.renderDashboard as () => void)(), spy or mock
console.error (e.g., replace with a jest.spyOn or sinon.stub tied to the test's
sandbox/context), call renderDashboard, then assert the spy/stub was not called;
finally restore the original console.error. Target symbols: sandbox,
renderDashboard, and the test's lifecycle so the console.error mock is cleaned
up after the assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/viewer-dashboard.test.ts`:
- Around line 120-167: The test should also assert that no console errors were
emitted when rendering malformed dashboard data: before calling
(sandbox.renderDashboard as () => void)(), spy or mock console.error (e.g.,
replace with a jest.spyOn or sinon.stub tied to the test's sandbox/context),
call renderDashboard, then assert the spy/stub was not called; finally restore
the original console.error. Target symbols: sandbox, renderDashboard, and the
test's lifecycle so the console.error mock is cleaned up after the assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fd6cc7fe-d57e-4e71-9f96-40ae557c116d

📥 Commits

Reviewing files that changed from the base of the PR and between 486f07f and d90246d.

📒 Files selected for processing (2)
  • src/viewer/index.html
  • test/viewer-dashboard.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/viewer/index.html

Signed-off-by: NgoQuocViet2001 <ngoquocviet2001@gmail.com>
@NgoQuocViet2001 NgoQuocViet2001 force-pushed the fix/347-dashboard-shape branch from d90246d to 911873e Compare June 21, 2026 08:13
@NgoQuocViet2001

Copy link
Copy Markdown
Author

Rebased this onto current main and resolved the dashboard-state overlap with the newer graph/session helpers.

Validation:

  • npx vitest run test/viewer-dashboard.test.ts test/viewer-session-id.test.ts - 5 tests passed
  • npm_config_script_shell="C:\Program Files\Git\bin\bash.exe" npm run build
  • git diff --check

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.

Dashboard failed to load: Cannot read properties of undefined (reading 'slice') — v0.9.12

2 participants