toga-ai 1.0.1099 → 1.0.1101
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/toga2-commerce/features/cart-add-item-line-merge.md +2 -2
- package/knowledge/2.0/apps/toga2-commerce/features/catalog-cache-freshness.md +16 -8
- package/knowledge/2.0/apps/toga2-commerce/features/error-codes-and-sentry-signals.md +4 -3
- package/knowledge/2.0/apps/toga2-commerce/features/inactive-item-purchase-gating.md +3 -2
- package/knowledge/2.0/apps/toga25-supply/features/sales-order-items-table.md +2 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ project: TOGa Commerce
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-21
|
|
10
10
|
owners: ["tcox"]
|
|
11
11
|
files:
|
|
12
12
|
- toga2-commerce/src/stores/useCartStoreZu.ts
|
|
@@ -72,7 +72,7 @@ Passed 2026-10-19. Unit tests: `src/stores/useCartStoreZu.test.ts` (4 tests incl
|
|
|
72
72
|
## Gotchas
|
|
73
73
|
|
|
74
74
|
- **⚠ Fixing the re-add price exposed a price-0 bug on the item page.** `handleAddItemToCart` used to reset `itemForCart` to price 0 / lease 0 / uuid `""`; the sync effect does not re-run, so a second click sent price 0. The old merge hid it by keeping the line's price. Fixed on `TRUE-82729`: reset quantity only.
|
|
75
|
-
- **⚠ The old merge bug was old, not a regression** — present since at least 2025-10 (`8c3ad44c`). It surfaced in QA after `TRUE-82427` made the item page send the refetched price (CodeRabbit
|
|
75
|
+
- **⚠ The old merge bug was old, not a regression** — present since at least 2025-10 (`8c3ad44c`). It surfaced in QA after `TRUE-82427` made the item page send the refetched price (CodeRabbit on the old PR #376, since closed — 82427 was restarted, see [catalog cache freshness](./catalog-cache-freshness.md#summary)). `TRUE-81382` never touches the cart store.
|
|
76
76
|
- The inactive-item guard also lives in `addItem` — see [inactive-item purchase gating](./inactive-item-purchase-gating.md#3-the-store-is-the-choke-point-not-the-buttons).
|
|
77
77
|
|
|
78
78
|
## Change history
|
|
@@ -6,7 +6,7 @@ project: TOGa Commerce
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-21
|
|
10
10
|
owners: ["bala", "apeterson", "tcox"]
|
|
11
11
|
files:
|
|
12
12
|
- toga2-commerce/src/lib/queryClient.ts
|
|
@@ -19,6 +19,7 @@ files:
|
|
|
19
19
|
- toga2-commerce/src/pages/BundleView/hooks/useBundleQueryData.ts
|
|
20
20
|
- toga2-commerce/src/pages/Home/viewModel/useHomeViewModel.ts
|
|
21
21
|
- toga2-commerce/src/pages/Home/HomePage.tsx
|
|
22
|
+
- toga2-commerce/src/components/AuthLayout/AuthLayout.tsx
|
|
22
23
|
- toga2-commerce/src/pages/ItemsView/viewModel/useItemDetailsViewModel.ts
|
|
23
24
|
- toga2-commerce/src/pages/Filter/viewModel/useFilterViewModel.ts
|
|
24
25
|
- toga2-commerce/src/pages/Cart/viewModel/useCartViewModel.ts
|
|
@@ -45,7 +46,9 @@ The persisted React Query cache (`localStorage["commerce"]`), the per-query `sta
|
|
|
45
46
|
|
|
46
47
|
## Summary
|
|
47
48
|
|
|
48
|
-
> **Status 2026-10-
|
|
49
|
+
> **Status 2026-10-21 — branch-dependent.** `TRUE-82427` (`dccedde1`, **pending PR, not on `_production` or `_sandbox-client`**) removes the per-query `staleTime` overrides on item detail, filter/search, cart shipping methods, Home and BundleView, and turns `refetchOnWindowFocus` back on app-wide. On `_production` and `_sandbox-client` the 24h overrides in [the inventory](#where-the-staleness-lives) still apply. Confirm the branch before reasoning about freshness.
|
|
50
|
+
>
|
|
51
|
+
> Restarted from scratch 2026-10-21 (developer's call): new branch cut from `_production` `33f84716`. The old branch, PR #376 and commits `93f12265` / `246ef484` / `61e4ffd9` / `e5eca52f` are gone; the old `_sandbox-client` merge `3bd23a15` was reverted by `b435def9`. Never cite the old hashes.
|
|
49
52
|
|
|
50
53
|
The whole React Query cache is persisted to **`localStorage["commerce"]`** via `PersistQueryClientProvider`. With a long `staleTime` it serves catalogue and price state hours out of date **across full page reloads**, in both directions (a switched-off item stays buyable; a switched-on item stays hidden).
|
|
51
54
|
|
|
@@ -71,7 +74,7 @@ Cache persisted via `createSyncStoragePersister` with a build-id **`buster`** an
|
|
|
71
74
|
|
|
72
75
|
### Where the staleness lives
|
|
73
76
|
|
|
74
|
-
`_production` column inventoried 2026-10-01; `TRUE-82427` column verified 2026-10-
|
|
77
|
+
`_production` column inventoried 2026-10-01; `TRUE-82427` column re-verified 2026-10-21 on `dccedde1`.
|
|
75
78
|
|
|
76
79
|
| Query | `_production` | `TRUE-82427` |
|
|
77
80
|
|---|---|---|
|
|
@@ -81,7 +84,7 @@ Cache persisted via `createSyncStoragePersister` with a build-id **`buster`** an
|
|
|
81
84
|
| `useHomeViewModel.ts` (3) | 30s + `gcTime` 1h + focus `false` | `gcTime` 1h only |
|
|
82
85
|
| `useBundleQueryData.ts` (2) | 30s + `gcTime` 1h + focus `false` | `gcTime` 1h only |
|
|
83
86
|
| `useEditAddressFromCartForm.ts:75` countries | 24h | 24h — out of scope (dev decision) |
|
|
84
|
-
| `queries/queries.ts
|
|
87
|
+
| `queries/queries.ts` login/prefetch | 5 min | 5 min — out of scope (dev decision) |
|
|
85
88
|
|
|
86
89
|
**On `_production`:** a price/availability edit can take **up to 24h** to reach the item page, and a refresh does not fix it (the copy is in `localStorage["commerce"]`).
|
|
87
90
|
|
|
@@ -102,7 +105,9 @@ Limits to state to the business:
|
|
|
102
105
|
- the effect runs in `"fields-ready"` **or** `"ready"`;
|
|
103
106
|
- it uses functional `setHomeDataState(prev => …)` spreading `prev.data`, so `bundlesData` survives when the bundles, categories and items blocks all run in one pass;
|
|
104
107
|
- it depends on `homeDataState.status`, not the whole object (avoids a render loop);
|
|
105
|
-
- the view model no longer sets the `*ToDisplay` lists — `HomePage.tsx` rebuilds them in a **`useLayoutEffect`** on `data` via `applySearch(submittedSearchRef.current)`, keeping the shopper's **submitted** search. Not `inputValue` — the search box updates it on every keystroke, so reapplying it would filter by unsubmitted typing
|
|
108
|
+
- the view model no longer sets the `*ToDisplay` lists — `HomePage.tsx` rebuilds them in a **`useLayoutEffect`** on `data` via `applySearch(submittedSearchRef.current)`, keeping the shopper's **submitted** search. Not `inputValue` — the search box updates it on every keystroke, so reapplying it would filter by unsubmitted typing. The ref is set in `handleSearchSubmit` and cleared in `handleClearSearch`. A plain `useEffect` caused a one-frame "no results" flash;
|
|
109
|
+
- `applySearch` / `handleClearSearch` set both lists with `?? []`, so an old list cannot stay on screen;
|
|
110
|
+
- the error page shows only when the failing query has **no data**: `assortmentsFailed = data ? null : error` (same for bundles), and `isError` clears when both recover. Without this, a failed background refetch replaced good cached Home data with the error page until remount.
|
|
106
111
|
|
|
107
112
|
### Item detail Add to Cart must use the refetched price (`TRUE-82427`)
|
|
108
113
|
|
|
@@ -132,11 +137,11 @@ const shouldDehydrateQuery = (query) => {
|
|
|
132
137
|
> **⚠ Branch state (2026-10-08) — two persistence filters exist; neither is on `_production`.**
|
|
133
138
|
> - `_production`: `buster` + `throttleTime: 0`, **no `dehydrateOptions`**.
|
|
134
139
|
> - `_beta` / `#sprint84`: `NON_PERSISTED_QUERY_KEYS` above, in `App.tsx`.
|
|
135
|
-
> - `TRUE-81382`
|
|
140
|
+
> - `TRUE-81382` (off `_sandbox-client` since revert `df472007`, 2026-10-21): `shouldPersistQuery` in `src/queries/queries.ts`, excluding `BUNDLE_QUERY_KEYS` (`fetchBundlesByPersona`, `bundleData`, `bundleImagesData`, `fetchItemDetailsViaBundle`).
|
|
136
141
|
>
|
|
137
142
|
> When they meet, merge into **one** filter holding both key lists.
|
|
138
143
|
|
|
139
|
-
**Bundle queries uncached — `TRUE-81382` branch only.** There, `bundleData`, `bundleImagesData`, `fetchBundlesByPersona` spread `BUNDLE_NO_CACHE_QUERY_OPTIONS` (`{ staleTime: 0, gcTime: 0 }`) and are excluded by `shouldPersistQuery`; `useBundleBuilderZu` no longer persists the raw parent-bundle payload (cause: an inactive item was orderable from a stale persisted bundle). The constant does **not** exist on `_production` or `TRUE-82427`. **Merging with `TRUE-82427`** (
|
|
144
|
+
**Bundle queries uncached — `TRUE-81382` branch only.** There, `bundleData`, `bundleImagesData`, `fetchBundlesByPersona` spread `BUNDLE_NO_CACHE_QUERY_OPTIONS` (`{ staleTime: 0, gcTime: 0 }`) and are excluded by `shouldPersistQuery`; `useBundleBuilderZu` no longer persists the raw parent-bundle payload (cause: an inactive item was orderable from a stale persisted bundle). The constant does **not** exist on `_production` or `TRUE-82427`. **Merging with `TRUE-82427`** (checked 2026-10-13 against `origin/TRUE-81382` `7fcecbf3` and the old 82427 branch; the restarted branch edits the same lines, so it still applies): 81382 does **not** set `refetchOnWindowFocus: false` on the bundle queries. Both branches edit the same lines in `useBundleQueryData.ts` and the Home bundles query, so git shows a conflict there. Resolve to: keep the `...BUNDLE_NO_CACHE_QUERY_OPTIONS` spread; no `refetchOnWindowFocus: false`; no `staleTime: 30_000`; no `gcTime: 1h` on the bundle queries (81382's `gcTime: 0` wins). `_sandbox-client` still carries the old `false` values (app-wide and per-query) until 82427 reaches it. In `App.tsx` keep **both** `buster` and `dehydrateOptions`.
|
|
140
145
|
|
|
141
146
|
### Decision — `gcTime` is the speed knob, `staleTime` is the correctness knob
|
|
142
147
|
|
|
@@ -171,6 +176,8 @@ Pinned 2026-09-03 on `TRUE-81610`.
|
|
|
171
176
|
- BundleView `applyBundleFormatting.ts` — the image effect is blocked by the `hasRunImageFormatting` ref, so an images-only refetch is ignored.
|
|
172
177
|
- Filter — search results come from a `useMutation` `onSuccess` on search-text change, so focus refetch never refreshes them (category browsing is fine).
|
|
173
178
|
- `GetSupportPage.tsx` — calls `reset()` on every `userData` change, so a refetch with changed data can wipe a message being typed.
|
|
179
|
+
- **⚠ Never call a page view model from `AuthLayout`.** It stays mounted on every route, so the view model's queries run on every page. `AuthLayout` used `useHomeViewModel()` only to read `homeDataState.fields`, which kept the 3 heavy Home queries (`fetchAssortmentsByPersona`, `fetchBundlesByPersona`, items) live everywhere — with focus refetch on, every tab return refetched all three. Fixed on `TRUE-82427`: `AuthLayout` reads `useAssignClientFields(fieldKey, language, user).fields` directly, with the same "all five groups present" gate (`HEADERFIELDS`, `HOMEPAGEFIELDS`, `FOOTERFIELDS`, `LOGINSETTINGSFIELDS`, `CARTOVERLAY`), and keeps the last full set in a `useRef` while a new `clientFields` key loads (language switch, view-as role change, after a cache clear). Without the ref, `useQuery` returns `undefined` for a render: header/footer labels blank and `LoginSettingsSwitcher` unmounts mid-submit. Trade-off: the first Home visit after landing on another page is a cold fetch (fine — `gcTime` 1h + persisted cache).
|
|
180
|
+
- **⚠ "The price didn't update" — check the environment first.** A price changed in one environment's Supply never reaches a Commerce pointed at another. `npm run compass` uses `.env.development` → `https://api.beta.togahub.com/v2` (beta DB). To test a client-sandbox Supply change locally: run `npx vite --mode sandbox-client --host compass.togacommerce` (`.env.sandbox-client` → `https://api.client.sandbox.togahub.com/v2`), then `localStorage.clear()` and log in again (beta tokens do not work on client-sandbox).
|
|
174
181
|
- **⚠ A per-query `refetchOnWindowFocus: false` or `staleTime` beats the global default.** Grep for them before blaming `queryClient.ts`.
|
|
175
182
|
- **⚠ Never verify a catalogue or FIELDS change on a warm browser.** Run `localStorage.removeItem('commerce')` or log out first.
|
|
176
183
|
- **⚠ A cart line's price never refetches** (Zustand, outside React Query).
|
|
@@ -183,8 +190,9 @@ Pinned 2026-09-03 on `TRUE-81610`.
|
|
|
183
190
|
- **`AuthLayout` never remounts**, so `refetchOnMount` fires once per session for queries it owns.
|
|
184
191
|
|
|
185
192
|
## Change history
|
|
193
|
+
- 2026-10-21 — `TRUE-82427` restarted from `_production` as one commit `dccedde1` (pending PR); old branch, PR #376 and its `_sandbox-client` merge gone (reverted `b435def9`). Same scope, plus: Home error page only when the failing query has no data; Home display lists default to `[]`; `AuthLayout` reads client fields directly instead of `useHomeViewModel` (stops the Home queries running on every page); local env-mode testing gotcha. `TRUE-81382` noted off `_sandbox-client` (`df472007`). (tcox)
|
|
186
194
|
- 2026-10-19 — The two open item-page Add to Cart bullets closed by `TRUE-82729`; moved to [cart addItem line merge](./cart-add-item-line-merge.md). (tcox)
|
|
187
|
-
- 2026-10-13 — `TRUE-82427` (
|
|
195
|
+
- 2026-10-13 — `TRUE-82427` first version (old branch, since replaced): per-query `staleTime` / `refetchOnWindowFocus: false` overrides removed, focus refetch on app-wide, guard's explicit opt-in removed, Home refetch fix, item-detail Add to Cart uses refetched price, Home refetch reapplies the submitted search, 81382 merge resolution corrected; four other refetch-ignoring pages logged as open. Countries + 5-min login queries left out of scope. 30s heavy-query shape superseded. (tcox)
|
|
188
196
|
- 2026-10-08 — Bundle queries uncached + excluded from persistence (TRUE-81382); branch map of the two persistence filters; buster live on `_production`. (tcox)
|
|
189
197
|
- 2026-10-01 — Global default already `staleTime: 0`; per-query 24h overrides inventoried; ticket scope agreed. (apeterson)
|
|
190
198
|
- 2026-09-22 — Causes 1 (default) and 2 fixed; login resets client state. TRUE-81991 (`e546db3d`). (apeterson)
|
|
@@ -6,8 +6,8 @@ project: TOGa Commerce
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
10
|
-
owners: ["bala"]
|
|
9
|
+
updated: 2026-10-21
|
|
10
|
+
owners: ["bala", "tcox"]
|
|
11
11
|
files:
|
|
12
12
|
- toga2-commerce/src/components/ErrorMessages/components/FiveHundredContent.tsx
|
|
13
13
|
- toga2-commerce/src/components/ErrorMessages/components/UserSettingsError.tsx
|
|
@@ -37,7 +37,7 @@ In commerce Sentry, `AxiosError: Network Error` means **the browser never reache
|
|
|
37
37
|
## How it works
|
|
38
38
|
|
|
39
39
|
- `FiveHundredContent.tsx:76` renders the literal `CODE: E0-1`.
|
|
40
|
-
- **Case (a), API failure:** `useHomeViewModel.ts` (~L299-331) sets the page error when `assortmentsError` and/or `bundlesError` is set. An error with no status (a string, or a Network Error) defaults to `500`, so it renders the 500 screen inside the layout. Header and welcome banner stay.
|
|
40
|
+
- **Case (a), API failure:** `useHomeViewModel.ts` (~L299-331) sets the page error when `assortmentsError` and/or `bundlesError` is set. An error with no status (a string, or a Network Error) defaults to `500`, so it renders the 500 screen inside the layout. Header and welcome banner stay. On `TRUE-82427` (pending PR) the error counts only when that query has **no data**, so a failed background refetch keeps the cached page — see [catalog cache freshness](./catalog-cache-freshness.md#home-page-must-accept-refetched-data-true-82427).
|
|
41
41
|
- **Case (b), crash:** `routes.tsx:124`, `AuthLayout`'s `errorElement` is `<ErrorMessage errorType={500}/>`. It replaces the whole layout, so no header.
|
|
42
42
|
- `UserSettingsError.tsx` builds other codes as `E<context>-<setting><op>-<status>`; with no error recorded it also falls back to `E0-1`.
|
|
43
43
|
|
|
@@ -58,4 +58,5 @@ In commerce Sentry, `AxiosError: Network Error` means **the browser never reache
|
|
|
58
58
|
- **⚠ Open (not ticketed) — expired sessions land on E0-1 instead of sign-in.** Commerce Sentry, 14 days to 2026-10-14: `Failed to fetch refresh token` 682 events / 576 IPs, `Error fetching assortments (401)` 648 / 581 IPs, `Error fetching bundles (401)` 589 / 531 IPs. The Home 401s show the E0-1 page rather than sending the user back to sign in.
|
|
59
59
|
|
|
60
60
|
## Change history
|
|
61
|
+
- 2026-10-21 — Case (a) note: on `TRUE-82427` the Home error page needs the failing query to have no data. (tcox)
|
|
61
62
|
- 2026-10-16 — Created: E0-1 is hardcoded (API failure vs crash by the header), Network Error = never reached api2, Sentry issue map, `user.ip` search, end-user reachability test, open 401 → E0-1 issue. TRUE-82716 investigation. (bala)
|
|
@@ -57,7 +57,7 @@ An item with **`Items.isActive = 0`** must not be viewable, addable to a cart, o
|
|
|
57
57
|
|
|
58
58
|
**Therefore the gate is on the purchase CONTEXT, never on the flag alone.** The discriminator is whether the line belongs to a kit: `isset($payload->bundleItem)` server-side, the bundle wrapper client-side. Kit lines are never evaluated.
|
|
59
59
|
|
|
60
|
-
> **⚠ Branch state (verified 2026-10-08): two separate implementations exist.** Layers 1-4 (`checkIsItemPurchasable`, `useCartReconciliation`) are on **`_beta` only** — not `_production`, not `_sandbox-client`. Layer 6 (TRUE-81382 submit re-check) was built on `_production`'s base and is on `TRUE-81382` / `
|
|
60
|
+
> **⚠ Branch state (verified 2026-10-08): two separate implementations exist.** Layers 1-4 (`checkIsItemPurchasable`, `useCartReconciliation`) are on **`_beta` only** — not `_production`, not `_sandbox-client`. Layer 6 (TRUE-81382 submit re-check) was built on `_production`'s base and is on `TRUE-81382` / `_qa-task` (reverted off `_sandbox-client` by `df472007`, 2026-10-21; still not `_production`). They **disagree on kit lines and add-ons** (first gotcha). Reconcile them before both reach `_production`.
|
|
61
61
|
|
|
62
62
|
## How it works
|
|
63
63
|
|
|
@@ -128,7 +128,7 @@ Implementation:
|
|
|
128
128
|
- **⚠ OPEN CONFLICT — layer 6 judges kit components and add-on bundles on flags that are off BY DESIGN.** Two checks in `findUnavailableCartItems` misfire:
|
|
129
129
|
1. `bundleItems.item.isActive` — most Compass kit heroes are inactive **on purpose** (Summary table: 87 of 91 primaries on dev-sandbox), so nearly every kit order would block.
|
|
130
130
|
2. `isFlagOff(freshChildEntry.childBundle?.isActive)` — kit add-on bundles (`BundleItems.childBundleId`) are **always** `Bundles.isActive = 0` so they never show as standalone kits on Home. This blocks **every** cart that holds an add-on with "These items are no longer available..." (found 2026-10-21, TRUE-82981).
|
|
131
|
-
Fix before TRUE-81382 (commit `7fcecbf3`, on `
|
|
131
|
+
Fix before TRUE-81382 (commit `7fcecbf3`, on `_qa-task` — reverted off `_sandbox-client` — not `_production`) ships: judge kit lines and add-ons only on the kit line's `BundleItems.isActive` + the parent bundle, never the component item's or the child bundle's own flag. See [granting persona bundle access](../../../clients/compass-usa/workflows/granting-persona-bundle-access.md#kit-add-on-bundles-need-their-own-personas_bundles-grant).
|
|
132
132
|
- **⚠ `Items.isActive = 0` means two different things and nothing distinguishes them.** Never gate on the flag alone. Only a **standalone** line is judged; the kit-membership check (`bundleItem` present / absent) is what makes the flag safe to read.
|
|
133
133
|
- **⚠ A failed lookup must never empty a cart.** `fetchItemsActiveStatus` originally returned `[]` when `data.items` was missing or not an array. Reconciliation reads an empty list as *"every item I asked about is gone"* and clears the cart — so a malformed `200` walked straight past the `try`/`catch` that was supposed to guarantee a lookup failure was harmless. It now **throws**, so the caller's `catch` leaves the cart untouched; a genuine zero-row answer still returns a real empty array. Any "reconcile against the server" routine needs this distinction between *empty* and *unknown*.
|
|
134
134
|
- **⚠ Judge only the uuids you actually queried.** The reconcile `set` filtered the *current* `state.items` against results computed from a snapshot taken **before** the `await`, so a line added while the lookup was in flight was removed without ever being checked. Fixed by scoping the removal to the queried uuid set.
|
|
@@ -139,6 +139,7 @@ Implementation:
|
|
|
139
139
|
- **The server check is one query per order, not per line** — uuids are deduped into a single `IN (…)` lookup, and the empty list returns early because `IN ()` is a MySQL syntax error.
|
|
140
140
|
|
|
141
141
|
## Change history
|
|
142
|
+
- 2026-10-21 — Branch state: `TRUE-81382` reverted off `_sandbox-client` (`df472007`); still on `_qa-task`. (tcox)
|
|
142
143
|
- 2026-10-21 — Layer 6 also blocks every kit add-on (child bundles are inactive by design); fix not yet made. (bala)
|
|
143
144
|
- 2026-10-08 — Added layer 6 (TRUE-81382 submit re-check), branch state, and the open kit-component conflict. (tcox)
|
|
144
145
|
|
|
@@ -38,7 +38,7 @@ The Items table inside the Supply sales order / service request modal: an INTERI
|
|
|
38
38
|
|
|
39
39
|
- **Ordering.** Top-level units sort by line number. Inside a kit, children sort primary → required → other parts and add-ons → fees, keeping original order within each group. An add-on header and its lines are **one group**, so they always stay together.
|
|
40
40
|
- **Add-on header key = the add-on's first order-line uuid**, not the bundle uuid. The same add-on bundle can appear twice on one order; a bundle-uuid key would collide.
|
|
41
|
-
- Add-on lines
|
|
41
|
+
- **Add-on lines keep their real `isPrimary`.** The kit-level "Computer Support" badge and the child sort read only each child group's LEAD row; for an add-on that is the header row, which has no `isPrimary`. So an add-on's own primary part shows its "Computer Support" badge, and nothing leaks to the kit. Do not force `isPrimary = false` in `buildAddOnRows()`; it protects nothing and hides that badge.
|
|
42
42
|
- The developer decision (TRUE-82981): the add-on must match the main kit layout exactly. Do not invent a different style for it.
|
|
43
43
|
|
|
44
44
|
## Gotchas
|
|
@@ -48,3 +48,4 @@ The Items table inside the Supply sales order / service request modal: an INTERI
|
|
|
48
48
|
|
|
49
49
|
## Change history
|
|
50
50
|
- 2026-10-21 — Added the `addOn` tier: add-ons render like the main kit with their parts listed (TRUE-82981, PR #71). (bala)
|
|
51
|
+
- 2026-10-21 — `buildAddOnRows()` no longer forces `isPrimary = false` on add-on lines; badge propagation reads only group lead rows (TRUE-82981, commit `26ac427`, CodeRabbit review). (bala)
|
package/package.json
CHANGED