Commit Graph

5 Commits

Author SHA1 Message Date
0459fa137d Stop loading the whole version twice on every page load
The version re-validation effect could not tell "the versions fetch has not
landed yet" from "this source has no versions", because both look like an
empty array. So a versionId restored from localStorage was cleared on the
first render and set straight back when the fetch returned: 29 -> '' -> 29.

Forecast's load effect is keyed on [versionId, sourceId], so that round
trip ran initViewer twice. Two /agg requests, two full aggregations in
Postgres, two Arrow payloads -- on version 29 that is the 285k-row
aggregate computed twice at ~17s each, which is most of the "it hangs
before it displays" and the Postgres process sitting at the top of htop.

sourcesLoaded already guarded the identical effect for sources; versions
just never got the same treatment. Cleared when the source changes, since
the list belongs to the previous source until the new fetch lands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:42:38 -04:00
e31a60b18b Re-check the selected source and version against the live list
The selection is restored from localStorage, but it was only validated once
at mount. Deregistering the selected source left App holding an id that no
longer exists, so every subsequent call 404'd "Source not found" with no way
out but a reload — Setup.deleteSource clears its own selectedSource and never
tells App. Deleting the selected version had the same shape.

Move both checks into effects keyed on the lists themselves. A sourcesLoaded
flag keeps the source effect from firing against the initial empty array and
wiping the restored id before the fetch resolves.

Also coerce both refresh callbacks to an array. A 401 returns an error object,
and data.some() then threw inside an unhandled promise, stranding the
selection instead of clearing it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit e6e2faeb37)
2026-09-15 21:31:07 -04:00
e279a510d8 Lift source/version selection to a functional StatusBar
App.jsx owns sources/sourceId/versions/versionId and persists them
across reloads. StatusBar renders the dropdowns plus a status badge —
Source-only on Setup, Source · Version · status on Baseline/Forecast.
The duplicate in-view selector bars in Forecast and Baseline are gone;
Baseline keeps its version actions (New/Close/Reopen/Delete) inline.
Setup reports source-list mutations up via refreshSources so the bar
stays in sync after register/deregister.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 20:54:55 -04:00
4a4cb80189 Add light/dark mode with theme toggle 2026-04-25 23:29:25 -04:00
dc090fe394 Scaffold React/Vite/Tailwind UI with 3-step Setup → Baseline → Forecast flow
- ui/: React + Vite + Tailwind app (Setup, Baseline, Forecast views, collapsible sidebar, status bar, canvas timeline)
- server.js: serve built UI from public/app/
- package.json: add build script (cd ui && npm run build)
- routes/sources.js: default new col_meta role to 'dimension' instead of 'ignore'
- .gitignore: exclude public/app/ build output
- pf_spec.md: update tech stack, nav, frontend section, and project status to reflect current implementation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 16:28:45 -04:00