toga-ai 1.0.1149 → 1.0.1150
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/api2/features/v2-api-error-codes.md +5 -1
- package/knowledge/2.0/apps/toga-blox/features/api-client.md +3 -1
- package/knowledge/2.0/apps/toga-blox/features/table.md +3 -1
- package/knowledge/2.0/apps/toga25-supply/INDEX.md +1 -0
- package/knowledge/2.0/apps/toga25-supply/features/bundle-item-pricing.md +5 -3
- package/knowledge/2.0/apps/toga25-supply/features/bundle-item-retire.md +65 -0
- package/knowledge/2.0/apps/toga25-supply/features/loading-and-error-states.md +23 -1
- package/knowledge/2.0/apps/toga25-supply/workflows/cypress-testing.md +6 -2
- package/knowledge/INDEX.md +1 -1
- package/knowledge/clients/compass-usa/workflows/changing-a-kit-line-item.md +10 -4
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ project: API
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-26
|
|
10
10
|
owners: [mhammontree, tcox, jcardinal, ajean, bala, apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- api2/Component/Api/V2/V2.php
|
|
@@ -145,6 +145,9 @@ This applies to `api2/Controller/Index.php` and to any `catch (_Exception_Valida
|
|
|
145
145
|
- **⚠ 200 + `isSuccess: true` is not a write receipt** — a DB failure can ride along as an ERROR entry
|
|
146
146
|
in `messages[]` (cause in `messages[].identifiers.error`). Scan `messages[]` for `type: ERROR`; a
|
|
147
147
|
front end that trusts the status shows a false "saved".
|
|
148
|
+
- **⚠ Warning `WZ-2` on a write = NOTHING was written.** The role may write none of the fields sent,
|
|
149
|
+
yet the response is 2xx. Treat an exact `WZ-2` code as a failed write (toga25-supply:
|
|
150
|
+
`src/utils/apiWriteResult.ts`).
|
|
148
151
|
- **A 400 from an interceptor rule has a generic top-level message ("Operation Failed…").** The rule's
|
|
149
152
|
own text is in `messages[].identifiers.message`. Front ends must show that one (Desk:
|
|
150
153
|
`readApiRefusalMessage` in `src/api/recordApi.ts`), never the top-level text.
|
|
@@ -152,6 +155,7 @@ This applies to `api2/Controller/Index.php` and to any `catch (_Exception_Valida
|
|
|
152
155
|
- **`c_` prefix is significant** — a mis-prefixed field name rejects the whole write with EV-12; verify native-vs-custom with `SHOW COLUMNS`.
|
|
153
156
|
|
|
154
157
|
## Change history
|
|
158
|
+
- 2026-10-26 — Gotcha: a 2xx write with warning `WZ-2` wrote nothing (TRUE-83079). (tcox)
|
|
155
159
|
- 2026-10-24 — Interceptor 400: the rule text is in `messages[].identifiers.message`, top-level message is generic (TRUE-82916). (jcardinal)
|
|
156
160
|
- 2026-10-01 — Added note 17: a 200 / `isSuccess: true` envelope can still carry an ERROR entry in
|
|
157
161
|
`messages[]` (DB cause in `messages[].identifiers.error`), so axios/blox never throws and a front end
|
|
@@ -6,7 +6,7 @@ project: TOGa Blox
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-26
|
|
10
10
|
owners: [apeterson, tcox]
|
|
11
11
|
files:
|
|
12
12
|
- toga-blox/src/reactQuery/queryHelpers.ts
|
|
@@ -59,6 +59,7 @@ blox axios/React-Query client — envelope, auth (Bearer + refresh), option seri
|
|
|
59
59
|
## Gotchas
|
|
60
60
|
|
|
61
61
|
- **Must `setAxiosInstance` before use** — otherwise every call throws.
|
|
62
|
+
- **⚠ `apiDelete` uses `validateStatus: status < 500`, so a 4xx delete RESOLVES** — the caller shows a false "deleted" toast. `apiPut`/`apiPost` do throw on 4xx. Check the envelope yourself (toga25-supply: `assertApiWriteSucceeded`, see [loading & save-error states](../../toga25-supply/features/loading-and-error-states.md)). Not fixed in blox (legacy, fixes-only).
|
|
62
63
|
- Always check `response.isSuccess` before reading `data`; `data` keys are **camelCased slugs** (`/sales-orders` → `data.salesOrders`).
|
|
63
64
|
- `TableViewField.slug` (URL-safe) ≠ `tableViewField` (DB column path); `getDataTableData` maps slug → DB field.
|
|
64
65
|
- Only **401** auto-retries; other network errors need React Query `retry`.
|
|
@@ -92,4 +93,5 @@ blox axios/React-Query client — envelope, auth (Bearer + refresh), option seri
|
|
|
92
93
|
|
|
93
94
|
## Change history
|
|
94
95
|
|
|
96
|
+
- 2026-10-26 — Gotcha: `apiDelete` resolves on 4xx (false success) (TRUE-83079) (tcox).
|
|
95
97
|
- 2026-10-20 — Gotcha: axios-only refresh; raw `fetch` callers must refresh themselves (TRUE-82954) (tcox).
|
|
@@ -6,7 +6,7 @@ project: TOGa Blox
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-26
|
|
10
10
|
owners: [apeterson, tcox, bala]
|
|
11
11
|
files:
|
|
12
12
|
- toga-blox/src/components/Table/hooks/useFetchTablePageMeta.ts
|
|
@@ -133,6 +133,7 @@ This exists because an unscoped `GET /{recordRoute}` returns *every* row of a lo
|
|
|
133
133
|
- **`isExpandableCell` still clobbers every other rich cell type.** Only `STATUS`/`STATUS_BADGE` are protected today. `URGENCY`, `BOOLEAN`, `CURRENCY`, `DATE`, `AVATAR` and `CLIENT` carry the **same latent defect** — set the flag on one of those fields and the cell degrades to raw truncated text. The fuller fix is inverting the deny-list into an **allowlist** (expandable only for free-text/default cells); deliberately not done yet.
|
|
134
134
|
- **A cell-rendering difference between local and a deployed environment is usually DB data, not code.** `isExpandableCell` is a per-field flag in the **server's table meta**, so the same blox build renders differently against two databases. Diff the branches over the cell-rendering files **first** (`git diff <feature> origin/_sandbox-client -- src/components/Table/...`); if that comes back empty, stop reading code and go look at the table-meta rows.
|
|
135
135
|
- **An action cell with no `onAction` used to be DEAD — the chevron is now a real button (2026-09-21).** `ChevronActionCell` rendered a `<div>` whose `onClick` called `onAction?.(row)`, and no consumer ever supplied `onAction` (toga25-supply's `chevronOnly` column sets only id/position/width/type), so the expand chevron was an indicator that did nothing. Tell-tale: the CSS already carried a `.chevronCell:disabled` rule, which can never match a `div`. It is now a `<button>` with `aria-expanded`, `aria-label` (new `expandLabel`/`collapseLabel` props, defaults "Expand row"/"Collapse row"), `disabled` and `stopPropagation`; `ActionCellContext` gained `onRowClick` so a column with no `onAction` falls back to toggling its own row. **That fallback is deliberately scoped to `type === "CHEVRON"`** — applying it to every action-cell type would make e.g. a `DOWNLOAD` column with no `onAction` start firing the row click. A button also needs an explicit CSS reset (`padding: 0; font: inherit`) plus a `:focus-visible` outline. Shipped in `1.1.10-sandbox-client.170`.
|
|
136
|
+
- **⚠ Pin EVERY trailing action column sticky `"right"` — a non-sticky one breaks the column lines.** blox drops the right border of the column just before the **first** action column (`utils/isBeforeActionColumn` → `.beforeActionColumn { border-right: none }`), expecting that action column to be sticky and draw its own edge line; only the **first** right-sticky column draws that edge line (`utils/isEdgeStickyColumn`). So a non-sticky CUSTOM action column placed before a sticky one shows **no line on its left** and a **doubled (thick) line on its right**. Fix in the app: pin all trailing action columns `sticky: "right"`; `getStickyOffsets` stacks the right offsets. Seen in `@agilant/toga-blox` `1.1.4-production.196`, toga25-supply bundle line table (TRUE-83079).
|
|
136
137
|
- `MIN_COLUMN_WIDTH = 120` is the shrink floor only for columns with **no** explicit width.
|
|
137
138
|
- **Never truncate header labels.** `truncateCells` (`.truncateCells .headerCellLabel` in `toga.module.css`) is for **body** values only; it must apply only `white-space: nowrap` to the header (no `overflow:hidden`/`text-overflow:ellipsis`/wrapping) or headers show ellipses. Headers must render in full on one line, never abbreviated, never overlapping.
|
|
138
139
|
- The filter `includes` mode treats comma-separated values as OR.
|
|
@@ -144,6 +145,7 @@ This exists because an unscoped `GET /{recordRoute}` returns *every* row of a lo
|
|
|
144
145
|
- **Table/surface meta is cached with `Infinity` staleTime/gcTime** (`useFetchTablePageMeta`), so after a DB metadata change (`TableViewFields`, `Core.RecordFields`) a **hard reload** is required to see it. And the app consumes toga-blox's built **`dist/`**, not `src/` — editing blox source requires `npm run build` before it takes effect at runtime.
|
|
145
146
|
|
|
146
147
|
## Change history
|
|
148
|
+
- 2026-10-26 — Gotcha: a non-sticky action column before a sticky one loses its left line and doubles its right line (TRUE-83079) (tcox)
|
|
147
149
|
- 2026-10-05 — Storybook verify gotcha: blox's Storybook has no host tokens, components render unstyled (tcox)
|
|
148
150
|
- 2026-09-28 — multi-select filter "Clear" now actually clears (calls `onClear`, page-1 guard); sort badge now points down for `desc` via CSS rotation (apeterson)
|
|
149
151
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
| [TOGa 2.5 Supply — Architecture](architecture.md) | Architecture of toga25-supply — the React/TS Vite SPA frontend for 2.0 Supply, multi-client + meta-driven, built on `@agilant/toga-blox`; open before any struct |
|
|
6
6
|
| [Action-Button Rule Engine (Flag / Rule grammar)](features/action-button-rule-engine.md) | Declarative config-driven Flag/Rule grammar that resolves `isEnabled`/`isVisible`/`isComplete` on SalesOrder action-button options and approval stage inputs (ev |
|
|
7
7
|
| [Bundle item pricing (unit / lease rows, edit save path, duplicate rows)](features/bundle-item-pricing.md) | How a bundle item's unit/lease price is read, displayed and SAVED in supply — the two-call save (never nest the price in a PUT), `_unitPrice`/`_leasePrice` + `c |
|
|
8
|
+
| [Retiring a kit line (bundle item Active toggle, Status column — never delete)](features/bundle-item-retire.md) | How Supply admins retire a kit (bundle) line — Active toggle in the line editor, trash button = retire behind a confirm, Inactive badge in the Status column; op |
|
|
8
9
|
| [Client API-Fetch Fields (useClientApiFields / apiFields.json)](features/client-api-fetch-fields.md) | Resolves a client's API-fetch projection (`fields`/`ojoin`/`join`/`where`) from one colocated per-page `apiFields.json` keyed by client slug (useClientApiFields |
|
|
9
10
|
| [Client-Configurable Fields (useClientFields / fieldsConfig)](features/client-configurable-fields.md) | Config that varies by client (or client × role) — field overrides, filter buttons, group-by, column pickers, layout toggles — resolved through `src/fieldsConfig |
|
|
10
11
|
| [Column State (URL-driven show/hide, order & pinning)](features/column-visibility.md) | URL-driven "Columns" button + modal (`cols` param) for show/hide + order + pinning of table columns, client-configurable then Surface-driven; open for column-vi |
|
|
@@ -6,8 +6,8 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
10
|
-
owners: ["apeterson", "bala"]
|
|
9
|
+
updated: 2026-10-26
|
|
10
|
+
owners: ["apeterson", "bala", "tcox"]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/layout/BundleItemRecordModalLayout/hooks/useBundleItemEditForm.tsx
|
|
13
13
|
- toga25-supply/src/layout/BundleRecordModalLayout/types.ts
|
|
@@ -24,6 +24,7 @@ related:
|
|
|
24
24
|
- ../../api2/features/v2-api-error-codes.md
|
|
25
25
|
- ./record-modals-and-nested-tables.md
|
|
26
26
|
- ../../../clients/compass-usa/workflows/changing-a-kit-line-item.md
|
|
27
|
+
- ./bundle-item-retire.md
|
|
27
28
|
---
|
|
28
29
|
|
|
29
30
|
How a bundle item's unit/lease price is read, displayed and SAVED in supply — the two-call save (never nest the price in a PUT), `_unitPrice`/`_leasePrice` + `calcDepth: 2`, and the duplicate `BundleItemPrices` rows.
|
|
@@ -114,7 +115,8 @@ established it **creates a new row** rather than overwriting an unknown one. Nev
|
|
|
114
115
|
- **⚠ A failed price save can report SUCCESS.** api2 returned `status: 200` / `isSuccess: true` while
|
|
115
116
|
carrying the `EV-10` DB failure inside `messages[].identifiers.error`, so blox `apiPut` did not throw
|
|
116
117
|
and the modal showed "Bundle item updated" on a write that never landed. Check `messages[]` for
|
|
117
|
-
`type: ERROR` — see [V2 error codes](../../api2/features/v2-api-error-codes.md).
|
|
118
|
+
`type: ERROR` — see [V2 error codes](../../api2/features/v2-api-error-codes.md). The bundle line
|
|
119
|
+
save now runs `assertApiWriteSucceeded` ([save-error handling](./loading-and-error-states.md)).
|
|
118
120
|
- **⚠ A kit price change does NOT reprice orders (Compass/Canada).** A price edit inserts a new
|
|
119
121
|
`BundleItemPrices` row; commerce reads the newest, but `SalesOrderItems.price` is a snapshot, so
|
|
120
122
|
pending orders keep the old price. Some **new** orders also saved the old price after the update
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Retiring a kit line (bundle item Active toggle, Status column — never delete)
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: toga25-supply
|
|
5
|
+
project: TOGa 2.5 Supply
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-10-26
|
|
10
|
+
owners: ["tcox"]
|
|
11
|
+
files:
|
|
12
|
+
- toga25-supply/src/layout/BundleItemRecordModalLayout/hooks/useRetireBundleItem.ts
|
|
13
|
+
- toga25-supply/src/layout/BundleItemRecordModalLayout/hooks/useBundleItemEditForm.tsx
|
|
14
|
+
- toga25-supply/src/layout/BundleItemRecordModalLayout/components/BundleItemRecordEdit.tsx
|
|
15
|
+
- toga25-supply/src/layout/BundleItemRecordModalLayout/viewModel/FIELDS/DEFAULT/bundleItemRecordFields.json
|
|
16
|
+
- toga25-supply/src/layout/BundleRecordModalLayout/components/BundleItemsTable.tsx
|
|
17
|
+
- toga25-supply/src/layout/BundleRecordModalLayout/viewModel/useBundleItemsTableViewModel.tsx
|
|
18
|
+
- toga25-supply/src/layout/BundleRecordModalLayout/viewModel/FIELDS/DEFAULT/bundleRecordViewFields.json
|
|
19
|
+
- _underscore/Model/Client/Bundle.php
|
|
20
|
+
- _underscore/Model/Compass/Bundle.php
|
|
21
|
+
related:
|
|
22
|
+
- ./bundle-item-pricing.md
|
|
23
|
+
- ./loading-and-error-states.md
|
|
24
|
+
- ./record-modals-and-nested-tables.md
|
|
25
|
+
- ../../toga-blox/features/table.md
|
|
26
|
+
- ../../../../clients/compass-usa/workflows/changing-a-kit-line-item.md
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
How Supply admins retire a kit (bundle) line — Active toggle in the line editor, trash button = retire behind a confirm, Inactive badge in the Status column; open before adding any delete/remove action to bundle items.
|
|
30
|
+
|
|
31
|
+
## Summary
|
|
32
|
+
|
|
33
|
+
A kit line (`BundleItems` row) is **retired (`isActive = 0`), never deleted**, from Supply.
|
|
34
|
+
`SalesOrderItems.bundleItemId` and `SalesQuoteItems.bundleItemId` point at old lines, so a real
|
|
35
|
+
delete breaks placed orders/quotes and fails outright once a line has a price or an order.
|
|
36
|
+
Retire needs the role's **UPDATE** grant + write on `isActive` — not DELETE.
|
|
37
|
+
|
|
38
|
+
## How it works
|
|
39
|
+
|
|
40
|
+
### Line editor (`BundleItemRecordModalLayout`)
|
|
41
|
+
- **Active** toggle in the Settings section (`bundleItemRecordFields.json`). New line defaults Active; an existing line keeps its saved value.
|
|
42
|
+
- Save sends the toggle value. (Before TRUE-83079 the save hardcoded `isActive: 1`, so any edit silently re-activated a retired line.)
|
|
43
|
+
- **No Delete button.** Removed on purpose: it fired with no confirm and threw away unsaved edits. Retire in the editor = toggle off + Save.
|
|
44
|
+
|
|
45
|
+
### Bundle line table (`BundleItemsTable`)
|
|
46
|
+
- Trash button **retires**: `PUT /v2/bundle-items/{uuid}` `{ isActive: 0 }` behind a "Retire bundle item?" confirm dialog. Hidden on inactive lines.
|
|
47
|
+
- **Status** column: blox CUSTOM action column showing an Inactive badge (blank when Active). Labels from `bundleRecordViewFields.json` → `bundleItemsStatusColumn { label, inactiveLabel }`; reuses the modal `.badge` CSS.
|
|
48
|
+
- Every trailing action column is pinned sticky `"right"` — see the blox action-column border gotcha in [Table component](../../toga-blox/features/table.md).
|
|
49
|
+
- Shared hook `useRetireBundleItem`; table refetches after retire.
|
|
50
|
+
|
|
51
|
+
### Why a partial PUT `{ isActive: 0 }` is safe
|
|
52
|
+
- V2 update writes only the sent fields.
|
|
53
|
+
- `BundleItem` models have no save hooks.
|
|
54
|
+
- Kit price totals in `_Model_Client_Bundle` and `_Model_Compass_Bundle` already filter `BundleItems.isActive = 1`, so a retired line drops out of the kit price.
|
|
55
|
+
|
|
56
|
+
### Write result check
|
|
57
|
+
Save and retire run the response through `assertApiWriteSucceeded()` — a 2xx can still be a failed write. See [save-error handling](./loading-and-error-states.md).
|
|
58
|
+
|
|
59
|
+
## Gotchas
|
|
60
|
+
- **⚠ Never add a hard delete for bundle items** — not in the table, not in the editor. Retire only.
|
|
61
|
+
- A role with no write grant on `isActive` gets a 2xx with warning `WZ-2` and **nothing is written** — `assertApiWriteSucceeded` turns that into an error toast. The fix is an ACL grant, not front-end code.
|
|
62
|
+
- **Compass test kits (client-sandbox, Base persona):** kit #82 "HP B/W LaserJet Printer" (bundle id 4); kit #115 "HP All-In-One Printer (9130b)" (bundle id 20) — #115 has **two active Primary lines** for the same printer (line 400 `4U555A#B1H`, line 2042 `4U555A-S`), the known duplicate-item pair; good for a retire test. Kit number = `Bundles.number`, not `id`.
|
|
63
|
+
|
|
64
|
+
## Change history
|
|
65
|
+
- 2026-10-26 — Supply can retire kit lines: Active toggle, trash = retire + confirm, Status column, editor Delete removed; save no longer forces `isActive: 1` (TRUE-83079). (tcox)
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-26
|
|
10
10
|
owners: ["tcox"]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/components/TableSkeleton/TableSkeleton.tsx
|
|
@@ -18,8 +18,12 @@ files:
|
|
|
18
18
|
- toga25-supply/src/layout/PrimaryTableClientLayout/PrimaryTableClientLayout.tsx
|
|
19
19
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/recordShapeMemory.ts
|
|
20
20
|
- toga25-supply/src/utils/saveErrorToaster.ts
|
|
21
|
+
- toga25-supply/src/utils/apiWriteResult.ts
|
|
21
22
|
related:
|
|
22
23
|
- ./record-modals-and-nested-tables.md
|
|
24
|
+
- ./bundle-item-retire.md
|
|
25
|
+
- ../../api2/features/v2-api-error-codes.md
|
|
26
|
+
- ../../toga-blox/features/api-client.md
|
|
23
27
|
- ./transfer-orders-page.md
|
|
24
28
|
- ./persisted-query-cache.md
|
|
25
29
|
- ../workflows/cypress-testing.md
|
|
@@ -50,6 +54,22 @@ Per-record shape (`itemCount`, `hasInvoices`, `hasShipments`) in `sessionStorage
|
|
|
50
54
|
### Save-error toaster — `src/utils/saveErrorToaster.ts`
|
|
51
55
|
Item, vendor-item, bundle and bundle-item create/edit hooks call `useToaster().addToaster({ status: "error", ...SAVE_ERROR_TOASTER_MESSAGE })`. Raw error goes to the console, never to the user. New save hooks must use the same constant.
|
|
52
56
|
|
|
57
|
+
### Write-result check — `src/utils/apiWriteResult.ts`
|
|
58
|
+
An api2 write can answer 2xx and still fail. `assertApiWriteSucceeded(response)` throws `ApiWriteError` when:
|
|
59
|
+
1. `isSuccess === false`, or
|
|
60
|
+
2. any `messages[]` entry has `type: "ERROR"`, or
|
|
61
|
+
3. a warning code is exactly `WZ-2` (role may write none of the sent fields → nothing written).
|
|
62
|
+
|
|
63
|
+
`describeApiWriteError(error)` builds the toast text, in this order:
|
|
64
|
+
1. `messages[].identifiers.message` (interceptor rule text),
|
|
65
|
+
2. else the defined message with the `"Operation Failed: "` prefix stripped,
|
|
66
|
+
3. plus `(code, ref <error.id>)`,
|
|
67
|
+
4. fallback `SAVE_ERROR_TOASTER_MESSAGE`.
|
|
68
|
+
|
|
69
|
+
Never shows `identifiers.error` (raw SQL + DB name). Used by bundle line save + retire ([bundle-item-retire](./bundle-item-retire.md)); new write hooks should use it.
|
|
70
|
+
|
|
71
|
+
**Decision (TRUE-83079, tcox):** showing api2's curated defined/interceptor message is a deliberate exception to frontend standard §19 "no raw server string" — it is curated text, not raw.
|
|
72
|
+
|
|
53
73
|
### Visual review — temporary dev gallery
|
|
54
74
|
To eyeball every state at once: restore the old gallery with `git show TRUE-79502:src/pages/DevLoadingStates/DevLoadingStatesPage.tsx`, register it in `src/routes.tsx` **inside `AllowedRoutes`** behind `import.meta.env.DEV` at `/dev/loading-states` (needs login). Newer blox `TablePagination` needs `recordsPerPage` inside `paginationMeta` — the old page must be patched. **Delete it before merge**; it is not shipped.
|
|
55
75
|
|
|
@@ -58,7 +78,9 @@ To eyeball every state at once: restore the old gallery with `git show TRUE-7950
|
|
|
58
78
|
- **⚠ `isPageFetch` path in `PrimaryTableServerLayout` is dead code** (never true in practice). Open follow-up — do not build on it.
|
|
59
79
|
- **⚠ Do not merge `_production` into the stale TRUE-79502 / TRUE-79505 branches** — it drops newer prod features. Cut a fresh branch from `_production` and port pieces by hand (done as TRUE-82385).
|
|
60
80
|
- Old-branch pieces deliberately **not** ported: `ModalBanner` error variant + `DevErrorStates` page (TRUE-79505), `BulkProgressToast` (no consumers), `DevLoadingStatesPage` (demo), `SalesOrderItemsTableLayout` (deleted in `_production` 97d20ff). TRUE-79502-update's `useClientFields` / Prudential CSV-BOM edits are unrelated to loading. TRUE-79505-updated, TRUE-79505-prod and TRUE-79501 are already fully in `_production`. TRUE-79506 never existed.
|
|
81
|
+
- **⚠ blox `apiDelete` resolves on a 4xx** (false "deleted" toast) — see [api-client](../../toga-blox/features/api-client.md). **OPEN:** `useBundleEditForm.tsx:34` (persona-bundle removal) still trusts `apiDelete`; run it through `assertApiWriteSucceeded`.
|
|
61
82
|
- A disabled React Query v5 query reports `pending` forever — see [transfer-orders-page](./transfer-orders-page.md) before deriving a skeleton flag from one.
|
|
62
83
|
|
|
63
84
|
## Change history
|
|
85
|
+
- 2026-10-26 — Added `apiWriteResult.ts` (2xx-but-failed write check + curated toast text, §19 exception) for bundle line save/retire (TRUE-83079). (tcox)
|
|
64
86
|
- 2026-10-06 — Ported loading states (TRUE-79502-update) + save-error toaster onto fresh `_production` as TRUE-82385; Transfer Orders wired; Cypress expectations updated. (tcox)
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: workflow
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-26
|
|
10
10
|
owners: [apeterson, tcox, rgirish]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/cypress.config.ts
|
|
@@ -149,7 +149,8 @@ Writing the create specs turned up five real app defects. Recorded here because
|
|
|
149
149
|
|
|
150
150
|
### Rest of the repo's test state (for context)
|
|
151
151
|
|
|
152
|
-
- **Vitest is the other half.** `npm test` (`vitest run`) currently has **one failing test file**: `src/hooks/useTalosSurface.test.ts` fails with `TypeError: Unknown file extension ".css"` on `@agilant/toga-blox/dist/global.css` — the suite fails to **load**, so it is silently skipped in full. **Pre-existing** — the file was last touched in commit `604a779` and the Cypress work changed neither it nor `vitest.config.ts`. Re-confirmed on a clean tree 2026-09-14, with every other file green (148/148 on `_sandbox-client`). Needs a separate fix (Vitest CSS handling for blox imports).
|
|
152
|
+
- **Vitest is the other half.** `npm test` (`vitest run`) currently has **one failing test file**: `src/hooks/useTalosSurface.test.ts` fails with `TypeError: Unknown file extension ".css"` on `@agilant/toga-blox/dist/global.css` — the suite fails to **load**, so it is silently skipped in full. **Pre-existing** — the file was last touched in commit `604a779` and the Cypress work changed neither it nor `vitest.config.ts`. Re-confirmed on a clean tree 2026-09-14, with every other file green (148/148 on `_sandbox-client`). Needs a separate fix (Vitest CSS handling for blox imports). Still failing 2026-10-26.
|
|
153
|
+
- **⚠ On Windows, vitest HANGS with the default `threads` pool** (no output, >5 min). Run `npx vitest run <files> --pool=forks` (~8s).
|
|
153
154
|
- **Dozens of unrelated `tsc -p tsconfig.app.json` errors? Check `node_modules` against the lock first.** Seen 2026-10-16: installed blox `1.0.318-beta.40` vs pinned `1.1.4-production.196`. `npm ci --legacy-peer-deps` fixed it.
|
|
154
155
|
- **No other mechanical guardrails exist in this repo:** no `.github/workflows`, no husky, no lint-staged. The only `.git/hooks/pre-commit` is a machine-local `code-review-graph` shim that always exits 0 and is not checked in.
|
|
155
156
|
- **Green FE tests do not mean a client gets a feature.** Real rollout is a role-scoped `SurfaceOverrides IS_VISIBLE` row in `dbchanges2`; the fixture only simulates the grant.
|
|
@@ -174,3 +175,6 @@ Writing the create specs turned up five real app defects. Recorded here because
|
|
|
174
175
|
- **⚠ Some lists are fetched TWICE when they open** (once as the unfiltered search source, once for the filtered options), so a `cy.wait('@alias')` can consume the wrong request and assert against the wrong body. Assert on **`cy.get('@alias.all')`** and pick the request you mean.
|
|
175
176
|
- **⚠ After merging a branch off `_feature-cypress`, run `npm install` before anything else.** Those branches import Talos packages (`@assistant-ui/react`, `@assistant-ui/react-markdown`, `@langchain/langgraph-sdk`, `remark-gfm`); with a stale `node_modules` **every page** dies with *"Failed to resolve import"* and every spec fails for a reason that looks nothing like the cause. The lockfile already has them, so plain `npm install` fixes it. **Note:** `npm install` replaces a locally linked blox with the registry copy — relink afterwards if you were testing a local blox.
|
|
176
177
|
- **Scrub captured payloads.** Copying a real body out of Chrome DevTools (Network → filter `/v2/` → Response → Copy response) is the fastest way to build a fixture — but those payloads carry **real customer data**. Remove emails, names, addresses and tokens before committing.
|
|
178
|
+
|
|
179
|
+
## Change history
|
|
180
|
+
- 2026-10-26 — Vitest on Windows: use `--pool=forks` (default pool hangs) (TRUE-83079). (tcox)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -32,7 +32,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
32
32
|
- **toga2-view** (TOGa View Frontend) — 12 doc(s) → [2.0/apps/toga2-view/INDEX.md](2.0/apps/toga2-view/INDEX.md)
|
|
33
33
|
- **toga2-hub** (TOGa Hub) — 2 doc(s) → [2.0/apps/toga2-hub/INDEX.md](2.0/apps/toga2-hub/INDEX.md)
|
|
34
34
|
- **toga2-commerce** (TOGa Commerce) — 34 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
|
|
35
|
-
- **toga25-supply** (TOGa 2.5 Supply) —
|
|
35
|
+
- **toga25-supply** (TOGa 2.5 Supply) — 28 doc(s) → [2.0/apps/toga25-supply/INDEX.md](2.0/apps/toga25-supply/INDEX.md)
|
|
36
36
|
- **toga25-iq** (TOGa IQ) — 1 doc(s) → [2.0/apps/toga25-iq/INDEX.md](2.0/apps/toga25-iq/INDEX.md)
|
|
37
37
|
- **toga2-template** (TOGa App Template) — 1 doc(s) → [2.0/apps/toga2-template/INDEX.md](2.0/apps/toga2-template/INDEX.md)
|
|
38
38
|
- **toga25-desk** (TOGa Desk 2.5) — 1 doc(s) → [2.0/apps/toga25-desk/INDEX.md](2.0/apps/toga25-desk/INDEX.md)
|
|
@@ -6,12 +6,14 @@ project: TOGa Commerce
|
|
|
6
6
|
client: compass-usa
|
|
7
7
|
type: workflow
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
10
|
-
owners: [bala]
|
|
9
|
+
updated: 2026-10-26
|
|
10
|
+
owners: [bala, tcox]
|
|
11
11
|
files:
|
|
12
12
|
- toga2-commerce/src/utils/checkIsItemPurchasable.ts
|
|
13
13
|
- toga2-commerce/src/pages/BundleView/api/BundleApi.tsx
|
|
14
|
+
- toga25-supply/src/layout/BundleItemRecordModalLayout/hooks/useRetireBundleItem.ts
|
|
14
15
|
related:
|
|
16
|
+
- ../../../2.0/apps/toga25-supply/features/bundle-item-retire.md
|
|
15
17
|
- ./granting-persona-bundle-access.md
|
|
16
18
|
- ./cross-kit-bundle-corruption.md
|
|
17
19
|
- ./persona-refactor-migration.md
|
|
@@ -47,13 +49,13 @@ The request is usually phrased by the **hero item** ("every kit with the new iPa
|
|
|
47
49
|
### The write pattern: INSERT a mirror line, then deactivate the old one
|
|
48
50
|
1. `INSERT` a new `BundleItems` row **mirroring the line it replaces** — same `bundleItemGroupId`, `sortOrder`, `isActive` / `isRequired` / `isVisible`, quantities and `measureId` — changing only `itemId`.
|
|
49
51
|
2. `INSERT` the matching `BundleItemPrices` rows for the new line. This is the **only** child table that needs mirroring.
|
|
50
|
-
3.
|
|
52
|
+
3. Retire the old line (`isActive = 0`). It stays in the table forever. **No SQL needed (since TRUE-83079):** a Supply admin turns off **Active** in the line editor, or uses the line table's trash button (retire + confirm) — see [Retiring a kit line](../../../2.0/apps/toga25-supply/features/bundle-item-retire.md). A retired line drops out of the kit price.
|
|
51
53
|
|
|
52
54
|
### Checklist for any "add an item to a kit" data change
|
|
53
55
|
1. Resolve the hero by `BundleItems.itemId` (not part number) and list **every** matching bundle, allowing for multiple active primaries.
|
|
54
56
|
2. Confirm which of those kits already carry the target line, so you change only the ones that need it.
|
|
55
57
|
3. Insert the mirror `BundleItems` row, then its `BundleItemPrices` rows.
|
|
56
|
-
4.
|
|
58
|
+
4. Retire the replaced line (`isActive = 0`) — in Supply, or in the same SQL file for a bulk change. Never delete it.
|
|
57
59
|
5. **Diff `Personas_Items` for the new item against the item it replaces and backfill every missing `personaId` — persona 1 "All" above all.** This is the step that gets forgotten, and it is the one that decides whether anyone sees the change.
|
|
58
60
|
6. Re-check `Personas_Bundles` only if the kit itself is new to a persona; an existing bundle grant needs no change.
|
|
59
61
|
|
|
@@ -77,7 +79,11 @@ Then the `Personas_Items` backfill above, without which only MITS Team would hav
|
|
|
77
79
|
- **⚠ `BundleItemPrices` can already hold duplicate rows for the same `priceTypeId`** — old line **457** had **three** rows at `priceTypeId = 1`. Copy the source rows deliberately: do not assume one row per price type, and do not blindly reproduce the duplicates either.
|
|
78
80
|
- **Open issue — bundle 27's lease pricing is partly stale.** Bundle **27** is the only one of the three carrying **lease-48 (`priceTypeId = 3`)** prices, and its **new** hero line **1990** has **no lease price at all**. Anyone quoting bundle 27 on a 48-month lease is reading incomplete pricing. Not fixed; needs a pricing decision before the missing rows are added.
|
|
79
81
|
|
|
82
|
+
## Change history
|
|
83
|
+
- 2026-10-26 — Retiring the old line no longer needs SQL: Supply has an Active toggle + retire button (TRUE-83079). Same flow for Compass Canada. (tcox)
|
|
84
|
+
|
|
80
85
|
## Related
|
|
86
|
+
- [Retiring a kit line (Supply)](../../../2.0/apps/toga25-supply/features/bundle-item-retire.md)
|
|
81
87
|
- [Granting persona bundle access](./granting-persona-bundle-access.md)
|
|
82
88
|
- [Cross-kit bundle corruption](./cross-kit-bundle-corruption.md)
|
|
83
89
|
- [Persona refactor migration](./persona-refactor-migration.md)
|
package/package.json
CHANGED