toga-ai 1.0.496 → 1.0.497

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,88 @@
1
+ ---
2
+ type: session
3
+ slug: toga25-loading-states
4
+ title: Design-mockup loading states for toga25-supply tables and modals
5
+ author: tcox
6
+ repos: [toga25-supply, toga-blox-npm]
7
+ framework: "2.0"
8
+ client: shared
9
+ status: active
10
+ created: 2026-08-03
11
+ updated: 2026-08-03
12
+ ---
13
+
14
+ # Session: toga25-loading-states
15
+ **Date:** 2026-08-03
16
+ **Project/Repo:** toga25-supply + toga-blox-npm (2.0)
17
+ **Task:** Implement the "Toga25-supply mockup" design's loading states — table skeletons (initial/refresh/filter), pagination loading, Refresh busy pill, bulk progress toast, and modal skeletons (cold/warm/sub-section) — pixel-faithful to the mockup, in toga25-supply with supporting toga-blox changes.
18
+
19
+ ---
20
+
21
+ ## What WORKED
22
+ - **TableSkeleton built on the real table's CSS module** — `src/components/TableSkeleton/TableSkeleton.tsx` imports `@agilant/toga-blox/dist/components/Table/themeConfig/toga.module.css` (the exact module the blox PrimaryTable is styled by), so skeleton and loaded table are pixel-identical by construction. Real header labels + static sort glyphs from table meta, type-aware cells (status dot, avatar circle, image tile + label bar, badge pill), real pagination chrome. **User visually approved.** Wired into `PrimaryTableServerLayout` replacing blox `TableShimmer`.
23
+ - **Shimmer texture matched to design** — `Shimmer.module.css` overlay rewritten to the mockup gradient: 100deg, transparent→38%, `#F7F8FB` at 50% (strong: `#F0F2F6`), →62% transparent, 100vw-wide band, 2s linear. Fixes every skeleton app-wide (modals included).
24
+ - **Pagination loading** — blox `TablePagination` gained `loadingPage?: number | null` (threaded through `PrimaryTable` + server template + both types); shows 12px spinner + `Loading page N…` (`.paginationLoadingText`, #72757D/14px) in place of the count; `TableBody` dims to 0.55 (`.bodyDimmed`) while a page fetch is in flight; controls stay full-strength (pointer-events blocked only). App wrapper detects page fetch via new `page` prop vs `paginationMeta.page` (`isPageFetch`) — refresh/filter/sort still show the full skeleton (per design), page changes keep rows.
25
+ - **Refresh busy pill** — all 5 pages (SalesOrders, Items, Bundles, VendorItems, Inventory): icon spins 1.1s in fixed 20px box (`.refreshIconBox` in `src/index.css`), label flips to `Refreshing…`; `useIsFetching({queryKey:["table-data"], predicate: q => q.state.data !== undefined})` excludes cold loads.
26
+ - **Fidelity audit (agent) against mockup source** confirmed shimmer/spinner/copy exact and produced 14 fixes, all applied: no columnBorders on skeleton (loaded table has none), rows 16, sort glyph placeholder, avatar/image/badge shapes, active-filter chip stays in skeleton header (`filteredColumnSlugs` from `columnFilters`), bulk toast track 14px + `background-attachment: fixed` + cancel spacing.
27
+ - **Modal skeletons (sales-order modal)** — cold = existing `SalesOrderModalSkeleton` (header shimmer); warm = new `warmHeader` prop renders real `SalesOrderTopBar` from the clicked row while body shimmers; row context plumbed as optional `row` on both wrappers' `renderModal` (server + client), passed as `rowRecord` from SalesOrders.tsx. Sub-section refresh = `SubSectionShimmer` (3×36px r6 bars) in Invoices/Shipments sections while their independent queries (`useInvoices`/`useShipments`) load — sections keep frame+title, no longer pop in late; `getDetailSections` show-gates include loading.
28
+ - **CodeRabbit fixes** — client wrapper's `renderModal` moved OUTSIDE the loading gate (open modal no longer unmounts on table refetch); shared `TableRowRecord = { uuid: string } & Record<string, unknown>` exported from `PrimaryTableServerLayout/types.ts`, reused in both wrappers + modal, `displayRecords` tightened to it (killed 2 pre-existing no-explicit-any errors).
29
+ - **Components added**: `BulkProgressToast` (design-exact, unwired — no bulk feature exists), `SubSectionShimmer`; barrel exports updated.
30
+ - **Client testing infra** — hosts entries added via UAC-elevated PowerShell (`Start-Process powershell -Verb RunAs`) for `compasscanada.dev.sandbox.togasupply` and `nychh.dev.sandbox.togasupply`; NYCHH is the inventory client (only one with dedicated `NYCHH_INVENTORY_GROUPINGS`). All dev servers closed at session end.
31
+ - Every round verified with `npx tsc --noEmit` + eslint (touched files) + `npm run build` — all clean at session end.
32
+
33
+ ## What did NOT work — DO NOT RETRY THESE
34
+ - **Hand-rolled skeleton from mockup geometry + big-bang parallel implementation.** First attempt (3 parallel agents: components + table wiring + modal wiring incl. error states) rendered a skeleton with no card border, no header labels, equal-width bars, bright white glint — user: "further off than we started" and **reverted everything** (`git checkout` + clean). Do not rebuild loading UI from the mockup's px values directly; mirror the app's real rendered table (shared CSS module) and ship ONE state at a time for visual sign-off.
35
+ - **`background-attachment: fixed` for the unison shimmer inside modals** — breaks inside the record modal's transform (treated as local). Use the per-element 100vw translateX overlay with the same gradient instead (deliberate, documented in `Shimmer.module.css`). It IS fine for `BulkProgressToast`'s progress fill (not inside a transform).
36
+ - **Rebuilding toga-blox while dev servers run** — `prebuild rm -rf dist` fails with "Directory not empty" (Windows file locks from Vite dep-optimizer). Stop all vite servers first, then `cd /c/WWW/toga-blox-npm && npm run build`, then restart (and `rm -rf node_modules/.vite` in the app if the browser shows stale-dep errors).
37
+ - **Starting a client dev server without its hosts entry** — vite resolves `--host` via DNS at startup: `Error: getaddrinfo ENOTFOUND compasscanada.dev.sandbox.togasupply`. The hosts entry must exist BEFORE `npm run <client>`. Binding 127.0.0.1 instead is NOT a workaround: the client slug comes from the first hostname segment at login.
38
+ - **Background Bash tasks inherit `c:\WWW` cwd, not the repo** — `npm run compasscanada` failed "Missing script"; always `cd /c/WWW/toga25-supply && npm run …` in background commands. Foreground shell cwd also resets between some calls.
39
+ - **`TaskStop` on an `npm run` vite server orphans the node child** holding the port — after stopping, kill listeners: `netstat -ano | grep LISTENING | grep ":517"` → `taskkill //F //PID <pid>`.
40
+ - **Blanket sed for `page,` insertion** hit the wrong block in `useItemFulfillmentModalViewModel.tsx` (duplicated `page` inside a destructure = syntax error). Targeted Edit with unique context fixed it.
41
+ - **`useIsFetching` without a predicate** made Refresh show "Refreshing…" during cold loads (design shows it only for refetches of on-screen data).
42
+
43
+ ## Not tried yet (candidates for next session)
44
+ - **Table error states** (server/timeout/empty/no-results/permission/maintenance/ratelimit per mockup ErrorBlock) — spec extracted at scratchpad `table-states-spec.md` §2.12-2.14/§4; first attempt reverted; needs the app-side error surface (`useTableData` discards query errors — an app hook subscribing to the query cache by `["table-data", slug]` prefix worked in the reverted round and can be reused conceptually).
45
+ - **Modal error states** (generic/not-found/permission/conflict per `modal-states-spec.md` §§7-10) — `src/components/RecordLoadError` exists (unused, generic copy matches mockup); six placeholder `<>Error</>` sites mapped in the reverted round's integration map.
46
+ - **Warm open for Item/VendorItem/Bundle record modals** — same two-step as sales-order: accept `rowRecord`, hand real header to skeleton via `warmHeader`-style prop.
47
+ - **TableSkeleton for `PrimaryTableClientLayout`** (modal-embedded tables still use blox `TableShimmer`; also its skin is `supply-modal-table`, different tokens).
48
+ - **Bulk feature wiring** — `BulkProgressToast` has zero consumers; per-row processing scrim (100deg `rgba(63,93,202,0.06)` at 50%) not implemented; app has no bulk selection at all.
49
+ - **Class-B inherited chrome differences (USER DECISION PENDING)** — app table vs mockup: header ~38px/14px vs 34px/13px, rows ~40px vs 48px, cell padding 25px vs 12px, separators #D4D5D8 vs #E8E9EA, "per page" vs "rows shown", filter chip #4f6bd4/r2 vs #3F5DCA/r5 (looks like a blox bug), card shadow. Fixing = restyling the live table in toga-blox.
50
+ - **blox bug**: `.tableAndPaginationInner.supply` sets `font-size: var(--primaryTable-pagination-text-default)` which resolves to a COLOR (#8C8E96) — declaration silently dropped, text inherits ~16px.
51
+
52
+ ## Current file state
53
+ | File | Status | Notes |
54
+ |------|--------|-------|
55
+ | toga25-supply `src/components/TableSkeleton/` | new | CSS-module-mirroring table skeleton (approved) |
56
+ | toga25-supply `src/components/BulkProgressToast/` | new | design-exact, unwired |
57
+ | toga25-supply `src/components/SubSectionShimmer/` | new | 3×36px bars sub-section well |
58
+ | toga25-supply `src/components/Shimmer/Shimmer.module.css` | modified | 100deg subtle band per design |
59
+ | toga25-supply `src/components/index.ts` | modified | new barrel exports |
60
+ | toga25-supply `src/layout/PrimaryTableServerLayout/{.tsx,types.ts}` | modified | TableSkeleton gate, `page`/isPageFetch, `loadingPage`, `filteredColumnSlugs`, `renderModal.row`, `TableRowRecord` |
61
+ | toga25-supply `src/layout/PrimaryTableClientLayout/{.tsx,types.ts}` | modified | `renderModal` outside gate + row context; still blox TableShimmer for loading |
62
+ | toga25-supply 6 table layouts + 2 VMs | modified | pass `page` through (SalesOrders/Items/Bundles/VendorItems/Generic/ItemFulfillment) |
63
+ | toga25-supply 5 pages | modified | Refresh busy pill + predicate |
64
+ | toga25-supply `src/index.css` | modified | `.refreshIconBox` + 1.1s spin keyframes |
65
+ | toga25-supply SalesOrderRecordModalLayout + view/VM/sections/skeleton/helpers | modified | warm/cold/sub-section modal loading states |
66
+ | toga-blox-npm (branch `feature-new-table`) `TablePagination.tsx` + `types.ts` | modified | loadingPage indicator, full-strength controls |
67
+ | toga-blox-npm `PrimaryTable.tsx` + `Table/types.ts` | modified | loadingPage threading, bodyDimmed on TableBody |
68
+ | toga-blox-npm `toga.module.css` | modified | `.paginationSpinner`, `.paginationLoadingText`, `.bodyDimmed` |
69
+ | toga-blox-npm `dist/` | rebuilt | current with all source changes |
70
+ | **Both repos: all changes UNCOMMITTED** (toga25-supply on `phase-two`) | — | user decides when/how to land |
71
+
72
+ ## Decisions made
73
+ - **Skeletons mirror the real rendered app table, not the mockup's raw geometry** — share the blox CSS module so load→loaded never shifts; the mockup's own px values only apply where the app matches them. Chosen after the hand-rolled attempt was reverted. Rejected: patching blox `TableShimmer` (8 hardcoded columns, Tailwind-JIT-fragile).
74
+ - **One state at a time with user visual sign-off** — replaced the 3-slice parallel big-bang that got reverted.
75
+ - **Per-element translateX shimmer overlay** (viewport-anchored gradient breaks in transformed modals); exact mockup gradient stops preserved.
76
+ - **Page-fetch detection at the wrapper** via requested `page` vs `paginationMeta.page` — no blox useTableData changes needed.
77
+ - **Loading-state-only scope** — explicitly did NOT change Refresh button idle chrome (`secondaryActionAlt` stays, though mockup pill is blue), nor any class-B live-table styling; user instruction.
78
+ - **`TableRowRecord` typed with `unknown` not `any`**; alias lives in the server layout types (the "table-layout contract"), client types re-export.
79
+ - **Modal-embedded client tables render bare when empty** (no onboarding panel) — empty is normal there.
80
+
81
+ ## Blockers
82
+ none — pending items are user decisions (class-B chrome; when to commit) and the next feature slices.
83
+
84
+ ## Exact next step
85
+ > With DevTools throttling on, visually verify the three modal skeleton states in the sales-order modal (click a row = warm header; reload with the uuid in the URL = cold; watch Invoices/Shipments shimmer wells), then replicate the warm pattern to ItemRecordModalLayout, VendorItemRecordModalLayout, and BundleRecordModalLayout, and start the table error states from `table-states-spec.md` (scratchpad specs may be gone — re-extract from `Toga25-supply mockup/src/inventory-table.jsx` §ErrorBlock if so).
86
+
87
+ ---
88
+ _Saved by /session-save on 2026-08-03_
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.496",
3
+ "version": "1.0.497",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",