Skip to content

App v3: loading, empty and error states - #1270

Merged
PavelMakarchuk merged 16 commits into
mainfrom
feat/v3-ui-states
Oct 14, 2026
Merged

PavelMakarchuk merged 16 commits into
mainfrom
feat/v3-ui-states

Conversation

@PavelMakarchuk

@PavelMakarchuk PavelMakarchuk commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Every async view in app v3 now waits in the shape of what it loads, says plainly when there is nothing to show, and says plainly when something failed, with Try again where it helps. No view in this scope waits for good on a failed request.

What changed

Shared set (components/flagship/states/)

  • EmptyState: one short line, an optional icon and the next action, in a dashed box. It fits the bill feed's "No bills match." + "Clear filters" from Reforms: federal and state bills apart, by stage #1264.
  • ErrorState: a plain message with Try again and more actions. The button stays busy while a refetch is in flight. A compact form goes inside cards.
  • SkeletonRegion, SkeletonLine, CardGridSkeleton: placeholders with one named, busy status.

Build

  • While the parameter index loads, placeholders in the shape of the search bar (or the draft's table) hold its place.
  • When the model's metadata fails: "Could not load the parameters" + Try again (it fetches again).
  • A parameter search with no match offers "Clear search".

Reforms

  • Bills and saved reforms load as placeholder cards in the grid's own tracks.
  • When the bill feed or the saved reforms fail: an error with Try again (it was "Try reloading the page").
  • "No saved reforms yet." + Build a reform. "No reforms match." + Clear search. "No bills match." + Clear filters. "The bill feed is not configured here." and "No analyzed bills yet." use the same empty state.

Report

  • A link that names no report: "Report not found" at once, with no retries, plus Your reforms and Back to Build.
  • When the report or a simulation fails to load: "Could not load the report" + Try again. Only the failed queries are fetched again. Before, the page waited for good.
  • A failed policy does not stop the run (it only costs the provision detail).
  • Until the run starts, a placeholder holds the run card's place.
  • The calculation error now uses ErrorState.
  • When the budget window fails, the window card and the overview summary both offer Try again.

Bill report

  • While the feed loads, a placeholder in the report's shape holds the page.
  • When the feed fails: an error with Try again. A bill that is not in the feed, or a deployment with no feed, gets an empty state and the next step.
  • When the metadata fails, the full results say so and fetch it again (it was "Reload the page"). A failed full run uses the same compact error.

v2 impact

None. All changes are in components/flagship, pages/flagship and libs/flagship, plus these hooks:

  • useFlagshipReport and useTrackedBills: only flagship pages use them.
  • useFlagshipMetadataStatus: new.

No files changed in components/ui, shared calculation code, v2 routes or designTokens.

Overlap with open PRs

Tests run

  • bun run typecheck: pass
  • bunx eslint on every changed file: pass
  • bunx prettier --check on every changed file: pass
  • bunx vitest run on the flagship component, page, hook and lib tests: pass
  • bun run vitest (full suite): 397 files passed, 1 skipped; 4406 tests passed, 10 skipped

New tests: the states (EmptyState, ErrorState, Skeletons), useFlagshipMetadataStatus, useFlagshipReport (not found, failed simulation, failed policy, retry), loadError, ReportLoadError, BillReportStatus, ReportSkeleton / RunProgressSkeleton, Reforms states, Report load states, Build metadata failure, Bill report feed and metadata failures.

🤖 Generated with Claude Code

PavelMakarchuk and others added 11 commits October 14, 2026 14:52
Every v3 report, custom or bill, now opens Validation on three cards:
external estimates (the bill's fiscal note, or related published
scores, or one line that none exists), data calibration (official
totals against PolicyEngine in one aligned table), and baseline
comparisons (the scorecard's published measures). Numbers are
right-aligned in tabular figures; each row opens its details. The
fiscal-note range chip stays in Validation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
External scores and the scorecard's published measures assume current
law. A report compared with another policy now marks both scorecard
cards "Not comparable", names what it compares with, and does not ask
the scorecard. Data calibration still shows. Reports on current law
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EmptyState, ErrorState and skeleton placeholders under
components/flagship/states, so every v3 surface waits, says "none yet"
and fails the same way. ErrorState keeps its retry button busy while a
refetch is in flight, so a second click does not stack requests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While the parameter index loads, placeholders in the shape of the search
bar (or of the draft's table) hold its place. If the model's metadata
fails, Build says so and asks for it again instead of loading for good.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bills and saved reforms load as placeholder cards in the grid's own
tracks. A failed feed or store says so with Try again. No saved reforms
offers Build; a search that hides every card offers to clear it, and
"No bills match." with "Clear filters" uses the bill feed's wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A link that names no report says "Report not found" at once, without
retries. A report, simulation or policy that fails to load shows
"Could not load the report" with Try again, which asks only for what
failed. Until the run starts, a placeholder holds the run card's place.
The calculation error now uses the shared ErrorState.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The window card and the overview's summary both say the window could
not be calculated, with Try again. The summary drops its progress link
while the window has failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While the feed loads, a placeholder in the report's shape holds the
page. A failed feed says so with Try again; a bill the feed does not
carry, or a deployment with no feed, says so with the next step. When
the model's metadata fails, the full results say so and ask for it
again; a failed full run uses the same error state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A policy that fails to load only costs the provision detail, so the
report keeps showing its run instead of the load error. Try again still
asks for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
policyengine-calculator-next Ready Ready Preview Oct 14, 2026 8:22pm UTC
policyengine-website Ready Ready Preview Oct 14, 2026 8:22pm UTC

Request Review

A report or bill feed refetch that fails after the data is in no longer
counts as a failed load: the report keeps its run card (not "Could not
load the report" or "Report not found"), and the bill grid shows no
error above its bills.

The run card and its placeholder are each the one live status on the
report wait. When metadata fails, the report overview says "Could not
load the parameters" with Try again, the same title Build and the bill
report now use. Build's table placeholder draws a row per group, as the
table does, so breakdown members no longer make it shrink on arrival.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk and others added 3 commits October 14, 2026 16:19
# Conflicts:
#	app/src/components/flagship/report/ReportView.tsx
#	app/src/tests/unit/components/flagship/report/ReportView.test.tsx
#	app/src/tests/unit/pages/flagship/Report.test.tsx
ReportValidation now marks external estimates "Not comparable" for a
custom baseline, and its own tests cover that case. The note these two
tests looked for is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	app/src/pages/flagship/BillReport.page.tsx
#	app/src/pages/flagship/Reforms.page.tsx
#	app/src/pages/flagship/Report.page.tsx

This branch was successfully deployed

2 active deployments
Preview – policyengine-calculator-next — d0260927 Deployed Oct 14, 2026 by vercel[bot]
Preview – policyengine-website — d0260927 Deployed Oct 14, 2026 by vercel[bot]
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