Skip to content

fix(dashboard): an empty project says it's empty instead of drawing empty charts (BEA-51) - #101

Merged
ssowonny merged 2 commits into
mainfrom
bea-51-ph-scan-bug-knowledge-insights-renders-empty-chart-frames
Jul 31, 2026
Merged

fix(dashboard): an empty project says it's empty instead of drawing empty charts (BEA-51)#101
ssowonny merged 2 commits into
mainfrom
bea-51-ph-scan-bug-knowledge-insights-renders-empty-chart-frames

Conversation

@ssowonny

Copy link
Copy Markdown
Contributor

TL;DR

  • A brand-new project's Dashboard used to be ~840px of empty bordered boxes with HOT + STALE / HOT + FRESH / COLD + STALE floating over nothing. Now it says the project is empty and points at Installation.
  • Only the zero-files case changed. Files-with-no-reads still charts exactly as before.
  • The project home gets the same message but no button — ConnectGuide right above it already IS the set-up-a-device guide.
  • Folder-scoped dashboards get the same state, worded for the scope ("Nothing in archive to chart yet.").
  • Known gap: the plan wanted this after BEA-49, whose orphans list joins the guard condition. fix(dashboard): keep reads for a deleted file on the map (BEA-49) #100 is still open, so this lands with !scoped.length and a comment marking the spot — see Deviation below.

Screenshots

Dashboard on a project with no files:

Before After
before after

Project home (/<project-id>) — same message, no second CTA under ConnectGuide:

Before After
before after

Folder-scoped route with nothing under it (/<project-id>/dashboard/archive):

Before After
before after

The populated project, unchanged — this is the "files-but-no-reads is untouched" criterion:

Before After
before after

What changed

Insights.tsx rendered its three panels unconditionally. pts derives from flatFiles, so a project with no files gave pts = [] — and then Treemap emitted an empty <svg> at its fixed 720×480 viewBox while Scatter drew its axes, threshold lines and three quadrant labels, all of which come from the HOT_READS/STALE_DAYS constants rather than from data. Only HotPath guarded, and its message ("No reads in the window yet") is the wrong claim for a project that has no files at all.

One early return, placed one level up from the charts — where the three <h3>s and the lens switcher also live, which is what makes "three headers over nothing" go away too. Treemap and Scatter keep no guards of their own.

Two new optional props on Insights:

  • installHref — a real <a> rather than a callback, routed through nav.ts's linkProps so it stays copyable and middle-clickable while still navigating synchronously in-app. The dashboard route passes it; the project home doesn't, since ConnectGuide directly above it is the install guide and a second button six inches under the first reads as two different steps. (This was the plan's flagged judgment call — one prop to flip if you'd rather have it in both places.)
  • loading — not in the plan, and needed. useTree starts with flatFiles = [], so without it the guard fires on the first frame of every dashboard load and a populated project flashes "This project has no files" before the charts arrive. Verified absent: a polling check during a cold load of the seeded wiki never observes .in-blank.

Gated on scoped.length, never on pts.some(p => p.reads) — files-with-no-reads is the other zero state and it was already right (Treemap pads every file to reads + 1 so unread files keep a sliver).

CSS: .in-blank for spacing on top of the existing .dl-empty, plus text-decoration: none added to the existing .pbtn rule now that it also styles an anchor. No new tokens.

Deviation from the plan

The plan's step 1 says land BEA-49 first, because its orphans list belongs in this guard (a project with zero files but orphaned heat rows should still chart). #100 is open and unmerged, so this takes the plan's own stated fallback: the condition is !scoped.length, with the comment above it naming BEA-49 and what joins it. The two PRs will conflict in Insights.tsx; whichever merges second re-derives the guard as !scoped.length && !orphans.length.

Acceptance

  • go build ./..., go vet ./..., go test ./... — all pass.
  • npm run e2e99 passed, including two new cases in dashboard.spec.ts: the empty project (no .in-chart, no "hot + stale" anywhere in the body, message contains "no files", CTA href is /<id>/install) and a no-regression case asserting the seeded project still renders .in-treemap with no .in-blank. The empty project is created and deleted at runtime — a permanent fixture named before wiki would move where the app lands and break home.spec.ts.
  • frontend/check-dist.shinternal/webapp/static is fresh.
  • Manually verified the folder-scoped route: message names the scope, 0 charts, CTA href correct.

Architecture changes

None — Insights is already in architecture/webapp-frontend.md and no type or relationship moves. Two optional props on an existing component.

Build session

cd $(git worktree list | grep bea-51-ph-scan-bug-knowledge-insights | awk '{print $1}') && claude --resume f8533811-1811-494d-9758-001bd2457ea4

(Only works on the machine that ran the build.)

ssowonny and others added 2 commits July 30, 2026 20:12
…mpty charts (BEA-51)

A brand-new project's Dashboard rendered ~840px of empty bordered SVG
frames with the "hot + stale" / "hot + fresh" / "cold + stale" quadrant
labels floating over nothing: Treemap and Scatter had no empty guard, and
the quadrant labels come from the HOT_READS/STALE_DAYS constants rather
than from data. Only HotPath said anything, and what it said ("No reads in
the window yet") is the wrong claim — the project has no files at all.

The guard goes one level up in Insights, where the three panel headers and
the lens switcher also live, so those go away too instead of sitting over
nothing. Gated on "no files", never on "no reads": files-with-no-reads is
the other zero state and it already behaves correctly (Treemap pads every
file to reads + 1 so unread files keep a sliver).

Two new optional props. `installHref` puts a real <a> in the empty state,
routed through linkProps so it stays copyable and middle-clickable — the
dashboard route passes it, the project home doesn't, because ConnectGuide
directly above it IS the set-up-a-device guide. `loading` keeps the tree's
first frame from claiming a populated project has no files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	internal/webapp/static/assets/index-B9pybzqe.css
#	internal/webapp/static/assets/index-iGTfiq-J.js
#	internal/webapp/static/index.html
@ssowonny
ssowonny merged commit 9c18c83 into main Jul 31, 2026
2 checks passed
@ssowonny
ssowonny deleted the bea-51-ph-scan-bug-knowledge-insights-renders-empty-chart-frames branch July 31, 2026 09:19
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.

1 participant