toga-ai 1.0.251 → 1.0.252

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.
@@ -8,5 +8,5 @@
8
8
  | [Column Visibility (URL-driven show/hide columns)](features/column-visibility.md) | A "Columns" header button that opens a modal listing every column from the table meta, lets the user show/hide columns, adjusts the table live, and persists the | toga25-supply/src/components/ColumnVisibilityModal/, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrdersTableData.tsx |
9
9
  | [Meta-Driven Page & Table Setup](features/meta-driven-table-data.md) | A page in this app is **meta-driven end to end**: the page view model fetches *page meta* (labels, sections, ACL) and *table meta* (the columns/fields + table s | toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrdersTableState.ts, toga25-supply/src/hooks/useTablePageMeta.ts, toga-blox-npm/dist/hooks/useFetchPageMeta.d.ts, toga-blox-npm/dist/hooks/useFetchTablePageMeta.d.ts, toga-blox-npm/dist/hooks/useAssignTableFieldLabels.d.ts, toga-blox-npm/dist/components/Table/hooks/useTableData.d.ts |
10
10
  | [Record Modals & Nested Tables](features/record-modals-and-nested-tables.md) | The repo's family of modal + nested-table patterns layered over toga-blox `TableRecordModal` and `PrimaryTable*Layout`. | toga25-supply/src/layout/ItemRecordModalLayout/, toga25-supply/src/layout/SalesOrderRecordModalLayout/, toga25-supply/src/layout/SalesOrderItemsTableLayout/, toga25-supply/src/layout/ItemFulfillmentModal/, toga25-supply/src/layout/GenericNestedTables/, toga25-supply/src/hooks/useTableCellInteractions.ts |
11
- | [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/componentRegistry.tsx, toga25-supply/src/surface/SurfaceActionBar.tsx, toga25-supply/src/surface/SurfaceSection.tsx, toga25-supply/src/surface/resolve.ts, toga25-supply/src/surface/types.ts, toga25-supply/src/surface/index.ts, toga25-supply/src/pages/Login/LoginPage.tsx, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/Items/ItemsPage.tsx, toga25-supply/src/pages/Items/viewModel/useItemsPageViewModel.tsx, toga25-supply/src/pages/VendorItems/VendorItemsPage.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/Inventory.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/index.ts, toga25-supply/src/fieldsConfig/index.ts |
11
+ | [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/componentRegistry.tsx, toga25-supply/src/surface/SurfaceActionBar.tsx, toga25-supply/src/surface/SurfaceSection.tsx, toga25-supply/src/surface/resolve.ts, toga25-supply/src/surface/types.ts, toga25-supply/src/surface/index.ts, toga25-supply/src/pages/Login/LoginPage.tsx, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/Items/ItemsPage.tsx, toga25-supply/src/pages/Items/viewModel/useItemsPageViewModel.tsx, toga25-supply/src/pages/VendorItems/VendorItemsPage.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/Inventory.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/index.ts, toga25-supply/src/fieldsConfig/index.ts |
12
12
  | [Cypress Testing Harness (component + e2e)](workflows/cypress-testing.md) | The Cypress test harness for the `toga25-supply` frontend, bootstrapped from scratch (`cypress` was already a dependency but there was no config, no `cypress/` | toga25-supply/cypress.config.ts, toga25-supply/cypress/tsconfig.json, toga25-supply/cypress/support/component.tsx, toga25-supply/cypress/support/component-index.html, toga25-supply/cypress/support/e2e.ts, toga25-supply/cypress/support/commands.ts, toga25-supply/cypress/support/fixtures.ts, toga25-supply/cypress/support/mocks/useApprovalModalViewModel.ts, toga25-supply/cypress/component/SalesOrderApprovalModalsLayout.cy.tsx, toga25-supply/cypress/component/RecordApprovalModalLayout.cy.tsx, toga25-supply/cypress/component/EnterPoNumberModal.cy.tsx, toga25-supply/cypress/e2e/salesOrderApproval.cy.ts |
@@ -11,7 +11,11 @@ owners: [jcardinal, apeterson]
11
11
  files:
12
12
  - toga25-supply/src/surface/useFetchSurfaceMeta.ts
13
13
  - toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts
14
+ - toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts
14
15
  - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx
16
+ - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx
17
+ - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx
18
+ - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx
15
19
  - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts
16
20
  - toga25-supply/src/surface/evaluateSurfaceRule.ts
17
21
  - toga25-supply/src/surface/actionRegistry.ts
@@ -56,15 +60,18 @@ feature flag — see below). Backend: [surface-resolver](../../_underscore/featu
56
60
  **structural fingerprint**: `looksLikeBundle` now requires **both** an `elements` array **and** a
57
61
  `surface` descriptor object (not the `elements` array alone — see the decoy gotcha below).
58
62
  `extractBundle(raw, slug)` then **prefers** the bundle whose `surface.slug === slug`, falling back to
59
- first-found, so a stray sibling bundle can't win. `looksLikeGroup` requires the documented `group`
60
- discriminator key so a single-bundle envelope is not mistaken for a group. On a malformed payload it
63
+ first-found, so a stray sibling bundle can't win. On a malformed payload it
61
64
  falls back to a safe empty bundle (empty `elements` + empty `messages`/`theme`/`vocabularies` maps)
62
65
  so the page never crashes.
63
66
  - **`useFetchSurfaceMetaGroup(slugs[])`** — the grouped sibling of `useFetchSurfaceMeta`, for a screen
64
67
  needing many section surfaces at once. **Order-insensitive** (the slug list is normalized so cache
65
68
  hits don't depend on argument order), `staleTime: Infinity`, hits the grouped endpoint
66
- `GET /v2/surfaces/meta-group?slugs=...`, and extracts the `{surfaces}` map via `extractGroup()` /
67
- `looksLikeGroup()` (the same structural-fingerprint approach as `extractBundle`). Returns `{}` for
69
+ `GET /v2/surfaces/meta-group?slugs=...`, and extracts the SLUG-keyed `{surfaces}` map via the
70
+ recursive **`findSurfaceMap(raw, depth=5)`** — which walks the envelope tree and returns the
71
+ `surfaces` map whose **values look like bundles** (or an empty/null map), uniquely identifying the
72
+ inner slug-keyed map regardless of nesting or `data` wrapping. (`extractGroup`'s old
73
+ `data`/`data.<key>` probe and the `looksLikeGroup` `group`-discriminator check were both removed —
74
+ see the group-nesting gotcha below for why.) Returns `{}` for
68
75
  unmigrated screens (`enabled:false`), so a non-roster client does no fetch.
69
76
  - **`componentRegistry`** (`src/surface/componentRegistry.tsx`) — the **presentation sibling** of
70
77
  `actionRegistry`, both keyed by the surface meta's `action.key`. `actionRegistry` maps key→behavior
@@ -154,6 +161,17 @@ three bespoke renderers `detailSection`/`locationCard`/`totalsCard` are untouche
154
161
  `getDetailSections` are untouched — **only the SOURCE of section config moves JSON → Surface.**
155
162
  Business logic stays in code: the recurring-lease `_totalLease` gate in the grid and approval
156
163
  gating are **not** moved. (Registered-renderer seam: *config describes, code decides.*)
164
+ - **Full adapter-seam data path (verified this session, no direct `<SurfaceSection>`):**
165
+ `useFetchSurfaceMetaGroup(SALES_ORDER_SURFACE_SLUGS)` → `surfaceBundleToTenantFields(surfaces)` →
166
+ merged into `tenantFields` (roster clients only; `clientSlug` is the **uppercased** `getHostname()`
167
+ result matched against the roster) → **`buildPatchedTenantFields`** (which only overrides
168
+ `recordActionFields`, so it **preserves all surface section keys**) → `SalesOrderView` →
169
+ **`SalesOrderSummaryGrid`** (renders by `section.type` / `cardType`:
170
+ `detailSection`/`locationCard`/`totalsCard`, where `cardType` comes from `surface.config.cardType`)
171
+ + **`getDetailSections`** (reads `section.isVisible` for the `displayToggle` sections, which carry a
172
+ `sectionVisibility` marker element). **Decision (confirmed by the developer this session): KEEP the
173
+ adapter approach — do NOT replace it with a direct `<SurfaceSection>` swap.** The bespoke grid
174
+ renderers and the `TenantFields` seam are the deliberate integration point.
157
175
  - **Roster gate — `SALES_ORDER_SURFACE_MIGRATED_CLIENTS = [COMPASS, COMPASSCANADA, QUAD]`** (an
158
176
  in-code roster in `surfaceBundleToTenantFields.ts`; the view-model
159
177
  `useSalesOrderRecordModalLayoutModel.tsx` consults it). The view-model resolves sections from
@@ -182,6 +200,27 @@ seeding NYCHH/Prudential/SPGlobal is deferred; the Client-DB prod cross-cluster
182
200
  bundle → the action bar renders nothing. Fix: `looksLikeBundle` must require **both** `elements` AND
183
201
  a `surface` descriptor; use recursive `findBundle` + slug-preferring `extractBundle` (see How it
184
202
  works). The durable backend follow-up is to confirm/stabilize the single-meta envelope contract.
203
+ - **The GROUPED meta envelope double-nests the slug-keyed `surfaces` map under an OUTER route-keyed
204
+ `surfaces` slot — match by value shape, never grab the first `surfaces`.** The meta-group V2 envelope
205
+ mirrors single-meta's bundle nesting: the real SLUG-keyed map sits one level deeper under a ROUTE-keyed
206
+ outer slot — `{ surfaces: { "meta-group": { group, surfaces: { "order-details": bundle, … } } },
207
+ elements: [] }`. The old `extractGroup` grabbed the **first** `surfaces` it saw (the outer route-keyed
208
+ one, whose values are *group* objects, not bundles), so `surfaces["order-details"]` was `undefined`
209
+ and `surfaceBundleToTenantFields` produced `{}` — every migrated-client SalesOrders section vanished.
210
+ Fix: recursive **`findSurfaceMap(raw, depth=5)`** returns the `surfaces` map whose **values look like
211
+ bundles** (or null/empty), uniquely identifying the inner slug-keyed map regardless of nesting or
212
+ `data` wrapping. Verified by trace across 6 envelope shapes (double-nested, resolver-return-at-top,
213
+ simple, data-wrapped, null-child, empty). **Note:** an earlier attempt that required a top-level
214
+ `group` discriminator on the probed level (`looksLikeGroup`) broke the fetch (returned `{}`) because
215
+ the V2 envelope carries no top-level `group` at that level — `looksLikeGroup` was removed entirely.
216
+ - **For migrated clients, a dropped (`surface: null`) display section silently vanishes — there is no
217
+ JSON fallback left.** Once a client's JSON section blocks are deleted (roster migration), a section
218
+ whose surface resolves to `surface: null` (a seed/ACL gap, e.g. `additional-order-details` /
219
+ `admin-notes` / `notes`) is dropped by `surfaceBundleToTenantFields` and the section disappears with
220
+ no fallback. That is a backend seed/ACL gap, **not** an FE bug. Separately, two sections are
221
+ intentionally gated in `getDetailSections`: `shipments` is **permanently hidden** (the view-model
222
+ hardcodes `shipmentsData: []` and `useShipments` is commented out; the section gates on
223
+ `shipmentsData.length > 0`), and `invoices` is data-gated on `invoiceData.length > 0`.
185
224
  - **The surface `record` shape must match the rule field namespace — wrap as `{ order }`.** Seeded
186
225
  Tier-1 rules namespace their field as `order._status`, so `getByPath(record, "order._status")` only
187
226
  resolves if the host passes `record={{ order }}`. Passing the bare order object resolves to
@@ -210,6 +249,19 @@ seeding NYCHH/Prudential/SPGlobal is deferred; the Client-DB prod cross-cluster
210
249
  treat type-checking as pending. Runtime `GET /v2/surfaces/{slug}/meta` also not yet exercised.
211
250
 
212
251
  ## Change history
252
+ - 2026-06-30 — Follow-up: fixed the GROUPED meta fetch returning `{}` (every migrated-client
253
+ SalesOrders section had vanished). The meta-group envelope double-nests the slug-keyed `surfaces`
254
+ map under an outer ROUTE-keyed `surfaces` slot; the old `extractGroup` grabbed the first (outer,
255
+ group-valued) `surfaces`. Replaced it with recursive `findSurfaceMap(depth=5)` that returns the
256
+ `surfaces` map whose values are bundle-shaped (verified across 6 envelope shapes). **Reverted the
257
+ earlier same-session `group`-discriminator `looksLikeGroup` change** — requiring a top-level `group`
258
+ broke the fetch; `looksLikeGroup` removed entirely. Verified the SalesOrders section migration is
259
+ fully wired via the adapter seam (`useFetchSurfaceMetaGroup` → `surfaceBundleToTenantFields` →
260
+ `buildPatchedTenantFields` (overrides only `recordActionFields`) → `SalesOrderSummaryGrid` /
261
+ `getDetailSections`) and confirmed the decision to KEEP the adapter over a direct `<SurfaceSection>`.
262
+ Documented why some sections stay hidden (`shipments` hardcoded empty; `invoices` data-gated; and a
263
+ dropped `surface: null` display section vanishes with no JSON fallback for migrated clients — a
264
+ seed/ACL gap). (apeterson)
213
265
  - 2026-06-30 — Migrated the SalesOrders record-modal sections onto Surface for the roster clients
214
266
  [COMPASS, COMPASSCANADA, QUAD] via the registered-renderer seam: added `useFetchSurfaceMetaGroup`
215
267
  (order-insensitive grouped `/surfaces/meta-group` fetch) + `surfaceBundleToTenantFields()` (adapts
@@ -221,7 +273,7 @@ seeding NYCHH/Prudential/SPGlobal is deferred; the Client-DB prod cross-cluster
221
273
  - 2026-06-30 — Debugged + extended the client-side action-bar renderer (no client-specific work).
222
274
  Fixed three rendering bugs: (1) the single-meta envelope's **decoy `elements: []`** masked the real
223
275
  nested bundle — `looksLikeBundle` now requires `elements` AND a `surface` descriptor, with recursive
224
- `findBundle(depth=4)` + slug-preferring `extractBundle` + `group`-discriminator `looksLikeGroup` +
276
+ `findBundle(depth=4)` + slug-preferring `extractBundle` +
225
277
  safe empty `messages`/`theme`/`vocabularies` fallback (`useFetchSurfaceMeta.ts`); (2) Tier-1 rules
226
278
  always false because the host passed the bare order object instead of the `{ order }` envelope the
227
279
  `order.*` field namespace requires (`SalesOrderTopBar.tsx`); (3) every action icon rendered as
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.251",
3
+ "version": "1.0.252",
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",