CLAUDE.md: add UI section covering Pivot inspector patterns

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul Trowbridge 2026-05-02 10:39:25 -04:00
parent b52f5c930e
commit bef3d6d89c

View File

@ -140,6 +140,28 @@ records.data → apply_transformations() →
- Server.js has global error handler - Server.js has global error handler
- Database functions return JSON with `success` boolean - Database functions return JSON with `success` boolean
## UI (React + Vite)
The frontend lives in `ui/src/` and is built to `public/` via `npm run build` from the `ui/` directory. **Always run `npm run build` from `ui/` after any changes to `ui/src/` files.**
### Pages
- **Sources / Rules / Mappings / Records** — standard CRUD pages
- **Pivot** (`ui/src/pages/Pivot.jsx`) — interactive pivot/crosstab powered by Perspective (`@perspective-dev` v4.4.0, loaded from CDN). See `docs/perspective-pivot.md` for the full Perspective API reference.
- **Stacks** — multi-source union views with running balance
- **Log** — import audit trail
### Pivot inspector panel
Clicking a data cell opens a right-hand inspector panel showing the underlying transactions for that cell. Key behaviors:
- **Toggle**: clicking the same cell again closes the panel. The toggle key is `JSON.stringify({ p: row.__ROW_PATH__, c: column_names })` — stable across source and stack views.
- **Listener cleanup**: the `perspective-click` handler is stored in `perspClickHandlerRef` and removed via `removeEventListener` on effect cleanup. Without this, switching views accumulates duplicate listeners that fire multiple times per click.
- **split_by filter derivation**: `detail.config.filter` from the click event may omit split_by column constraints. They are derived from `column_names` positionally (`column_names[i]` matches `config.split_by[i]`) and appended to the filter before querying.
- **Row filtering**: a temporary `table.view({ filter, expressions })` is used so Perspective evaluates expression/computed columns correctly. Falls back to JS-side `filterRowsByConfig` on error (which skips filters for fields not in raw data).
- The panel is resizable via a drag handle on its left edge (`paneWidth` state, min 240px).
- The transaction table is sortable (click header) and shows column totals for all-numeric columns.
## File Structure ## File Structure
``` ```
@ -154,6 +176,14 @@ dataflow/
│ ├── rules.js │ ├── rules.js
│ ├── mappings.js │ ├── mappings.js
│ └── records.js │ └── records.js
├── ui/
│ ├── src/
│ │ ├── pages/ # One file per page
│ │ └── api.js # API client
│ └── package.json
├── public/ # Built UI (gitignored, generated by npm run build)
├── docs/
│ └── perspective-pivot.md # Perspective API reference
├── examples/ ├── examples/
│ ├── GETTING_STARTED.md # Tutorial │ ├── GETTING_STARTED.md # Tutorial
│ └── bank_transactions.csv │ └── bank_transactions.csv