toga-ai 1.0.747 → 1.0.749
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.
- package/knowledge/2.0/apps/toga-blox/INDEX.md +1 -1
- package/knowledge/2.0/apps/toga-blox/features/table-record-modal.md +34 -1
- package/knowledge/2.0/apps/toga-blox/features/talos-assistant.md +50 -1
- package/knowledge/clients/nychh/INDEX.md +1 -1
- package/knowledge/clients/nychh/features/talos-assistant-enablement.md +110 -26
- package/knowledge/sessions/2026-09-02-transfer-order-create-modal-apeterson.md +106 -0
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
| [Primary Table templates (server/client, sizing, virtualization)](features/primary-table-templates.md) | `src/templates/PrimaryTable/` is the **production, wired-up table** built on the [Table component](table.md). | toga-blox/src/components/Table/themeConfig/toga.module.css, toga25-supply/src/themeConfig.json, toga-blox/src/templates/PrimaryTable/PrimaryTable.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableServerTemplate.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableClientTemplate.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableHeaderCell.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableBodyCell.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableRow.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableExpandableRow.tsx, toga-blox/src/templates/PrimaryTable/types.ts |
|
|
12
12
|
| [TableRecordModal (record-detail modal shell)](features/table-record-modal.md) | `TableRecordModal` is a **generic, presentational modal shell** for showing a single table record (row) in detail — typically opened from a table row click. | toga-blox/src/components/TableRecordModal/TableRecordModal.tsx, toga-blox/src/components/TableRecordModal/index.ts, toga-blox/src/components/TableRecordModal/tableRecordModal.module.css |
|
|
13
13
|
| [Table component (cells, action cells, filters & sorts, hooks, theming)](features/table.md) | The `Table` component (`src/components/Table/`) is the **TanStack Table v8** building block behind the [Primary Table templates](primary-table-templates.md). | toga-blox/src/components/Table/hooks/useFetchTablePageMeta.ts, toga-blox/src/api/types.ts, toga-blox/src/components/Table/index.ts, toga-blox/src/components/Table/types.ts, toga-blox/src/components/Table/utils/buildTanstackColumns.tsx, toga-blox/src/components/Table/utils/resolveCellType.tsx, toga-blox/src/components/Table/components/cellTypes, toga-blox/src/components/Table/components/actionCells, toga-blox/src/components/Table/components/columnFiltersAndSorts, toga-blox/src/components/Table/hooks, toga-blox/src/components/Table/themeConfig |
|
|
14
|
-
| [Talos AI-Assistant Component (launcher + docked/drawer chat panel)](features/talos-assistant.md) | `Talos` is a **shared, pure-UI** AI-assistant component in `@agilant/toga-blox`: a header launcher button (`TalosLauncher`) plus a chat panel (`TalosPanel`) tha | toga-blox/src/components/Talos/TalosLauncher.tsx, toga-blox/src/components/Talos/TalosPanel.tsx, toga-blox/src/components/Talos/TalosMessage.tsx, toga-blox/src/components/Talos/types.ts, toga-blox/src/components/Talos/theme.ts, toga-blox/src/components/Talos/helpers.tsx, toga-blox/src/components/Talos/stub.ts, toga-blox/src/components/Talos/Talos.module.css, toga-blox/src/components/Talos/index.ts, toga-blox/src/components/Talos/TalosPanel.test.tsx, toga-blox/src/components/index.ts, toga-blox/src/components/Talos/README.md |
|
|
14
|
+
| [Talos AI-Assistant Component (launcher + docked/drawer chat panel)](features/talos-assistant.md) | `Talos` is a **shared, pure-UI** AI-assistant component in `@agilant/toga-blox`: a header launcher button (`TalosLauncher`) plus a chat panel (`TalosPanel`) tha | toga-blox/src/components/Talos/TalosLauncher.tsx, toga-blox/src/components/Talos/TalosPanel.tsx, toga-blox/src/components/Talos/TalosMessage.tsx, toga-blox/src/components/Talos/types.ts, toga-blox/src/components/Talos/theme.ts, toga-blox/src/components/Talos/helpers.tsx, toga-blox/src/components/Talos/stub.ts, toga-blox/src/components/Talos/Talos.module.css, toga-blox/src/components/Talos/index.ts, toga-blox/src/components/Talos/TalosPanel.test.tsx, toga-blox/src/components/index.ts, toga-blox/src/components/Talos/README.md, toga-blox/src/components/TableRecordModal/TableRecordModal.tsx |
|
|
15
15
|
| [Toaster — host-token styling contract](features/toaster.md) | The blox `Toaster` is a CSS-Module component whose every visual property reads a `--toaster-*` custom property supplied by the **host app**. | toga-blox/src/components/Toaster/Toaster.module.css, toga-blox/src/components/Toaster/Toaster.tsx, toga-blox/src/components/Toaster/ToasterContext.tsx, toga2-commerce/src/styles/index.css, toga2-commerce/src/components/Toasters/ToasterList.tsx |
|
|
16
16
|
| [Dynamic npm Publish Pipeline (branch → channel)](workflows/dynamic-publish-pipeline.md) | How `@agilant/toga-blox` (checkout folder `toga-blox-npm`, registry repo key `toga-blox`) publishes a per-environment npm **channel** (dist-tag) from a `_<mode> | toga-blox/.github/workflows/publish.yml, toga-blox/package.json, toga-blox/src/utils/getFontAwesomeIcon.tsx |
|
|
17
17
|
| [Landing a Large Long-Lived Feature Branch (merge, never rebase)](workflows/landing-a-large-feature-branch.md) | The procedure for landing a long-lived, very large feature branch (months old, hundreds of commits) into `_production` in `toga-blox-npm`. | toga-blox/package.json, toga-blox/.github/workflows/publish.yml |
|
|
@@ -6,7 +6,7 @@ project: TOGa Blox
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
9
|
+
updated: 2026-09-02
|
|
10
10
|
owners: [apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- toga-blox/src/components/TableRecordModal/TableRecordModal.tsx
|
|
@@ -15,6 +15,8 @@ files:
|
|
|
15
15
|
related:
|
|
16
16
|
- ../architecture.md
|
|
17
17
|
- table.md
|
|
18
|
+
- talos-assistant.md
|
|
19
|
+
- ../../toga25-supply/features/talos-integration.md
|
|
18
20
|
---
|
|
19
21
|
|
|
20
22
|
## Summary
|
|
@@ -58,6 +60,29 @@ it opens the modal with `isOpen={!!selectedRow}` and renders the record inside `
|
|
|
58
60
|
(often using the same `tableViewFields` metadata to format fields). `utils/resolveModalType.tsx`
|
|
59
61
|
and `types.ts` are present but **empty/reserved** for a future field-type→renderer mapping.
|
|
60
62
|
|
|
63
|
+
## `data-blox-modal-open` — the root-element marker (2026-09-02)
|
|
64
|
+
|
|
65
|
+
While open, `TableRecordModal` sets **`data-blox-modal-open` on `document.documentElement`**. Other
|
|
66
|
+
blox CSS reacts to it — today the Talos launcher dims under `:root[data-blox-modal-open]` (see
|
|
67
|
+
[Talos assistant](talos-assistant.md)).
|
|
68
|
+
|
|
69
|
+
**Why an attribute on the root element and not a prop or context.** The things that must react to
|
|
70
|
+
"a modal is open" render **outside this component's subtree** — the Talos launcher lives in the app
|
|
71
|
+
**header**. No shared React state reaches it. Threading a prop down would have touched **every
|
|
72
|
+
modal layout in the consuming app**. This is the same boundary-crossing trick as the existing
|
|
73
|
+
`--talos-dock-width` custom property.
|
|
74
|
+
|
|
75
|
+
**It is a COUNTER, not a boolean.** Modals stack — a record modal can open a create modal — and the
|
|
76
|
+
marker must **survive the inner one closing**. So:
|
|
77
|
+
|
|
78
|
+
- Each instance holds a **`holdsModalMarker` ref**, so a re-render cannot double-count and a close
|
|
79
|
+
cannot decrement twice.
|
|
80
|
+
- The marker is cleared at **three** points: the open→false transition's **animation end**, an
|
|
81
|
+
**unmount** safety net, and the **count reaching 0**.
|
|
82
|
+
|
|
83
|
+
Anything else that reads the marker gets stacking correctness for free. (Note this fixes stacking
|
|
84
|
+
for the *marker* only — the body-overflow gotcha below is unchanged.)
|
|
85
|
+
|
|
61
86
|
## Gotchas
|
|
62
87
|
|
|
63
88
|
- **No portal** — renders inline in the React tree; a parent `overflow: hidden` can clip it.
|
|
@@ -66,4 +91,12 @@ and `types.ts` are present but **empty/reserved** for a future field-type→rend
|
|
|
66
91
|
- CSS-variable defaults are hardcoded fallbacks; set vars on the DOM before mount to change sizes.
|
|
67
92
|
|
|
68
93
|
## Change history
|
|
94
|
+
- 2026-09-02 — Added **`data-blox-modal-open` on `document.documentElement`** while a modal is open,
|
|
95
|
+
so chrome rendered **outside** the modal subtree can react (first consumer: the Talos launcher dims
|
|
96
|
+
under `:root[data-blox-modal-open]`). Chosen over a prop/context because the launcher lives in the
|
|
97
|
+
app **header** — no shared React state reaches it, and threading a prop would touch every modal
|
|
98
|
+
layout in the host. It is a **counter, not a boolean**, because modals stack and the marker must
|
|
99
|
+
survive the inner one closing; each instance holds a `holdsModalMarker` ref so a re-render cannot
|
|
100
|
+
double-count and a close cannot decrement twice, and the marker clears at three points (open→false
|
|
101
|
+
animation end, unmount safety net, count reaching 0). (apeterson)
|
|
69
102
|
- 2026-06-23 — Documented TableRecordModal as a generic modal shell: positions, render-prop children, body-scroll lock, and consumer-owned field rendering / a11y (apeterson).
|
|
@@ -21,7 +21,9 @@ files:
|
|
|
21
21
|
- toga-blox/src/components/Talos/TalosPanel.test.tsx
|
|
22
22
|
- toga-blox/src/components/index.ts
|
|
23
23
|
- toga-blox/src/components/Talos/README.md
|
|
24
|
+
- toga-blox/src/components/TableRecordModal/TableRecordModal.tsx
|
|
24
25
|
related:
|
|
26
|
+
- table-record-modal.md
|
|
25
27
|
- ../architecture.md
|
|
26
28
|
- ../workflows/dynamic-publish-pipeline.md
|
|
27
29
|
- ../workflows/local-link-into-a-consumer-app.md
|
|
@@ -254,9 +256,42 @@ threadsStatus?: "loading" | "error" | "ready";
|
|
|
254
256
|
`DEFAULT_SUGGESTIONS` — four hardcoded **TOGa Supply** questions — was **removed**. Tenant
|
|
255
257
|
business copy must not sit inside a library five apps consume: any host that mounted the panel
|
|
256
258
|
silently inherited Supply's prompts. `suggestions` now defaults to an **empty module-level
|
|
257
|
-
constant**, and the host supplies the chips (supply reads them from the surface layer
|
|
259
|
+
constant**, and the host supplies the chips (supply reads them from the surface layer as **one
|
|
260
|
+
authored, ordered set per tenant** — see
|
|
258
261
|
[Talos integration](../../toga25-supply/features/talos-integration.md)).
|
|
259
262
|
|
|
263
|
+
### The launcher is DISABLED under an open modal — and the cause was NOT z-index (2026-09-02)
|
|
264
|
+
|
|
265
|
+
The launcher stayed bright and looked clickable while a record modal was open. The obvious diagnosis
|
|
266
|
+
(and the developer's first guess) was z-index. **It was wrong.** Checked, not assumed:
|
|
267
|
+
|
|
268
|
+
- `.launcher` has **no `z-index`** at all.
|
|
269
|
+
- blox `.header` has **no `z-index` and no `position`**; supply's `.headerActions` has neither.
|
|
270
|
+
- The modal `.backdrop` is `position: fixed; z-index: 40`.
|
|
271
|
+
|
|
272
|
+
So the launcher was **already painted under the backdrop and its clicks were already being
|
|
273
|
+
swallowed by it.** The real cause is purely visual: `.backdrop-right` / `.backdrop-left` is only
|
|
274
|
+
`rgba(0, 0, 0, 0.2)`, and a 20% black wash over a **white** button still reads as active next to
|
|
275
|
+
dimmed header chrome.
|
|
276
|
+
|
|
277
|
+
**Fix — a real disabled state, not a z-index change.** `TableRecordModal` sets
|
|
278
|
+
**`data-blox-modal-open` on `document.documentElement`**, and `Talos.module.css` dims the launcher
|
|
279
|
+
under `:root[data-blox-modal-open]`: `opacity: .5`, `filter: grayscale(1)`,
|
|
280
|
+
`pointer-events: none`, plus **stopping the `.launcher::before` orbit animation** (a spinning ring
|
|
281
|
+
on a greyed-out button still reads as live). Marker mechanics and why it is a **counter**:
|
|
282
|
+
[TableRecordModal](table-record-modal.md).
|
|
283
|
+
|
|
284
|
+
This applies to **every** `TableRecordModal` in a host app automatically.
|
|
285
|
+
|
|
286
|
+
🚨 **Known gap, left unfixed.** The launcher is still **keyboard-reachable** behind a modal —
|
|
287
|
+
`pointer-events: none` stops the **mouse only**. Supply's header takes `inert` for the side nav but
|
|
288
|
+
not for modals, and closing that is a **host** change affecting all header controls, so it was
|
|
289
|
+
flagged to the developer rather than patched here.
|
|
290
|
+
|
|
291
|
+
**Reusable lesson:** before reaching for z-index, read the actual computed stack. "Looks clickable"
|
|
292
|
+
and "is clickable" are different bugs, and a translucent scrim is a *contrast* problem, not a
|
|
293
|
+
*stacking* one.
|
|
294
|
+
|
|
260
295
|
### Tests (first ever for this component)
|
|
261
296
|
|
|
262
297
|
`TalosPanel.test.tsx` — **31 Vitest + RTL Talos tests** as of 2026-09-02 (8 at inception), all
|
|
@@ -324,6 +359,20 @@ Rollup *"failed to resolve import"* for a component they never referenced). blox
|
|
|
324
359
|
currently consumes it via a local symlink.
|
|
325
360
|
|
|
326
361
|
## Change history
|
|
362
|
+
- 2026-09-02 — **FIXED the launcher staying bright and clickable-looking under an open record
|
|
363
|
+
modal — and the cause was NOT z-index.** `.launcher` has no `z-index`, blox `.header` has no
|
|
364
|
+
`z-index`/`position`, and the modal `.backdrop` is `fixed; z-index: 40`, so the launcher was
|
|
365
|
+
**already** behind the backdrop with its clicks **already** swallowed. The real cause was contrast:
|
|
366
|
+
`.backdrop-right`/`-left` is only `rgba(0,0,0,0.2)` and a 20% wash over a white button still reads
|
|
367
|
+
as active. Fix is a real disabled state — `TableRecordModal` sets **`data-blox-modal-open` on
|
|
368
|
+
`document.documentElement`** (a **counter**, since modals stack) and `Talos.module.css` applies
|
|
369
|
+
`opacity: .5` / `grayscale(1)` / `pointer-events: none` and **stops the `.launcher::before` orbit
|
|
370
|
+
animation** under `:root[data-blox-modal-open]`. A root attribute rather than a prop because the
|
|
371
|
+
launcher renders in the host **header**, outside the modal subtree — the same trick as
|
|
372
|
+
`--talos-dock-width`. Applies to every `TableRecordModal` automatically. **Known gap flagged, not
|
|
373
|
+
fixed:** the launcher is still **keyboard**-reachable behind a modal; `pointer-events: none` stops
|
|
374
|
+
the mouse only, and adding `inert` is a host-header change. Suite at **31 Talos + TableRecordModal
|
|
375
|
+
tests**; blox `dist/` rebuilt. (apeterson)
|
|
327
376
|
- 2026-09-02 — **FIXED the `renderMessages` slot silently killing the in-flight loading UI**: the
|
|
328
377
|
bubble is synthesized from `isStreaming`/`progress` into the panel's internal `msgs` array, and the
|
|
329
378
|
host-render branch replaced that whole array, so a run showed **no feedback between submit and
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
| [NYCHH inventory-adjustment → item-fulfillment linking (direct FK columns, REST)](features/netsuite-inventory-adjustment-fulfillment-link.md) | 1.0 | For NYCHH stock adjustments, the NetSuite **inventory adjustment** carries a link to the **Item Fulfillment** it corrects, on the multi-select body custom field | library/app/api/toga2.php, library/app/api/netsuite/rest.php, worker/crons/toga2/netsuite/common_sync_togasupply.php, worker/crons/toga2/netsuite/sync_togasupply_hh.php, worker/crons/toga2/netsuite/diagnose_hh_import_inventory_adjustment.php |
|
|
6
6
|
| [NYCHH NetSuite → TransferOrders import (stocking-flag routing, PO bridges, origin location)](features/netsuite-transfer-order-import.md) | 1.0 | NYCHH's NetSuite **transfer orders are represented as NetSuite sales orders** (same as the GroWrk pattern), so the shared NetSuite → TOGa Supply importer (`App_ | library/app/api/toga2.php, library/app/api/netsuite/rest.php, library/app/netsuite.php, worker/crons/toga2/netsuite/sync_togasupply_hh.php, worker/crons/toga2/netsuite/common_sync_togasupply.php, worker/crons/toga2/netsuite/diagnose_hh_stuck_transfer_order.php, dbchanges2/Core/2026-08-27a - TransferOrderUuidSearchableIdentifier.sql, dbchanges2/Client/2026-08-28a - TransferOrderItemsTimestampColumns.sql, dbchanges2/Client/2026-08-28b - TransferOrderItemsTimestampColumnsReposition.sql, dbchanges2/Client/2026-08-29 - ItemReceiptTransferOrderIdFieldPermission.sql, dbchanges2/Client/2026-08-29b - ItemReceiptItemTransferOrderItemIdFieldPermission.sql |
|
|
7
7
|
| [NYCHH PO links are UPSTREAM — the downstream SO→PO route returns empty](features/po-number-upstream-direction.md) | 2.0 | NYCHH's sales orders are created **from the customer's purchase order**, so their SO↔PO links live in the **upstream** table `PurchaseOrders_SalesOrders` (route | _underscore/Model/Client/SalesOrder.php, _underscore/Trait/Netsuite/SalesOrder.php, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/hooks/usePurchaseOrderDetails.ts, dbchanges2/Client/2026-08-11b - SalesOrderPurchaseOrdersField.sql, dbchanges2/Client/2026-08-25 - SalesOrderPurchaseOrdersFieldAllClients.sql |
|
|
8
|
-
| [NYCHH Talos AI Assistant Enablement (the only granted tenant)](features/talos-assistant-enablement.md) | 2.0 | **NYCHH is the only tenant granted the Talos AI assistant in TOGa 2.5 Supply.** The feature is seeded **OFF in Core
|
|
8
|
+
| [NYCHH Talos AI Assistant Enablement (the only granted tenant)](features/talos-assistant-enablement.md) | 2.0 | **NYCHH is the only tenant granted the Talos AI assistant in TOGa 2.5 Supply, and it AUTHORS ITS OWN suggestion questions.** The feature is seeded **OFF in Core | dbchanges2/Core/2026-09-02a - TalosAssistantSurfaceSeed.sql, dbchanges2/Client_Nychh/2026-09-02a - TalosAssistantEnable.sql, toga25-supply/src/hooks/useTalosSurface.ts, toga25-supply/src/hooks/useTalosSurface.test.ts, toga25-supply/src/providers/TalosStreamProvider.tsx, toga25-supply/db-migrations/PLAYBOOK.md |
|
|
9
9
|
| [NYCHH transfer-order 2.0 model — inventory quantities + V2 field enablement](features/transfer-order-inventory-quantities.md) | 2.0 | The 2.0 (`_underscore`) side of NYCHH transfer-order support: a **two-branch inventory quantity model** on the NYCHH `Item` override, plus the **client-override | _underscore/Model/Nychh/Item.php, _underscore/Model/Nychh/PurchaseOrderItem.php, _underscore/Model/Nychh/TransferOrder.php, _underscore/Model/Nychh/TransferOrderStage.php, _underscore/Model/Client/TransferOrder.php, _underscore/Model/Client/TransferOrderItem.php, dbchanges2/Client_Nychh/2026-08-27a - TransferOrderCustomFieldWritePermission.sql, dbchanges2/Client_Nychh/2026-08-27b - TransferOrderStageStatusIdentifier.sql, dbchanges2/Client_Nychh/2026-08-28c - TransferOrderRecordAcl.sql, dbchanges2/Client/2026-08-28b - TransferOrderItemsTimestamps.sql, dbchanges2/Client/2026-09-01a - PurchaseOrderItemQtyFieldsApiRoleRead.sql, _underscore/Model/Client/PurchaseOrderItem.php |
|
|
10
10
|
| [NYCHH TransferOrder → NetSuite push (location roles, interceptor row 312, metadata state)](features/transfer-order-netsuite-push.md) | 2.0 | NYCHH is the **first and only** client on the outbound transfer-order push. | _underscore/Model/Client/TransferOrder.php, worker2/Worker/Netsuite/SalesOrder.php, dbchanges2/Client_Nychh/2026-09-02a - TransferOrderNetsuitePushInterceptor.sql |
|
|
11
11
|
| [NYC Health & Hospitals](profile.md) | 2.0 | NYC Health & Hospitals (NYCHH) is a TOGA 2.0 client on the `_underscore` platform, prod schema `Client_Nychh`. | dbchanges2/Client_Nychh/2026-09-02a - TransferOrderNetsuitePushInterceptor.sql, dbchanges2/Client_Nychh/2026-08-31a - PurchaseOrdersTableViewRebase.sql, dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql, dbchanges2/Client_Nychh/2026-08-28b - TransferOrdersNavigationEnable.sql, dbchanges2/Client_Nychh/2026-08-28c - TransferOrderRecordAcl.sql, dbchanges2/Client/2026-08-28b - TransferOrderItemsTimestamps.sql, dbchanges2/Client/2026-09-01a - PurchaseOrderItemQtyFieldsApiRoleRead.sql, dbchanges2/Client_Nychh/2026-09-02a - TalosAssistantEnable.sql |
|
|
@@ -12,6 +12,7 @@ files:
|
|
|
12
12
|
- dbchanges2/Core/2026-09-02a - TalosAssistantSurfaceSeed.sql
|
|
13
13
|
- dbchanges2/Client_Nychh/2026-09-02a - TalosAssistantEnable.sql
|
|
14
14
|
- toga25-supply/src/hooks/useTalosSurface.ts
|
|
15
|
+
- toga25-supply/src/hooks/useTalosSurface.test.ts
|
|
15
16
|
- toga25-supply/src/providers/TalosStreamProvider.tsx
|
|
16
17
|
- toga25-supply/db-migrations/PLAYBOOK.md
|
|
17
18
|
related:
|
|
@@ -24,21 +25,26 @@ related:
|
|
|
24
25
|
|
|
25
26
|
## Summary
|
|
26
27
|
|
|
27
|
-
**NYCHH is the only tenant granted the Talos AI assistant in TOGa 2.5 Supply
|
|
28
|
-
seeded **OFF in Core for every client** and turned on
|
|
29
|
-
the `talos-assistant` surface. Developer instruction,
|
|
30
|
-
it toggled off. and then we will toggle it on
|
|
28
|
+
**NYCHH is the only tenant granted the Talos AI assistant in TOGa 2.5 Supply, and it AUTHORS ITS
|
|
29
|
+
OWN suggestion questions.** The feature is seeded **OFF in Core for every client** and turned on
|
|
30
|
+
per tenant with `SurfaceOverrides` rows on the `talos-assistant` surface. Developer instruction,
|
|
31
|
+
verbatim: *"in core all clients should have it toggled off. and then we will toggle it on
|
|
32
|
+
specifically for nychh in supply."*
|
|
31
33
|
|
|
32
|
-
Everything shared — the surface, the elements, the blox panel, the supply provider — is
|
|
33
|
-
tenant-neutral. Only
|
|
34
|
+
Everything shared — the surface, the two elements, the blox panel, the supply provider — is
|
|
35
|
+
tenant-neutral. Only NYCHH's **three** override rows are NYCHH's.
|
|
34
36
|
|
|
35
37
|
## How it works
|
|
36
38
|
|
|
37
|
-
1. **Core** (`Core/2026-09-02a`) seeds surface `talos-assistant` (type `DRAWER`, not
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
1. **Core** (`Core/2026-09-02a`) seeds surface `talos-assistant` (type `DRAWER`, not record-bound)
|
|
40
|
+
with **two** elements, both `isVisible = 0`:
|
|
41
|
+
- `config.role='featureEnabled'`, `config.key='feature'` — the master switch.
|
|
42
|
+
- `config.role='suggestion'`, `config.key='suggestions'` — **the whole chip row in one element**,
|
|
43
|
+
its questions in `config.items` (an ordered array of `{label, prompt, icon}`).
|
|
44
|
+
2. **NYCHH** (`Client_Nychh/2026-09-02a`) inserts **three rows**:
|
|
45
|
+
- `IS_VISIBLE = '1'` on `feature`
|
|
46
|
+
- `IS_VISIBLE = '1'` on `suggestions`
|
|
47
|
+
- a **`CONFIG` override** on `suggestions` carrying **NYCHH's own three questions**.
|
|
42
48
|
3. The supply FE reads the marker via `useTalosSurface()` and **fails closed** — no bundle, failed
|
|
43
49
|
fetch, missing marker, or still-loading all mean disabled. `TalosStreamProvider`'s `enabled`
|
|
44
50
|
prop means an ungranted tenant never even calls Aegra's `/assistants`.
|
|
@@ -47,6 +53,53 @@ Mechanism and seeding rules:
|
|
|
47
53
|
[surface-layer-schema](../../../2.0/apps/dbchanges2/features/surface-layer-schema.md).
|
|
48
54
|
FE wiring: [Talos integration](../../../2.0/apps/toga25-supply/features/talos-integration.md).
|
|
49
55
|
|
|
56
|
+
## NYCHH's three questions — it does NOT inherit Core's default
|
|
57
|
+
|
|
58
|
+
| Label | Icon |
|
|
59
|
+
|---|---|
|
|
60
|
+
| How many orders have been placed in the last year? | `lock` |
|
|
61
|
+
| Show me orders pending fulfillment | `truck` |
|
|
62
|
+
| How many orders are in each status? | `chartSimple` |
|
|
63
|
+
|
|
64
|
+
Developer instruction, verbatim: *"now for nychh, i need the array to be this instead: …"*. NYCHH's
|
|
65
|
+
`CONFIG` override **replaces** Core's default set outright.
|
|
66
|
+
|
|
67
|
+
`icon` is a **literal FontAwesome name**, and `label` is a **raw string, not a `Messages` key** —
|
|
68
|
+
so `MessageTranslations` cannot translate these. That trade is recorded in the schema doc.
|
|
69
|
+
|
|
70
|
+
### 🚨 The override MUST restate `"role":"suggestion"`
|
|
71
|
+
|
|
72
|
+
A `CONFIG` override **replaces `config` wholesale — it does not merge** (`_underscore
|
|
73
|
+
Model/Core/Surface.php:839` assigns the decoded JSON over `$config`; there is no `array_merge`).
|
|
74
|
+
Send only `items` and `config.role` is **wiped**, the element stops matching in the frontend, and
|
|
75
|
+
**the chips silently disappear with no error anywhere**. A bare top-level JSON array also passes
|
|
76
|
+
that check, which is why it is the tempting wrong move.
|
|
77
|
+
|
|
78
|
+
The JSON goes in **`c_longValue`, never `value`** — `value` is `varchar(255)` and any real chip set
|
|
79
|
+
overflows it.
|
|
80
|
+
|
|
81
|
+
**That is why the verify query asserts the role survived, not just that the row exists:**
|
|
82
|
+
|
|
83
|
+
```sql
|
|
84
|
+
JSON_UNQUOTE(JSON_EXTRACT(o.c_longValue, '$.role')) -- must be non-NULL
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Changing NYCHH's chips later
|
|
88
|
+
|
|
89
|
+
The file carries a `CHANGING NYCHH'S CHIPS LATER` block with two recipes:
|
|
90
|
+
|
|
91
|
+
- **Reword / add / reorder a chip** → `UPDATE` the `CONFIG` row's `c_longValue`. Order is **array
|
|
92
|
+
order**; there is no per-chip `sortOrder`. No Core deploy.
|
|
93
|
+
- **Fall back to Core's default set** → **`DELETE` the `CONFIG` row.** Do **not** write an empty
|
|
94
|
+
`items` array — that renders an **empty chip row**, not the default.
|
|
95
|
+
|
|
96
|
+
### Section shape (prod cannot cross clusters)
|
|
97
|
+
|
|
98
|
+
Section **A2** is the single-cluster form (local/beta). Section **C2** is the prod literal-id form,
|
|
99
|
+
because Core and `Client_*` are on **separate clusters** in production. Section B reads the element
|
|
100
|
+
ids off the Core cluster first. Full three-section rule:
|
|
101
|
+
[surface-layer-schema](../../../2.0/apps/dbchanges2/features/surface-layer-schema.md).
|
|
102
|
+
|
|
50
103
|
## The grants are CLIENT-WIDE — no role scoping
|
|
51
104
|
|
|
52
105
|
`roleId` / `personaId` / `languageId` are **NULL**, so **every NYCHH user, including internal
|
|
@@ -55,6 +108,22 @@ grants navigation (NYCHH does not scope navigation by role). **Per-role gating w
|
|
|
55
108
|
it is ever needed, the grants have to be widened/narrowed at the *same* tier (see the shadowing rule
|
|
56
109
|
in the schema doc).
|
|
57
110
|
|
|
111
|
+
⚠ Note for whoever *does* scope it: chip **sets** are scopable, individual chips are not, and two
|
|
112
|
+
role-scoped `CONFIG` rows resolve by `ORDER BY (roleId IS NULL) DESC, (personaId IS NULL) DESC,
|
|
113
|
+
id ASC` — for a user holding both roles the **higher id simply wins**. The `feature` marker is a
|
|
114
|
+
plain boolean grant precisely so *access* keeps the clean grant-only rules.
|
|
115
|
+
|
|
116
|
+
## Teardown — order matters
|
|
117
|
+
|
|
118
|
+
Both SQL files carry a commented `TEARDOWN`. Run it in this order:
|
|
119
|
+
|
|
120
|
+
1. `DELETE` the `Client_Nychh.SurfaceOverrides` rows.
|
|
121
|
+
2. `DELETE` the Core `SurfaceElements` rows.
|
|
122
|
+
3. `DELETE` the `Surfaces` row.
|
|
123
|
+
|
|
124
|
+
Reverse it and the grants point at element ids that no longer exist. The `talos.feature.name`
|
|
125
|
+
`Message` is **left behind on purpose** — harmless, and re-used on a re-run.
|
|
126
|
+
|
|
58
127
|
## Aegra side
|
|
59
128
|
|
|
60
129
|
- **`assistant_id` `c7981164-1fe9-5878-b115-85c38dadad43`** — name `TOGa Supply`,
|
|
@@ -70,24 +139,39 @@ in the schema doc).
|
|
|
70
139
|
|
|
71
140
|
## Run state — 🚨 beta and prod are NOT done
|
|
72
141
|
|
|
73
|
-
Verified on **local only** (2026-09-02, developer ran the SQL
|
|
142
|
+
Verified on **local only** (2026-09-02, developer ran the SQL; the full teardown + re-run worked end
|
|
143
|
+
to end and NYCHH's three chips render):
|
|
74
144
|
|
|
75
145
|
- `navigation` surface = **id 39**, `appId` **1**.
|
|
76
|
-
-
|
|
77
|
-
|
|
78
|
-
labels non-NULL.
|
|
79
|
-
- `Client_Nychh` grants: **5 rows, all `IS_VISIBLE = '1'` on 216–220**.
|
|
146
|
+
- `Client_Nychh` overrides: **3 rows** — `IS_VISIBLE='1'` on `feature` and `suggestions`, plus the
|
|
147
|
+
`CONFIG` row carrying NYCHH's three items.
|
|
80
148
|
- **Beta and production: NOT YET RUN.**
|
|
81
149
|
|
|
82
|
-
**
|
|
83
|
-
|
|
84
|
-
|
|
150
|
+
**Do NOT copy any element id from this doc or from a teammate's local DB.** Element ids are
|
|
151
|
+
`AUTO_INCREMENT` and therefore **per-environment**. The first attempt of this feature consumed
|
|
152
|
+
`SurfaceElements` **216–220** under the old per-chip shape; those were torn down and re-created under
|
|
153
|
+
the two-element shape, so local ids advanced **again**. That is exactly why the client grant file's
|
|
154
|
+
Section B reads the ids off the Core cluster at run time.
|
|
85
155
|
|
|
86
156
|
## Change history
|
|
87
|
-
- 2026-09-02 —
|
|
88
|
-
|
|
89
|
-
`
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
157
|
+
- 2026-09-02 — **CORRECTED to the final shape (the per-chip design recorded earlier is
|
|
158
|
+
superseded).** NYCHH now writes **three** rows, not five: `IS_VISIBLE='1'` on the `feature` and
|
|
159
|
+
`suggestions` elements plus **one `CONFIG` override authoring NYCHH's own three questions** ("How
|
|
160
|
+
many orders have been placed in the last year?" / lock, "Show me orders pending fulfillment" /
|
|
161
|
+
truck, "How many orders are in each status?" / chartSimple). Core seeds **two** elements — the
|
|
162
|
+
`featureEnabled` marker and **one** `suggestion` element whose `config.items` is an ordered array
|
|
163
|
+
of `{label, prompt, icon}` — replacing the five-element, one-chip-per-element first cut, which
|
|
164
|
+
meant only **Core** could author a tenant's wording. 🚨 The override **must restate
|
|
165
|
+
`"role":"suggestion"`**: a `CONFIG` override replaces `config` wholesale (`Surface.php:839`, no
|
|
166
|
+
merge), so omitting it wipes the role and the chips **silently vanish** — hence the verify query
|
|
167
|
+
now asserts `JSON_EXTRACT(c_longValue,'$.role')` is non-NULL, and the JSON lives in `c_longValue`
|
|
168
|
+
(not the varchar(255) `value`). Added a `CHANGING NYCHH'S CHIPS LATER` block (`UPDATE` to reword,
|
|
169
|
+
`DELETE` to fall back to Core's default — **never** an empty `items` array, which renders an empty
|
|
170
|
+
row) and a commented **TEARDOWN** whose order is load-bearing (client `SurfaceOverrides` → Core
|
|
171
|
+
`SurfaceElements` → `Surfaces`). Chip labels are raw strings, so `MessageTranslations` cannot
|
|
172
|
+
translate them; chip **sets** are scopable but individual chips are not, and a multi-role user
|
|
173
|
+
resolves arbitrarily (higher id wins) — which is why the `feature` marker stays a plain boolean
|
|
174
|
+
grant. Re-verified on **local only** after a full teardown + re-run; element ids advanced again and
|
|
175
|
+
remain per-environment, so prod must read them off Core in Section B. **Beta and prod still not
|
|
176
|
+
run.** Recorded the NYCHH `assistant_id` and that thread auto-titles are broken **server-side** on
|
|
177
|
+
that assistant, not in supply. (apeterson)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: session
|
|
3
|
+
slug: transfer-order-create-modal
|
|
4
|
+
title: Create Transfer Order modal — single-POST create + design-matched UI
|
|
5
|
+
author: apeterson
|
|
6
|
+
repos: [toga25-supply, _underscore, dbchanges2, api2]
|
|
7
|
+
framework: "2.0"
|
|
8
|
+
client: nychh
|
|
9
|
+
status: active
|
|
10
|
+
created: 2026-09-02
|
|
11
|
+
updated: 2026-09-02
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Session: transfer-order-create-modal
|
|
15
|
+
**Date:** 2026-09-02
|
|
16
|
+
**Project/Repo:** toga25-supply (+ _underscore, dbchanges2, api2) — 2.0
|
|
17
|
+
**Task:** Build the Create Transfer Order modal for NYCHH end to end — one atomic POST, the three new `TransferOrders` columns behind it, and the picker/dropdown UI matched to the Claude Design mockup.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What WORKED
|
|
22
|
+
|
|
23
|
+
- **Single POST create.** `useCreateTransferOrder.ts` now posts header + lines in one request to `/transfer-orders`, lines nested under `transferOrderItems`. Verified against the engine, not guessed: `api2/Component/Api/V2/V2.php:3248` converts the inherent child's `route` kebab→camel, and `:5241` uses the SAME lookup on the CREATE path (`$childrenToCreate[$key] = $val`). Jeff's nesting row exists — `InherentRecordChildren` id 152, parent record 312 → child 313, route `transfer-order-items` (confirmed by query).
|
|
24
|
+
- **Three new columns.** `_underscore/Model/Client/TransferOrder.php` has `contactId` (FK Contacts), `createdByUserId` (FK Users), `description` (varchar 255). Migrations written and guarded with `INFORMATION_SCHEMA` checks.
|
|
25
|
+
- **Core ids verified against production before use.** `Records` MAX(id) = 358; RecordFields 2561–2563 free. Handoff for the team: next `Records.id` = 359, next `RecordFields.id` = 2564.
|
|
26
|
+
- **TransferOrderNotes tables + metadata ran clean.** `Client/2026-09-01b` and `Core/2026-09-01c` are applied (Records 357/358, RecordFields 2550–2560). Both tables ship empty. NOTE: now unused — see Decisions.
|
|
27
|
+
- **Target Location picker.** `SelectTargetLocationModal.tsx` — flat list, 250 ms debounced search, breadcrumb path built from `parentLocation.uuid` with a cycle guard.
|
|
28
|
+
- **Contact scoping.** Contacts come from `Contacts` through the `Contacts_Locations` junction, scoped to the chosen location (`useLocationContacts.ts`).
|
|
29
|
+
- **One select control for the whole modal.** New app-local `PanelSelect.tsx` — 38px trigger, search box inside the panel, green check on the chosen row, optional pinned footer, optional clear (×). `ContactSelect.tsx` is now a thin mapping over it. The PO filter uses it at 200px with "All POs" as a row in the list. Matches the mockup's `window.FormSelect` / `FilterLockSelect`.
|
|
30
|
+
- **"Show more" on the item cell.** `TransferItemPickerTable.tsx`, rules copied from blox `PrimaryTableBodyCell`: offered only when text is really clipped (measured on hover), collapsed visibility is CSS `group-hover` not state, expanded wraps above a "Show less" toggle and grows the row (body cells align top), toggle `stopPropagation`s so it never checks the row. Cells cap at 300px so clipping can happen at all in an auto-layout table. Items table max height 355px.
|
|
31
|
+
- **Blank Item column fixed.** Label chain is `item.title || item.description || "(untitled item)"`, and `vendorItem.item.description` was added to the requested fields.
|
|
32
|
+
- **Verification each time:** `npx tsc --noEmit` exits 0; `npx eslint src/pages/TransferOrders/view/CreateTransferOrderModal` stays at the same 8 pre-existing errors (2 `set-state-in-effect`, 1 `react-hooks/refs`, 4 `no-explicit-any`, 1 `react-refresh/only-export-components`). Baseline was established with `git stash`, so "zero new errors" is measured, not assumed.
|
|
33
|
+
|
|
34
|
+
## What did NOT work — DO NOT RETRY THESE
|
|
35
|
+
|
|
36
|
+
- **Three sequential POSTs to create a transfer.** Abandoned: it can leave a half-written transfer behind. The inherent-child single POST is one API transaction, which the front controller commits on success and rolls back on failure.
|
|
37
|
+
- **A scripted API endpoint for transfer create.** Not needed once the inherent child works. Developer decided no.
|
|
38
|
+
- **`useCallback` around the modal's `submit`.** React Compiler bailed with "Compilation Skipped: Existing memoization could not be preserved." Fixed by making `submit` a plain function. Do not wrap it again.
|
|
39
|
+
- **A `useEffect` that called `close()` when the select went disabled.** Tripped `react-hooks/set-state-in-effect`. Replaced with derived state: `const isPanelOpen = isOpen && !disabled;`.
|
|
40
|
+
- **Bare FK column names in the `fields` option.** I wrote `parentLocationId` and it returned nothing. This repo uses dotted paths — `parentLocation.uuid`, `vendorItem.item.title` — and FKs POST as nested `{ uuid }` objects.
|
|
41
|
+
- **A native `<select>` for the PO filter.** Looked like a different control next to the custom contact select. The mockup draws both with the same `FormSelect`.
|
|
42
|
+
- **Falling back to a part number for the item label.** Part Number already has its own column, so it duplicates a cell instead of naming the item.
|
|
43
|
+
- **`Locations.primaryContactId` as a default-contact FK.** Developer rejected it: `Contacts_Locations` is the right place.
|
|
44
|
+
- **A unique index on `Contacts_Locations (locationId, type)`.** Wrong — it is many-to-many, many contacts per location. Only `isPrimary` is viable.
|
|
45
|
+
- **My `_qty*` diagnosis "no ItemReceiptItems exist, it's data."** Wrong. The developer's query returned `216 | 80622 | 3270.00 | 27 | 3270.00` — receipts do exist. The seed-the-receipts plan built on that was also scrapped.
|
|
46
|
+
- **`AUTO_INCREMENT` / repo-derived ids for `Records` / `RecordFields`.** Never do this. They are the only two tables platform-wide with team-assigned ids; ask the developer, and the repo lags production.
|
|
47
|
+
- **Python heredoc edits that assume indentation depth.** Failed twice (`AssertionError: ('type', 0)`) — assumed 4 tabs where it was 3, and 10 where it was 11. Print `repr()` first or slice by index. The asserts fire before the write, so no file was corrupted.
|
|
48
|
+
|
|
49
|
+
## Not tried yet (candidates for next session)
|
|
50
|
+
|
|
51
|
+
- A live POST of the create flow. **Nothing in this modal has been sent to a real API yet.** Blocked on the two pending migrations + the `_underscore` deploy.
|
|
52
|
+
- Setting `transferOrderStageId` on create — unknown which stage row NYCHH seeds as the opening one.
|
|
53
|
+
- Minting `TransferOrders.number`. Deliberately not done client-side: two concurrent creates would race. Needs a server-side owner.
|
|
54
|
+
- Stamping `createdByUserId` from the JWT server-side instead of from the browser's `user` localStorage key.
|
|
55
|
+
- Dropping the now-unused `TransferOrderNotes` / `TransferOrderNoteTypes` tables and their Core metadata (Records 357/358, RecordFields 2550–2560).
|
|
56
|
+
- Adding the ACL grant for NYCHH on records 357/358 — currently missing (only needed if the notes tables stay).
|
|
57
|
+
- Adding the magnifier icon inside the item search box (the mockup has one on the left; ours has none).
|
|
58
|
+
- Populating `Items.title` for NYCHH — the real fix behind the description fallback.
|
|
59
|
+
|
|
60
|
+
## Current file state
|
|
61
|
+
|
|
62
|
+
| File | Status | Notes |
|
|
63
|
+
|------|--------|-------|
|
|
64
|
+
| `toga25-supply/.../CreateTransferOrderModal/hooks/useCreateTransferOrder.ts` | Modified | Single POST; exports `DESCRIPTION_MAX_LENGTH = 255`; omits `number` on purpose |
|
|
65
|
+
| `toga25-supply/.../hooks/usePurchaseOrderItemRows.ts` | Modified | `item.description` fallback; `VITE_TRANSFER_IGNORE_AVAILABILITY` escape hatch |
|
|
66
|
+
| `toga25-supply/.../hooks/useTargetLocationOptions.ts` | Modified | `parentLocation.uuid` dotted path; breadcrumb path + cycle guard |
|
|
67
|
+
| `toga25-supply/.../hooks/useLocationContacts.ts` | Modified | Contacts via `Contacts_Locations`, scoped to the location |
|
|
68
|
+
| `toga25-supply/.../hooks/useCreateLocationContact.ts` | Modified | Inline add-contact |
|
|
69
|
+
| `toga25-supply/.../view/SelectTargetLocationModal.tsx` | Created | Flat picker, debounced search, 720px card |
|
|
70
|
+
| `toga25-supply/.../view/PanelSelect.tsx` | Created | The one select control; `// TODO(blox): promote once stable` |
|
|
71
|
+
| `toga25-supply/.../view/ContactSelect.tsx` | Rewritten | Now a thin wrapper over `PanelSelect` |
|
|
72
|
+
| `toga25-supply/.../view/TransferItemPickerTable.tsx` | Modified | 355px max height, column lines, `ExpandableText` show-more, `align-top` cells |
|
|
73
|
+
| `toga25-supply/.../view/TransferNotesField.tsx` | Modified | Optional `maxLength`, wired to 255 |
|
|
74
|
+
| `toga25-supply/.../CreateTransferOrderModal.tsx` | Modified | `PanelSelect` for PO (200px, "All POs" row), plain `submit`, inline error |
|
|
75
|
+
| `_underscore/Model/Client/TransferOrder.php` | Modified | `contactId`, `createdByUserId`, `description` — **not deployed** |
|
|
76
|
+
| `_underscore/Model/Client/TransferOrderNote.php` | Created | Mirrors `PurchaseOrderNote` — currently unused |
|
|
77
|
+
| `_underscore/Model/Client/TransferOrderNoteType.php` | Created | Mirrors `PurchaseOrderNoteType` — currently unused |
|
|
78
|
+
| `dbchanges2/Client/2026-09-01b - TransferOrderNotesTables.sql` | Applied | Ran |
|
|
79
|
+
| `dbchanges2/Core/2026-09-01c - TransferOrderNotesRecords.sql` | Applied | Ran — Records 357/358, RecordFields 2550–2560 |
|
|
80
|
+
| `dbchanges2/Client/2026-09-01c - TransferOrderContactCreatedByAndDescription.sql` | **Not run** | 7 `INFORMATION_SCHEMA`-guarded sections; run on every client DB |
|
|
81
|
+
| `dbchanges2/Core/2026-09-01d - TransferOrderContactCreatedByAndDescriptionRecordFields.sql` | **Not run** | RecordFields 2561–2563 on record 312 + ACL roles 1 and 3 |
|
|
82
|
+
|
|
83
|
+
All application-repo changes sit uncommitted in the working tree on branch `features-talos-transferorders`. Nothing was committed or pushed.
|
|
84
|
+
|
|
85
|
+
## Decisions made
|
|
86
|
+
|
|
87
|
+
- **One POST, not a scripted endpoint.** The inherent child gives the same all-or-nothing write, so a custom endpoint buys nothing. Rejected: three sequential POSTs (can half-write), a scripted API method.
|
|
88
|
+
- **The modal's Notes box writes `TransferOrders.description`, not a note row.** A transfer carries one free-text description, not a thread of typed notes from different authors. Consequence: `TransferOrderNotes` / `TransferOrderNoteTypes` are now unused even though they are already migrated. Rejected: posting a `TransferOrderNotes` row per create.
|
|
89
|
+
- **`createdByUserId` is client-supplied** (read from the `user` localStorage key), matching the SalesOrders precedent. It is only as trustworthy as this client — still open for Jeff. Rejected for now: JWT-stamped server-side.
|
|
90
|
+
- **`number` is left NULL.** Minting max+1 from the browser races two concurrent creates. Rejected: client-side minting.
|
|
91
|
+
- **The contact list lives in `Contacts_Locations`,** not a `Locations` FK — the developer's call. Many contacts per location, so only `isPrimary` can mark a default.
|
|
92
|
+
- **`PanelSelect` is app-local, not blox.** Front-end standard §21: build it here, promote after a second consumer. blox's `AdvancedSelect` has `renderOption` but no footer slot, and a sentinel row inside `data` gets filtered out by the very search that makes you need it.
|
|
93
|
+
- **Grid geometry stays in the front end.** Cell max width, table max height and column lines are presentation, not surface metadata.
|
|
94
|
+
- **`VITE_TRANSFER_IGNORE_AVAILABILITY` is local-only.** It disables the guard that stops a transfer asking for more than can be dispatched. **Never set it in a deployed environment.**
|
|
95
|
+
|
|
96
|
+
## Blockers
|
|
97
|
+
|
|
98
|
+
- **`_qty*` returns 0 for every NYCHH PO line.** For PurchaseOrderItem `715ef031-003d-6742-871d-0d20de2fa40f` (PO 80622, line 21) the API gives `quantity: 3270` but `_qtyReceived` / `_qtyOnHand` / `_qtyAvailable` / `_qtyFulfilled` are all `0`, while SQL on `Client_Nychh` gives received 3270. A literal `0` (not absent) rules out field ACL and `calcDepth`. Physical shadowing columns also ruled out (the blank template has 7 columns on `PurchaseOrderItems`). The team KB already has the cause from 2026-09-01: the deployed `_Model_Nychh_PurchaseOrderItem` INNER JOINs `InventoryAdjustmentItems.itemFulfillmentItemId`, which is NULL on 100% of rows. Talk to Jeff as "this narrows the known blocker", not as a new bug. Worked around locally with `VITE_TRANSFER_IGNORE_AVAILABILITY=true`.
|
|
99
|
+
- **Two migrations + one deploy are pending,** so the create path cannot be tested live yet (see next step).
|
|
100
|
+
|
|
101
|
+
## Exact next step
|
|
102
|
+
|
|
103
|
+
> Run the pending rollout, in this order: (1) deploy `_underscore` so `TransferOrder.php` carries `contactId` / `createdByUserId` / `description`; (2) run `dbchanges2/Client/2026-09-01c - TransferOrderContactCreatedByAndDescription.sql` on every client DB; (3) run `dbchanges2/Core/2026-09-01d - TransferOrderContactCreatedByAndDescriptionRecordFields.sql` on Core; (4) post `next Records.id = 359` / `next RecordFields.id = 2564` to the team; (5) create one test transfer in the modal with `VITE_TRANSFER_IGNORE_AVAILABILITY=true` and confirm the row has `contactId`, `createdByUserId`, `description`, and its `TransferOrderItems` rows written in the same request.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
_Saved by /session-save on 2026-09-02_
|
package/package.json
CHANGED