toga-ai 1.0.780 → 1.0.782
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/dbchanges2/INDEX.md +1 -1
- package/knowledge/2.0/apps/dbchanges2/features/surface-layer-schema.md +104 -1
- package/knowledge/2.0/apps/toga25-supply/INDEX.md +1 -1
- package/knowledge/2.0/apps/toga25-supply/features/column-visibility.md +11 -1
- package/knowledge/2.0/apps/toga25-supply/features/record-modals-and-nested-tables.md +45 -1
- package/knowledge/2.0/apps/toga25-supply/features/surface-frontend.md +100 -1
- package/knowledge/2.0/apps/toga25-supply/features/toolbar-button-chrome.md +26 -1
- package/knowledge/clients/compass-canada/profile.md +8 -0
- package/knowledge/clients/compass-usa/profile.md +10 -0
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [Database Changes (dbchanges2) Repository Architecture](architecture.md) | `dbchanges2` is the **schema-migration / SQL change-set repository** for the entire 2.0 platform. | Core/, Client/, Client_<Tenant>/, Logs/, Logs_Client/, _modules/ |
|
|
6
6
|
| [Re-runnable additive migrations (uuid4 in SQL, INSERT guards, the DISTINCT trap, conditional ALTERs)](features/rerunnable-additive-inserts.md) | Most `dbchanges2` files are **additive data grants** run by hand against production, often more than once (once per environment, or twice because someone was no | dbchanges2/Client_Compass/2026-08-26a - CompassCreativeStudioPersona.sql, dbchanges2/Core/2026-08-27a - Insert - Netsuite Location SyncAll CronJob.sql, dbchanges2/Client/2026-09-01a - PurchaseOrderItemQtyFieldsApiRoleRead.sql |
|
|
7
|
-
| [Surface Layer Schema (UI presentation/config tables)](features/surface-layer-schema.md) | The persistent schema for the platform-wide **Surface** UI presentation/configuration layer (see the `_underscore` [surface-resolver](../../_underscore/features | dbchanges2/Core/2026-09-02a - TalosAssistantSurfaceSeed.sql, dbchanges2/Client_Nychh/2026-09-02a - TalosAssistantEnable.sql, dbchanges2/Core/2026-08-31a - SalesOrderDenialDetailsSurfaceSeed.sql, dbchanges2/Client_Compass/2026-08-31a - SalesOrderDenialDetailsReadOnlyRules.sql, toga25-supply/db-migrations/PLAYBOOK.md, toga25-supply/db-migrations/SURFACE-FEATURE-RUNBOOK.md, dbchanges2/Client_Compass/, dbchanges2/Client_CompassCanada/, dbchanges2/Client_Quad/, dbchanges2/Core/2026-08-28b - TransferOrderListActionsSurfaceSeed.sql, dbchanges2/Core/2026-08-24b - SalesOrderStatusFilterSurfaceSeed.sql, dbchanges2/Client_Compass/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_CompassCanada/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Quad/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Nychh/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Core/2026-08-21 - SalesOrderDecisionSurfacesReseed.sql, dbchanges2/Core/2026-08-24 - RestoreApproveDenyRowActionsVisibility.sql, dbchanges2/Client_Quad/2026-08-24 - ProdPortApprovePoNumberEnabledRule.sql, dbchanges2/Client_Quad/2026-07-21b - ApproveDisabledTooltipPoNumber.sql, dbchanges2/Client_Quad/2026-08-21 - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_CompassCanada/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client_Compass/2026-06-25d - SalesOrderSurfaceClientSeed.sql, _underscore/Model/Client/ThemeToken.php, toga25-supply/src/themeConfig.json, dbchanges2/Core/2026-06-25a - SurfaceCoreTables.sql, dbchanges2/Core/2026-06-25b - SurfaceRecordsAndFields.sql, dbchanges2/Core/2026-06-25c - SalesOrderLoginSurfaceSeed.sql, dbchanges2/Core/2026-06-29a - ItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Core/2026-06-29d - VendorItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29e - InventorySurfaceSeed.sql, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql, dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql, dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql, dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql, dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Core/2026-07-20a - Update - HideAdminNotesSectionByDefault.sql, dbchanges2/Core/2026-07-20b - Update - NotesSectionFieldElements.sql, dbchanges2/Client_Compass/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_Compass/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_Quad/2026-07-20a - NotesSectionFieldsOverride.sql, dbchanges2/Core/2026-07-20c - Update - VendorItemsToggleSurfaceSeed.sql, dbchanges2/Client_Compass/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_Compass/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Core/2026-07-20e - RestoreApproveDenyRowActions.sql, dbchanges2/Client_Compass/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Core/2026-07-17 - README - RUN ORDER.md, dbchanges2/Client_Compass/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Compass/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_CompassCanada/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_CompassCanada/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_Quad/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Quad/2026-07-21b - SalesOrderApproveDisabledTooltipTranslation.sql, dbchanges2/Core/2026-07-21a - SalesOrderDecisionSummarySurfaceSeed.sql, dbchanges2/Core/2026-07-21b - SalesOrderDecisionActionSurfaceSeed.sql, dbchanges2/Client_Quad/2026-07-21c - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Client_CompassCanada/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Core/2026-07-23a - PoNumberDetailFieldValueKey.sql, dbchanges2/Core/2026-07-29a - SalesOrderApprovalDetailsSurfaceSeed.sql, dbchanges2/Core/2026-08-05b - ApprovalDetailsShippingMethodConcatCharge.sql, dbchanges2/Core/2026-08-14a - NoteBadgesVocabularySurface.sql, dbchanges2/Client/2026-08-14a - NoteBadgeThemeTokens.sql, dbchanges2/Client/2026-08-14b - NoteBadgeUserColorFix.sql, dbchanges2/Client_Compass/2026-08-14a - NoteBadgeDelegateThemeTokens.sql, dbchanges2/Client_CompassCanada/2026-08-14a - NoteBadgeDelegateThemeTokens.sql, dbchanges2/Core/2026-08-26a - ServiceRequestRecordHeaderSurfaceSeed.sql, dbchanges2/Core/2026-08-26b - ServiceRequestDetailsSurfaceSeed.sql, dbchanges2/Core/2026-08-28a - TransferOrderSurfaceSeed.sql, dbchanges2/Client/2026-08-28a - TransferOrderStageThemeTokens.sql, dbchanges2/Client_Nychh/2026-08-28b - TransferOrdersNavigationEnable.sql, dbchanges2/Core/2026-09-03c - ColumnsModalSurfaceSeed.sql, dbchanges2/Core/2026-09-03d - ColumnsModalRetireConfigModal.sql |
|
|
7
|
+
| [Surface Layer Schema (UI presentation/config tables)](features/surface-layer-schema.md) | The persistent schema for the platform-wide **Surface** UI presentation/configuration layer (see the `_underscore` [surface-resolver](../../_underscore/features | dbchanges2/Client_Compass/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql, dbchanges2/Client_CompassCanada/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql, dbchanges2/Core/2026-09-03a - TransferOrderStatusBadgeRecordFields.sql, dbchanges2/Core/2026-09-03b - InventoryCreateTransferOrderAction.sql, dbchanges2/Client_Nychh/2026-09-03a - TransferOrdersStatusBadge.sql, dbchanges2/Client_Nychh/2026-09-03b - InventoryCreateTransferOrderShow.sql, dbchanges2/Core/2026-09-02a - TalosAssistantSurfaceSeed.sql, dbchanges2/Client_Nychh/2026-09-02a - TalosAssistantEnable.sql, dbchanges2/Core/2026-08-31a - SalesOrderDenialDetailsSurfaceSeed.sql, dbchanges2/Client_Compass/2026-08-31a - SalesOrderDenialDetailsReadOnlyRules.sql, toga25-supply/db-migrations/PLAYBOOK.md, toga25-supply/db-migrations/SURFACE-FEATURE-RUNBOOK.md, dbchanges2/Client_Compass/, dbchanges2/Client_CompassCanada/, dbchanges2/Client_Quad/, dbchanges2/Core/2026-08-28b - TransferOrderListActionsSurfaceSeed.sql, dbchanges2/Core/2026-08-24b - SalesOrderStatusFilterSurfaceSeed.sql, dbchanges2/Client_Compass/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_CompassCanada/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Quad/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Client_Nychh/2026-08-24b - SalesOrderStatusFilterHides.sql, dbchanges2/Core/2026-08-21 - SalesOrderDecisionSurfacesReseed.sql, dbchanges2/Core/2026-08-24 - RestoreApproveDenyRowActionsVisibility.sql, dbchanges2/Client_Quad/2026-08-24 - ProdPortApprovePoNumberEnabledRule.sql, dbchanges2/Client_Quad/2026-07-21b - ApproveDisabledTooltipPoNumber.sql, dbchanges2/Client_Quad/2026-08-21 - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_CompassCanada/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client_Compass/2026-06-25d - SalesOrderSurfaceClientSeed.sql, _underscore/Model/Client/ThemeToken.php, toga25-supply/src/themeConfig.json, dbchanges2/Core/2026-06-25a - SurfaceCoreTables.sql, dbchanges2/Core/2026-06-25b - SurfaceRecordsAndFields.sql, dbchanges2/Core/2026-06-25c - SalesOrderLoginSurfaceSeed.sql, dbchanges2/Core/2026-06-29a - ItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Core/2026-06-29d - VendorItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29e - InventorySurfaceSeed.sql, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql, dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql, dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql, dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql, dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Core/2026-07-20a - Update - HideAdminNotesSectionByDefault.sql, dbchanges2/Core/2026-07-20b - Update - NotesSectionFieldElements.sql, dbchanges2/Client_Compass/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_Compass/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_Quad/2026-07-20a - NotesSectionFieldsOverride.sql, dbchanges2/Core/2026-07-20c - Update - VendorItemsToggleSurfaceSeed.sql, dbchanges2/Client_Compass/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_Compass/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20c - ItemRecordEditButtonEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20d - ItemRecordVendorItemsEnable.sql, dbchanges2/Core/2026-07-20e - RestoreApproveDenyRowActions.sql, dbchanges2/Client_Compass/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Client_CompassCanada/2026-07-20e - RowActionsApprovalWorkflowAdminEnable.sql, dbchanges2/Core/2026-07-17 - README - RUN ORDER.md, dbchanges2/Client_Compass/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Compass/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_CompassCanada/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_CompassCanada/2026-07-21b - SalesOrderApprovalsGateEnable.sql, dbchanges2/Client_Quad/2026-07-21a - SalesOrderApproveEnabledRuleOverride.sql, dbchanges2/Client_Quad/2026-07-21b - SalesOrderApproveDisabledTooltipTranslation.sql, dbchanges2/Core/2026-07-21a - SalesOrderDecisionSummarySurfaceSeed.sql, dbchanges2/Core/2026-07-21b - SalesOrderDecisionActionSurfaceSeed.sql, dbchanges2/Client_Quad/2026-07-21c - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_Compass/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Client_CompassCanada/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Core/2026-07-23a - PoNumberDetailFieldValueKey.sql, dbchanges2/Core/2026-07-29a - SalesOrderApprovalDetailsSurfaceSeed.sql, dbchanges2/Core/2026-08-05b - ApprovalDetailsShippingMethodConcatCharge.sql, dbchanges2/Core/2026-08-14a - NoteBadgesVocabularySurface.sql, dbchanges2/Client/2026-08-14a - NoteBadgeThemeTokens.sql, dbchanges2/Client/2026-08-14b - NoteBadgeUserColorFix.sql, dbchanges2/Client_Compass/2026-08-14a - NoteBadgeDelegateThemeTokens.sql, dbchanges2/Client_CompassCanada/2026-08-14a - NoteBadgeDelegateThemeTokens.sql, dbchanges2/Core/2026-08-26a - ServiceRequestRecordHeaderSurfaceSeed.sql, dbchanges2/Core/2026-08-26b - ServiceRequestDetailsSurfaceSeed.sql, dbchanges2/Core/2026-08-28a - TransferOrderSurfaceSeed.sql, dbchanges2/Client/2026-08-28a - TransferOrderStageThemeTokens.sql, dbchanges2/Client_Nychh/2026-08-28b - TransferOrdersNavigationEnable.sql, dbchanges2/Core/2026-09-03c - ColumnsModalSurfaceSeed.sql, dbchanges2/Core/2026-09-03d - ColumnsModalRetireConfigModal.sql |
|
|
8
8
|
| [2.0 New-Client Onboarding (manual process)](workflows/client-onboarding.md) | > **A local browser wizard now automates this.** Steps 2–9 below (create DBs, generate Core/API > inserts, append to `Clients_Db.txt`) — plus the dbchanges2 bla | Client/, Client_<Tenant>/, Core/, Logs_Client/ |
|
|
9
9
|
| [Auditing a client DB that drifted from its models (partially applied module migration)](workflows/client-schema-drift-audit.md) | A recurring 2.0 failure mode: **one client's database drifts from what the PHP models declare**, usually because a `_modules/<module>/` migration was applied to | dbchanges2/Client_Growrk/2026-05-28.sql, dbchanges2/Client_Growrk/2026-08-10c - GrowrkServiceRequestCustomFieldsCatchUp.sql, dbchanges2/Client_Growrk/2026-08-10d - GrowrkServiceRequestTypeAndDispositionSeeds.sql, dbchanges2/_modules/netsuite/2026-07-10a - UnitInventoryFields.sql, dbchanges2/Client_Growrk/2026-08-10 - GrowrkUnitInventoryFieldsCatchUp.sql, dbchanges2/Client_Growrk/2026-08-10b - GrowrkUnitItemDescriptionAcl.sql, dbchanges2/Client_Growrk/_modules.txt |
|
|
10
10
|
| [Framework branch running AHEAD of schema — environment-wide 1054/EO-1 after a deploy](workflows/framework-branch-ahead-of-schema.md) | A **third** kind of 2.0 schema drift, distinct from the two already documented: nobody's database went backwards — **the code went forwards**. | _underscore/Model/Core/RecordField.php, _underscore/Model/Client/TableViewField.php, _underscore/Model/Client/TableView.php, _underscore/Model/Core/Surface.php, _underscore/Model/Client/Urgency.php, _underscore/Model/Client/RecordFieldSetting.php, _underscore/Model/Client/ClientRecordFieldSetting.php, api2/Component/Api/V2/V2.php, dbchanges2/Core/2026-08-14c - RecordFieldsValidationMetadata.sql, dbchanges2/Client/2026-08-14a - RecordFieldSettingsClientTable.sql, dbchanges2/Client/2026-08-13a - UserNavPreferencesClientTable.sql, dbchanges2/Client/2026-08-13c - PersonaNavVisibilityClientTable.sql |
|
|
@@ -6,9 +6,15 @@ project: Database Changes
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-04
|
|
10
10
|
owners: [jcardinal, apeterson, tcox]
|
|
11
11
|
files:
|
|
12
|
+
- dbchanges2/Client_Compass/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql
|
|
13
|
+
- dbchanges2/Client_CompassCanada/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql
|
|
14
|
+
- dbchanges2/Core/2026-09-03a - TransferOrderStatusBadgeRecordFields.sql
|
|
15
|
+
- dbchanges2/Core/2026-09-03b - InventoryCreateTransferOrderAction.sql
|
|
16
|
+
- dbchanges2/Client_Nychh/2026-09-03a - TransferOrdersStatusBadge.sql
|
|
17
|
+
- dbchanges2/Client_Nychh/2026-09-03b - InventoryCreateTransferOrderShow.sql
|
|
12
18
|
- dbchanges2/Core/2026-09-02a - TalosAssistantSurfaceSeed.sql
|
|
13
19
|
- dbchanges2/Client_Nychh/2026-09-02a - TalosAssistantEnable.sql
|
|
14
20
|
- dbchanges2/Core/2026-08-31a - SalesOrderDenialDetailsSurfaceSeed.sql
|
|
@@ -143,6 +149,25 @@ per-tenant deltas live in **Client** (mirrors `TableViews`/ACL/`ItemTranslations
|
|
|
143
149
|
`value varchar(255)` + `c_longValue mediumtext`. Precedence **base < client < persona < role**
|
|
144
150
|
with language as an orthogonal overlay; the resolver applies it most-specific-last in one pass.
|
|
145
151
|
|
|
152
|
+
### Which family is this table in? — the cheat sheet a UI-layer migration actually needs
|
|
153
|
+
|
|
154
|
+
Every `.sql` file for a UI-layer change has to be checked statement-by-statement against the
|
|
155
|
+
**cluster-isolation hard rule** (see the [dbchanges2 architecture](../architecture.md)), and the
|
|
156
|
+
tables that come up over and over split cleanly. **Verified placement:**
|
|
157
|
+
|
|
158
|
+
| Family | Tables |
|
|
159
|
+
|---|---|
|
|
160
|
+
| **CORE** | `Records`, `RecordFields`, `Messages`, `Surfaces`, `SurfaceElements`, `Actions`, `Vocabularies`, `VocabularyTerms` |
|
|
161
|
+
| **CLIENT** (per tenant) | `TableViews`, `TableViewJoins`, `TableViewFields`, `AclRecordPermissions` / `AclFieldPermissions` / the rest of `Acl*`, `SurfaceOverrides`, `MessageTranslations`, `ThemeTokens` |
|
|
162
|
+
|
|
163
|
+
Proof for the TableView half, rather than assumption: `_underscore/Model/Client/TableView.php:74`
|
|
164
|
+
declares `database: _underscore::DB_CLIENT`. The Core half is the `Model/Core/*` counterpart.
|
|
165
|
+
|
|
166
|
+
**The practical consequence:** a badge, a button or a column almost always needs **two files** — a
|
|
167
|
+
`Core/` one and a `Client_<Tenant>/` one — and **every Core id the client file needs must be inlined
|
|
168
|
+
as a literal, never sub-selected**. A `SELECT … FROM Core.…` inside a `Client_*` file cannot resolve
|
|
169
|
+
in production and the hook refuses the write.
|
|
170
|
+
|
|
146
171
|
## SurfaceElements — two orthogonal axes + edit-mode columns (one tree serves view + edit)
|
|
147
172
|
|
|
148
173
|
A record modal is modeled as **ONE** set of `<record>-record-*` SECTION surfaces (a header +
|
|
@@ -351,6 +376,36 @@ Both clients' `c`/`d` overrides and the Core seed were added to `Core/2026-07-17
|
|
|
351
376
|
ORDER.md`. Verified working in the UI for both clients. (Boolean toggle/badge labels in this modal
|
|
352
377
|
resolve through the resolver's new `trueLabel`/`falseLabel` emission — see the resolver doc.)
|
|
353
378
|
|
|
379
|
+
### Restrict-to-Persona field — the seed intended a client opt-in that was NEVER WRITTEN (2026-09-04)
|
|
380
|
+
|
|
381
|
+
The same Core-neutral-default → client-opt-in rule, but a case where only **half** of it shipped.
|
|
382
|
+
`Core/2026-07-17d` seeded the item modal's More-Info **`restrictToPersona`** element (surface
|
|
383
|
+
`item-record-more-info` = **19**, `SurfaceElements` id **57**) `isVisible=0` / `isEnabled=0` with
|
|
384
|
+
`config {valueKey: personaItems, computeValueKey: personaItems}`, intending each client to opt in —
|
|
385
|
+
and **no client override was ever authored**. Verified on prod **and** client-sandbox: **zero**
|
|
386
|
+
`SurfaceOverrides` rows for element 57 in `Client_Compass` or `Client_CompassCanada`. Symptom: the
|
|
387
|
+
item modal's "More Info" section header rendered with **no fields** for both Compass tenants (the
|
|
388
|
+
field showed only in edit mode, which is still JSON-driven — see
|
|
389
|
+
[surface-frontend](../../toga25-supply/features/surface-frontend.md)).
|
|
390
|
+
|
|
391
|
+
- **Fix:** `Client_Compass/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql` and
|
|
392
|
+
`Client_CompassCanada/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql` — client-wide
|
|
393
|
+
(`roleId`/`personaId`/`languageId` NULL) `IS_VISIBLE='1'` + `IS_ENABLED='1'` rows for
|
|
394
|
+
`surfaceId` 19 / `surfaceElementId` 57, `NOT EXISTS`-guarded (re-runnable), Core ids **inlined as
|
|
395
|
+
literals** and **pre-generated v4 UUID literals** (never MySQL `UUID()`) — the cluster-isolation
|
|
396
|
+
house style, same shape as `Client_Compass/2026-08-31a`. Ids 19/57 confirmed **identical on prod
|
|
397
|
+
and client-sandbox** Core before authoring.
|
|
398
|
+
- **This element is resolved by literal id, not id-agnostically, on purpose:** it carries no
|
|
399
|
+
`config.role` / `config.kind` marker to match on, and a `Client_*` file cannot read `Core.*`
|
|
400
|
+
across clusters — so the literal id is the only handle. Re-verify 19/57 against the target Core
|
|
401
|
+
before running this in a new environment.
|
|
402
|
+
- **⚠ Ship-together dependency — the FE goes FIRST (or together); this SQL alone CRASHES the modal.**
|
|
403
|
+
Making the field visible exposes a value the FE could not format until the `personaItems`
|
|
404
|
+
`computeValueKey` was registered in `ItemRecordView`; the unformatted array killed the whole modal
|
|
405
|
+
route with React **error #31**. Same class as the approvals-gate / Approve-step-two pair below.
|
|
406
|
+
- **Run state: `client-sandbox` `Client_Compass` only** (override rows 64/65, 2026-09-04 11:25).
|
|
407
|
+
**Prod not run; `Client_CompassCanada` not run anywhere.**
|
|
408
|
+
|
|
354
409
|
## SalesOrder decision-modal surfaces (approve + deny) — shared summary + per-action chrome
|
|
355
410
|
|
|
356
411
|
The approve/deny decision modal's display config was migrated off the per-client
|
|
@@ -840,6 +895,14 @@ rule resumes.
|
|
|
840
895
|
|
|
841
896
|
## Gotchas
|
|
842
897
|
|
|
898
|
+
- **🚨 A reserved-id comment block is NOT evidence.** Repo comments claimed `SurfaceElements`
|
|
899
|
+
reserved through 218; prod's `MAX(id)` was 220 and sandbox-client's was 232 (2026-09-03). Seeds
|
|
900
|
+
using AUTO_INCREMENT + `NOT EXISTS` consume ids invisibly and land differently per environment.
|
|
901
|
+
**Measure `MAX(id)` in every environment before picking a literal.**
|
|
902
|
+
- **`TableViews` / `TableViewJoins` / `TableViewFields` / `Acl*` are CLIENT tables**
|
|
903
|
+
(`_underscore/Model/Client/TableView.php:74` → `DB_CLIENT`); `Records` / `RecordFields` /
|
|
904
|
+
`Messages` / `Surfaces` / `SurfaceElements` are **CORE**. A UI-layer change therefore needs two
|
|
905
|
+
files, and the client file must inline every Core id as a literal.
|
|
843
906
|
- **🚨 SHIP-TOGETHER: `Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql`
|
|
844
907
|
MUST be in the SAME release as `Core/2026-08-21 - SalesOrderDecisionSurfacesReseed.sql`.**
|
|
845
908
|
`Client_Nychh/2026-08-13a` resolved its Core ids via a cross-DB join and **stored the authoring
|
|
@@ -1026,6 +1089,22 @@ exactly (`MAX(Surfaces.id)` 44, `MAX(SurfaceElements.id)` 160) — that was **ve
|
|
|
1026
1089
|
Using literals is still correct: a collision then fails loudly on the primary key instead of silently
|
|
1027
1090
|
mis-wiring (which is what `INSERT IGNORE` did in the 2026-08-24 incident above).
|
|
1028
1091
|
|
|
1092
|
+
#### 🚨 The reserved-id COMMENTS in this repo do not match reality — and they drift PER ENVIRONMENT
|
|
1093
|
+
|
|
1094
|
+
The comment blocks at the top of the seed files are a record of what was **claimed**, not of what is
|
|
1095
|
+
**taken**. Verified 2026-09-03: the repo comments said `SurfaceElements` were reserved through
|
|
1096
|
+
**218**, while `SELECT MAX(id)` returned **220 on production** and **232 on sandbox-client**.
|
|
1097
|
+
|
|
1098
|
+
**Cause:** several seeds insert `SurfaceElements` with **AUTO_INCREMENT behind a `NOT EXISTS`
|
|
1099
|
+
guard** (the purely-additive pattern documented below) rather than with a literal id. Those rows are
|
|
1100
|
+
real and consume ids, but they leave no literal anywhere for a later author to read — and because
|
|
1101
|
+
each environment runs them at a different time against a different ceiling, the ids they land on
|
|
1102
|
+
**differ per environment**.
|
|
1103
|
+
|
|
1104
|
+
> **Rule: measure `MAX(id)` in EVERY environment before picking a literal id.** Never take the
|
|
1105
|
+
> number from a comment block, a change-history entry, or this doc. The two authoring patterns are
|
|
1106
|
+
> both legitimate, but mixing them means the repo can never be an id ledger.
|
|
1107
|
+
|
|
1029
1108
|
#### Ceiling snapshot, verified read-only 2026-08-28 (before reserving the transfer-order block)
|
|
1030
1109
|
|
|
1031
1110
|
| Environment | `MAX(Surfaces.id)` | `MAX(SurfaceElements.id)` | `MAX(Messages.id)` |
|
|
@@ -1342,6 +1421,30 @@ environment and take the **highest** `MAX(id)+1`, never the one in front of you,
|
|
|
1342
1421
|
still unrun at the time, so this is a reservation, not a deployed state.
|
|
1343
1422
|
|
|
1344
1423
|
## Change history
|
|
1424
|
+
- 2026-09-04 — Added the **restrict-to-persona opt-in pair** (`Client_Compass/2026-09-04a` +
|
|
1425
|
+
`Client_CompassCanada/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql`): client-wide
|
|
1426
|
+
`IS_VISIBLE`+`IS_ENABLED` overrides on `surfaceId` **19** / `surfaceElementId` **57**, literal Core
|
|
1427
|
+
ids + v4 UUID literals + `NOT EXISTS` guards. Recorded the failure mode they fix — `Core/2026-07-17d`
|
|
1428
|
+
seeded the element OFF **intending** a per-client opt-in and **no client override was ever written**
|
|
1429
|
+
(zero rows in both Compass tenants, prod and sandbox), so the item modal's More Info section
|
|
1430
|
+
rendered empty. Also recorded the **FE-first ship order**: the override alone exposes an
|
|
1431
|
+
unformatted value and crashes the modal (React error #31). Run on **client-sandbox `Client_Compass`
|
|
1432
|
+
only**; prod and Canada pending. (tcox)
|
|
1433
|
+
- 2026-09-04 — 🚨 **The reserved-id comment blocks in this repo do NOT match reality, and drift per
|
|
1434
|
+
environment.** Comments said `SurfaceElements` were reserved through **218**; `SELECT MAX(id)`
|
|
1435
|
+
returned **220 on production** and **232 on sandbox-client**. Cause: several seeds insert
|
|
1436
|
+
`SurfaceElements` with **AUTO_INCREMENT behind a `NOT EXISTS` guard** instead of a literal id, so
|
|
1437
|
+
the rows consume ids invisibly and land on different numbers in each environment. Rule recorded:
|
|
1438
|
+
**measure `MAX(id)` in every environment before picking a literal** — a comment records a claim,
|
|
1439
|
+
not a reservation. Also added a **verified Core-vs-Client placement cheat sheet** for the tables a
|
|
1440
|
+
UI-layer migration touches (`TableViews`/`TableViewJoins`/`TableViewFields`/`Acl*`/
|
|
1441
|
+
`SurfaceOverrides`/`MessageTranslations`/`ThemeTokens` = **CLIENT**, proven at
|
|
1442
|
+
`_underscore/Model/Client/TableView.php:74` → `DB_CLIENT`; `Records`/`RecordFields`/`Messages`/
|
|
1443
|
+
`Surfaces`/`SurfaceElements`/`Actions`/`Vocabularies`/`VocabularyTerms` = **CORE**), because a
|
|
1444
|
+
badge or button change is almost always a two-file change and every Core id in the client file
|
|
1445
|
+
must be an inlined literal. Confirmed on the transfer-order status badge + Inventory
|
|
1446
|
+
create-transfer-order button seeds (`Core/2026-09-03a`+`b`, `Client_Nychh/2026-09-03a`+`b`), which
|
|
1447
|
+
again followed the Core-seeds-OFF / tenant-opts-in default. (apeterson)
|
|
1345
1448
|
- 2026-09-03 — Recorded the rule that **a modal needing surface-driven copy becomes its own Surface**:
|
|
1346
1449
|
the resolver reads messages only from `*MessageId` columns and never from `config`, so
|
|
1347
1450
|
`Core/2026-08-28b`'s `config.modal` keys could never resolve and the Columns modal rendered raw
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
| [Force Logout on Deployment (useDeploymentGuard)](features/force-logout-on-deployment.md) | On large deployments the backend bumps the Core parameter `META_LAST_REFRESH_DATETIME`. | toga25-supply/src/hooks/useDeploymentGuard.tsx, toga25-supply/src/App.tsx |
|
|
11
11
|
| [Meta-Driven Page & Table Setup](features/meta-driven-table-data.md) | A page in this app is **meta-driven end to end**: the page view model fetches *page meta* (labels, sections, ACL) and *table meta* (the columns/fields + table s | toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/TransferOrders/viewModel/useTransferOrdersPageViewModel.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrdersTableState.ts, toga25-supply/src/hooks/useTablePageMeta.ts, toga-blox-npm/dist/hooks/useFetchPageMeta.d.ts, toga-blox-npm/dist/hooks/useFetchTablePageMeta.d.ts, toga-blox-npm/dist/hooks/useAssignTableFieldLabels.d.ts, toga-blox-npm/dist/components/Table/hooks/useTableData.d.ts |
|
|
12
12
|
| [Persisted React Query cache (localStorage `supply-chain-query-cache`)](features/persisted-query-cache.md) | `localStorage["supply-chain-query-cache"]` is **not a hand-written cache**. | toga25-supply/src/App.tsx, toga25-supply/src/contexts/AuthContext.tsx, toga25-supply/src/hooks/useDeploymentGuard.tsx, toga25-supply/src/fieldsConfig/useClientFields.ts, toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/hooks/useCurrentUser.ts, toga25-supply/src/hooks/useStatusTypeValues.ts, toga25-supply/src/surface/useStatusColors.ts, toga25-supply/vite.config.ts |
|
|
13
|
-
| [Record Modals & Nested Tables](features/record-modals-and-nested-tables.md) | The repo's family of modal + nested-table patterns layered over toga-blox `TableRecordModal` and `PrimaryTable*Layout`. | toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/hooks/usePurchaseOrderDetails.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/FIELDS/apiFields.json, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/layout/PrimaryTableServerLayout/PrimaryTableServerLayout.tsx, toga25-supply/src/layout/PrimaryTableServerLayout/types.ts, toga25-supply/src/layout/ItemRecordModalLayout/, toga25-supply/src/layout/SalesOrderRecordModalLayout/, toga25-supply/src/layout/SalesOrderItemsTableLayout/, toga25-supply/src/layout/ItemFulfillmentModal/, toga25-supply/src/layout/GenericNestedTables/GenericNestedTables.tsx, toga25-supply/src/layout/GenericNestedTables/GenericTableLayout.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/DEFAULT/inventoryGroupings.json, toga25-supply/src/pages/TransferOrders/view/TransferOrderRecordModalLayout/TransferOrderRecordModalLayout.tsx, toga25-supply/src/pages/TransferOrders/helpers/buildInventoryPurchaseOrderUrl.ts, toga25-supply/src/hooks/useTableCellInteractions.ts, toga25-supply/src/hooks/useServerTableUrlState.ts, toga25-supply/src/layout/RecordApprovalModal/helpers/handleFormatApprovalWorkflowPayload.ts, toga25-supply/src/layout/RecordApprovalModal/api/approvalDecisionsApi.ts, toga25-supply/src/layout/RecordApprovalModal/ApprovalModal.module.css |
|
|
13
|
+
| [Record Modals & Nested Tables](features/record-modals-and-nested-tables.md) | The repo's family of modal + nested-table patterns layered over toga-blox `TableRecordModal` and `PrimaryTable*Layout`. | toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/hooks/usePurchaseOrderDetails.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/FIELDS/apiFields.json, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/layout/PrimaryTableServerLayout/PrimaryTableServerLayout.tsx, toga25-supply/src/layout/PrimaryTableServerLayout/types.ts, toga25-supply/src/layout/ItemRecordModalLayout/, toga25-supply/src/layout/SalesOrderRecordModalLayout/, toga25-supply/src/layout/SalesOrderItemsTableLayout/, toga25-supply/src/layout/ItemFulfillmentModal/, toga25-supply/src/layout/ItemFulfillmentModal/useItemFulfillmentModalViewModel.tsx, toga25-supply/src/layout/GenericNestedTables/GenericNestedTables.tsx, toga25-supply/src/layout/GenericNestedTables/GenericTableLayout.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/DEFAULT/inventoryGroupings.json, toga25-supply/src/pages/TransferOrders/view/TransferOrderRecordModalLayout/TransferOrderRecordModalLayout.tsx, toga25-supply/src/pages/TransferOrders/helpers/buildInventoryPurchaseOrderUrl.ts, toga25-supply/src/hooks/useTableCellInteractions.ts, toga25-supply/src/hooks/useServerTableUrlState.ts, toga25-supply/src/layout/RecordApprovalModal/helpers/handleFormatApprovalWorkflowPayload.ts, toga25-supply/src/layout/RecordApprovalModal/api/approvalDecisionsApi.ts, toga25-supply/src/layout/RecordApprovalModal/ApprovalModal.module.css |
|
|
14
14
|
| [Side navigation & default route — an empty nav renders a BLANK PAGE and gets reported as "cannot log in"](features/side-navigation-and-default-route.md) | The 2.5 side nav is **100% backend-driven** by the `navigation` surface bundle, and the same list also decides **which routes exist** and **where `/` lands**. | toga25-supply/src/routes.tsx, toga25-supply/src/layout/AppLayout/viewModel/useAppLayoutViewModel.ts, api2/Component/Api/V2/V2.php, _underscore/Model/Core/Surface.php |
|
|
15
15
|
| [SSO redirect & public-vs-user session gating (useAuthenticationFlow)](features/sso-redirect-and-session-gating.md) | How 2.5 Supply decides, on every navigation, whether an anonymous visitor should be bounced to their client's SSO IdP instead of the local `/login` form. | toga25-supply/src/hooks/useAuthenticationFlow.ts, toga25-supply/src/routes.tsx, toga25-supply/src/contexts/AuthContext.tsx, toga25-supply/src/api/api.ts |
|
|
16
16
|
| [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/layout/RecordApprovalModal/helpers/stackedCurrencyJoiner.ts, toga25-supply/src/layout/RecordApprovalModal/helpers/stackedCurrencyJoiner.test.ts, toga25-supply/src/App.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/DenialBanner.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/SalesOrderRecordModal.module.css, toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/SalesOrderApprovalModalsLayout.tsx, toga25-supply/src/layout/RecordApprovalModal/RecordApprovalModalLayout.tsx, toga25-supply/src/layout/RecordApprovalModal/view/ApprovalTimelineView.tsx, toga25-supply/src/layout/RecordApprovalModal/ApprovalModal.module.css, toga25-supply/src/utils/formatDateTime.ts, toga25-supply/src/utils/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/layout/RecordApprovalModal/, toga25-supply/src/contexts/AuthContext.tsx, toga25-supply/src/surface/applyColSpan.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/sectionRenderers.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getVisibleSections.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderApprovalSummaryGrid.tsx, toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Bundles/viewModel/useBundlesPageViewModel.tsx, toga25-supply/src/layout/ItemFulfillmentModal/useItemFulfillmentModalViewModel.tsx, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/ServiceRequestRecordModalLayout.tsx, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/view/ServiceRequestsView.tsx, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/viewModel/useServiceRequestRecordModalLayoutModel.tsx, toga25-supply/src/pages/ServiceRequests/view/ServiceRequestRecordModalLayout/viewModel/FIELDS/apiFields.json, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderNotesSection.tsx, toga25-supply/src/pages/SalesOrders/helpers/cleanOrder.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/AdminNotesSection.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getAdminNotes.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/resolveElementState.ts, toga25-supply/src/pages/SalesOrders/helpers/evaluateEnableRule.ts, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrderRowRecordState.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/componentRegistry.tsx, toga25-supply/src/surface/SurfaceActionBar.tsx, toga25-supply/src/surface/SurfaceSection.tsx, toga25-supply/src/surface/resolve.ts, toga25-supply/src/surface/types.ts, toga25-supply/src/surface/index.ts, toga25-supply/src/pages/Login/LoginPage.tsx, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/view/SurfaceRowActions.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrderVip.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/Items/ItemsPage.tsx, toga25-supply/src/pages/Items/viewModel/useItemsPageViewModel.tsx, toga25-supply/src/pages/VendorItems/VendorItemsPage.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/Inventory.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/index.ts, toga25-supply/src/fieldsConfig/index.ts, toga25-supply/src/layout/ItemRecordModalLayout/helpers/surfaceBundleToItemFields.ts, toga25-supply/src/layout/ItemRecordModalLayout/helpers/index.ts, toga25-supply/src/layout/ItemRecordModalLayout/viewModel/useItemRecordModalViewModel.tsx, toga25-supply/src/layout/ItemRecordModalLayout/ItemRecordModalLayout.tsx, toga25-supply/src/layout/ItemRecordModalLayout/components/ItemRecordView.tsx, toga25-supply/src/surface/useStatusColors.ts, toga25-supply/src/surface/SurfaceHeader.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/helpers/surfaceBundlesToDecisionFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/viewModel/useApprovalModalViewModel.tsx |
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-04
|
|
10
10
|
owners: [apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/components/ColumnVisibilityModal/
|
|
@@ -187,6 +187,11 @@ leaves a clean URL, and a column added to the meta later still shows up for that
|
|
|
187
187
|
|
|
188
188
|
## Gotchas
|
|
189
189
|
|
|
190
|
+
- **⚠ The six-page `useColumnState` migration cannot be reverted file-by-file.** The shared
|
|
191
|
+
`ColumnVisibilityModalLabels` type gained **required** fields (`shown`, `hidden`, `lockedTip`,
|
|
192
|
+
`pinnedTip`), so restoring an old call site no longer type-checks — the build breaks. Roll the
|
|
193
|
+
whole change back together or not at all. (The dead `columnsButton` return in the SalesOrders view
|
|
194
|
+
model was deleted in the same pass.)
|
|
190
195
|
- **No hardcoded copy in the component** — every user-facing string (incl. Close `aria-label`) is a
|
|
191
196
|
required `labels` prop. On the **legacy** path the fallbacks live in the view model's resolution
|
|
192
197
|
(never in the component or default props); on the **surface** path there are **no fallbacks at
|
|
@@ -211,6 +216,11 @@ leaves a clean URL, and a column added to the meta later still shows up for that
|
|
|
211
216
|
meta later won't appear for an old link until Reset (intended).
|
|
212
217
|
|
|
213
218
|
## Change history
|
|
219
|
+
- 2026-09-04 — ⚠ Recorded that the six-page `useColumnState` migration is **not reversible
|
|
220
|
+
file-by-file**: the shared `ColumnVisibilityModalLabels` type gained required fields (`shown`,
|
|
221
|
+
`hidden`, `lockedTip`, `pinnedTip`), so an old call site no longer type-checks and a partial revert
|
|
222
|
+
breaks the build. Roll it back whole or not at all. The dead `columnsButton` return in the
|
|
223
|
+
SalesOrders view model was removed in the same pass. (apeterson)
|
|
214
224
|
- 2026-09-03 — The modal became **its own MODAL Surface** (`columns-modal`, **Core 60**; Messages
|
|
215
225
|
293–298, SurfaceElements 222–232, `Core/2026-09-03c`). The 08-28 approach was unworkable: the
|
|
216
226
|
resolver only collects messages from `*MessageId` columns and **never scans `config`**, so the
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-04
|
|
10
10
|
owners: [apeterson, tcox, jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/hooks/usePurchaseOrderDetails.ts
|
|
@@ -19,6 +19,7 @@ files:
|
|
|
19
19
|
- toga25-supply/src/layout/SalesOrderRecordModalLayout/
|
|
20
20
|
- toga25-supply/src/layout/SalesOrderItemsTableLayout/
|
|
21
21
|
- toga25-supply/src/layout/ItemFulfillmentModal/
|
|
22
|
+
- toga25-supply/src/layout/ItemFulfillmentModal/useItemFulfillmentModalViewModel.tsx
|
|
22
23
|
- toga25-supply/src/layout/GenericNestedTables/GenericNestedTables.tsx
|
|
23
24
|
- toga25-supply/src/layout/GenericNestedTables/GenericTableLayout.tsx
|
|
24
25
|
- toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx
|
|
@@ -110,6 +111,29 @@ navigation). `ItemFulfillmentModal` sets it because the fulfillment table is rea
|
|
|
110
111
|
scoped so all other `PrimaryTableServerLayout` consumers keep normal row-click behavior — pass it
|
|
111
112
|
only for genuinely read-only tables.
|
|
112
113
|
|
|
114
|
+
### ⚠ `ItemFulfillmentModal`'s `slug` prop IS a TableView slug — and it is still hardcoded to sales orders
|
|
115
|
+
|
|
116
|
+
The shared "Qty Fulfilled" drill-down modal (`src/layout/ItemFulfillmentModal/`) reads as if `slug`
|
|
117
|
+
were a component variant. It is not: **`slug` is a TableView slug**, and the whole modal is built
|
|
118
|
+
from it — `useTablePageMeta({ slug })` supplies the columns and
|
|
119
|
+
`useTableData({ slug, tableViewMeta })` supplies the rows
|
|
120
|
+
(`useItemFulfillmentModalViewModel.tsx`).
|
|
121
|
+
|
|
122
|
+
**No TableView row for that slug → the modal opens EMPTY.** No error, no failed request. Reusing this
|
|
123
|
+
modal for a new record type is therefore a **migration** first, a front-end change second.
|
|
124
|
+
|
|
125
|
+
**Two spots are still hardcoded to sales orders** (blocking reuse as of 2026-09-04):
|
|
126
|
+
|
|
127
|
+
1. **line ~27** — the label fetch always asks for page meta `"item-fulfillments-for-sales-orders"`,
|
|
128
|
+
whatever slug was passed in.
|
|
129
|
+
2. **lines ~55–60** — the record filter falls back to **`"SalesOrders.uuid"`** for any unrecognised
|
|
130
|
+
slug, so a non-sales-order slug filters on the wrong column and returns nothing.
|
|
131
|
+
|
|
132
|
+
**Measured in `Client_Nychh`: only TableViews 12 (`item-fulfillments-for-sales-orders`) and 13
|
|
133
|
+
(`item-fulfillments-for-sales-order-items`) exist, both on `recordId` 29.** There is no
|
|
134
|
+
transfer-order equivalent in any environment — see
|
|
135
|
+
[transfer-orders-page](./transfer-orders-page.md).
|
|
136
|
+
|
|
113
137
|
## Pattern 5 — `GenericNestedTables` (config-driven multi-level / swap tables)
|
|
114
138
|
|
|
115
139
|
A config-driven renderer: declare an array of `TableLevel` objects instead of hand-wiring each
|
|
@@ -323,6 +347,14 @@ Scaffold per the `ItemRecordModalLayout` pattern (`src/layout/ItemRecordModalLay
|
|
|
323
347
|
sees the slide-up animation replay the moment the data arrives. Keep a single modal element and
|
|
324
348
|
switch only its **children** on the fetch state. Same defect and same fix on the ServiceRequest and
|
|
325
349
|
Transfer Order modals.
|
|
350
|
+
- **The item modal's VIEW is Surface-driven while its EDIT is still JSON (Pattern 6).** A field
|
|
351
|
+
that appears only after clicking **Edit** — and vanishes again on Cancel — is a **missing client
|
|
352
|
+
`SurfaceOverride`** on a Core-default-OFF element, not a data or fetch bug. The section header
|
|
353
|
+
then renders with no fields under it. Hit 2026-09-04 on **More Info → "Restrict to Persona"** for
|
|
354
|
+
both Compass tenants. The rule, the `computeValueKey` registry trap it exposed (raw object array →
|
|
355
|
+
React **error #31**, shown as the router's "Unexpected Application Error!" since the app has no
|
|
356
|
+
top-level `ErrorBoundary`), and the FE-first deploy order are in
|
|
357
|
+
[surface-frontend](surface-frontend.md).
|
|
326
358
|
- **A record's child rows may need a SECOND request.** Children nest inside the record response only
|
|
327
359
|
when `Core.InherentRecordChildren` declares them — `sales-orders` does, `transfer-orders` does
|
|
328
360
|
**not**. When they do not, fetch the nested route (`/{record}/{uuid}/{child-route}`) and read the
|
|
@@ -331,6 +363,18 @@ Scaffold per the `ItemRecordModalLayout` pattern (`src/layout/ItemRecordModalLay
|
|
|
331
363
|
[Transfer Orders page](transfer-orders-page.md).
|
|
332
364
|
|
|
333
365
|
## Change history
|
|
366
|
+
- 2026-09-04 — Added the Pattern 6 gotcha that the **item modal's VIEW is Surface-driven while its
|
|
367
|
+
EDIT is still JSON**: a field visible only in edit mode means a missing client `SurfaceOverride`,
|
|
368
|
+
not a data bug (found on Compass's "Restrict to Persona" field). Detail in
|
|
369
|
+
[surface-frontend](surface-frontend.md). (tcox)
|
|
370
|
+
- 2026-09-04 — ⚠ Recorded that **`ItemFulfillmentModal`'s `slug` prop is a TableView slug**, not a
|
|
371
|
+
component variant: `useTablePageMeta`/`useTableData` build the entire modal from it, so a missing
|
|
372
|
+
TableView row opens the modal **empty and silently**. Reusing it for a new record type is a
|
|
373
|
+
migration before it is a front-end change. Also flagged the **two spots still hardcoded to sales
|
|
374
|
+
orders** — the label fetch always requests `item-fulfillments-for-sales-orders` (line ~27) and the
|
|
375
|
+
record filter falls back to `SalesOrders.uuid` for any unrecognised slug (lines ~55–60), so a
|
|
376
|
+
transfer-order slug today filters the wrong column and returns nothing. `Client_Nychh` has only
|
|
377
|
+
TableViews 12/13, both on `recordId` 29; no transfer-order equivalent exists anywhere. (apeterson)
|
|
334
378
|
- 2026-09-03 — Added the **deep-link-from-a-modal-into-a-nested-table** pattern (pin `grouping`;
|
|
335
379
|
build the column-filter chip with the `useServerTableUrlState` serializer, keyed by the table-meta
|
|
336
380
|
**column id**; set `<slug>=<uuid>` to pre-expand the row) and the rule that makes it work:
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-04
|
|
10
10
|
owners: [jcardinal, apeterson, tcox]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/layout/RecordApprovalModal/helpers/stackedCurrencyJoiner.ts
|
|
@@ -341,6 +341,48 @@ in [surface-layer-schema](../../dbchanges2/features/surface-layer-schema.md):
|
|
|
341
341
|
> shows **`leasePrice`** for all clients, whereas the old DEFAULT JSON showed only unit price. Confirm
|
|
342
342
|
> that is the intended seed shape.
|
|
343
343
|
|
|
344
|
+
### ⚠ VIEW is Surface-driven but EDIT is still JSON — a Core-OFF field disappears from view only
|
|
345
|
+
|
|
346
|
+
A field seeded OFF in Core with **no client `SurfaceOverride`** is invisible in VIEW but still
|
|
347
|
+
rendered in EDIT (edit mode reads `itemRecordEditFields.json`). The symptom is a section header with
|
|
348
|
+
**no fields under it**, and the field appearing the moment the user clicks Edit and vanishing again
|
|
349
|
+
on Cancel — which reads like a data bug, not a config gap. Confirmed 2026-09-04 on the item modal's
|
|
350
|
+
**More Info → "Restrict to Persona"** field for Compass USA + Compass Canada: Core (`2026-07-17d`)
|
|
351
|
+
seeds surface `item-record-more-info` element **57** `isVisible=0` / `isEnabled=0` with
|
|
352
|
+
`config {valueKey: personaItems, computeValueKey: personaItems}`, intending a per-client opt-in, but
|
|
353
|
+
**no Compass override was ever written** (verified on prod **and** client-sandbox: zero
|
|
354
|
+
`SurfaceOverrides` rows for element 57 in either tenant). The data was never missing —
|
|
355
|
+
`apiFields.json`'s COMPASS delta already requests `personaItems.*` (see
|
|
356
|
+
[client-api-fetch-fields](client-api-fetch-fields.md)); only the presentation was. Fix = the missing
|
|
357
|
+
override (`Client_Compass` / `Client_CompassCanada` `2026-09-04a`, see
|
|
358
|
+
[surface-layer-schema](../../dbchanges2/features/surface-layer-schema.md)).
|
|
359
|
+
|
|
360
|
+
**Rule:** when a modal's VIEW moves to Surface and its EDIT stays JSON, every Core-default-OFF
|
|
361
|
+
element needs a per-client `SurfaceOverride` or the field silently drops out of view while staying
|
|
362
|
+
editable. "It shows in Edit mode" is evidence of a **missing override**, not of working config.
|
|
363
|
+
|
|
364
|
+
### ⚠ A seed's `computeValueKey` must exist in the consuming view's `COMPUTE_VALUE` registry
|
|
365
|
+
|
|
366
|
+
`ItemRecordView`'s `COMPUTE_VALUE` registry is keyed by the exact string in the surface element's
|
|
367
|
+
`config.computeValueKey`. The Core seed and the legacy per-client JSON can use **different key names
|
|
368
|
+
for the same formatter** — and did: the seed says `personaItems`, the JSON said `personaNames`, and
|
|
369
|
+
only `personaNames` was registered. A missing key is **not** a harmless no-op: `hydrateField`
|
|
370
|
+
produces `computeValue` `undefined`, the raw reshaped array `[{uuid, name, _joinUuid}]` reaches
|
|
371
|
+
`BaseDetailField`, and React throws **error #31** ("Objects are not valid as a React child … keys
|
|
372
|
+
{uuid, name, _joinUuid}"). Because this app has **no top-level `ErrorBoundary`** (see
|
|
373
|
+
[frontend standard](../../../standards/frontend.md)), that surfaces as the router's raw
|
|
374
|
+
**"Unexpected Application Error!"** page — the whole modal route dies, not one field.
|
|
375
|
+
|
|
376
|
+
Fix shape: register the formatter under **both** keys, and make it accept both value shapes.
|
|
377
|
+
`formatPersonaItems` (`ItemRecordView.tsx`) handles the view-model's flat reshaped
|
|
378
|
+
`{uuid, name: "<number> - <name>"}` **and** the raw API nested `{persona: {name, number}}`, and is
|
|
379
|
+
registered as `personaNames` (legacy JSON) **and** `personaItems` (Surface seed). Whenever you seed
|
|
380
|
+
a `computeValueKey`, grep the consuming view's registry for that literal string first.
|
|
381
|
+
|
|
382
|
+
> **Deploy order is load-bearing: FE first, or together — never the SQL first.** The override alone
|
|
383
|
+
> makes the field visible and therefore **crashes the modal**; the FE alone changes nothing visible.
|
|
384
|
+
> Same shape as the approvals-gate ship-together dependency.
|
|
385
|
+
|
|
344
386
|
## SalesOrders approval-decision modal (approve + deny) — migrated via an OVERLAY adapter seam
|
|
345
387
|
|
|
346
388
|
The SalesOrder approve/deny decision modal's config now sources its display fields from Surface,
|
|
@@ -741,8 +783,45 @@ in an edit to the shared blox stylesheet.
|
|
|
741
783
|
⚠ This is **shared infra** — `SurfaceActionBar` renders every migrated screen's chrome, so a change
|
|
742
784
|
here is a cross-screen change. Re-check Sales Orders, Items and Vendor Items after touching it.
|
|
743
785
|
|
|
786
|
+
## Hidden elements ARRIVE in the bundle — every hand-rolled builder must filter on `isVisible`
|
|
787
|
+
|
|
788
|
+
The resolver ships the **whole** element tree and marks state on it; it does **not** prune. So a
|
|
789
|
+
component that maps `bundle.elements` to its own controls **renders elements the Core seed
|
|
790
|
+
deliberately turned off** unless it checks `el.isVisible` itself. `SurfaceActionBar` does this for
|
|
791
|
+
you — a page that builds its own header buttons does not.
|
|
792
|
+
|
|
793
|
+
Found 2026-09-03 on the **Inventory** page: `useInventoryPageViewModel` built its header buttons
|
|
794
|
+
without the filter. It had no symptom only because no hidden element existed on that bar yet; the
|
|
795
|
+
moment `Core/2026-09-03b` seeded the Create Transfer Order button `isVisible = 0`, it would have
|
|
796
|
+
appeared for **every tenant** — defeating the whole Core-neutral-default / tenant-opt-in model. See
|
|
797
|
+
[transfer-orders-page](./transfer-orders-page.md).
|
|
798
|
+
|
|
799
|
+
> **Check for this wherever a view model reads `elements` directly.** `isVisible = 0` is the platform's
|
|
800
|
+
> off switch; ignoring it turns every neutral default into an accidental release.
|
|
801
|
+
|
|
802
|
+
## `useStatusColors` is keyed by `{ route, keyField }` — vocabularies do NOT all key on slug
|
|
803
|
+
|
|
804
|
+
The original hook mapped a vocabulary slug to an API **route** and assumed the term `value` was
|
|
805
|
+
always the record's **slug**. That held for sales orders and breaks for transfer orders:
|
|
806
|
+
`TransferOrderStages` has no slug column, so its `VocabularyTerms.value` holds the stage **NAME**.
|
|
807
|
+
|
|
808
|
+
`src/surface/useStatusColors.ts` therefore keys each vocabulary to a **`{ route, keyField }` pair**,
|
|
809
|
+
and matches the term value against that field of the fetched rows
|
|
810
|
+
(`?fields=slug,name,colorHex`). Adding a third STATUS vocabulary means answering *"what does its
|
|
811
|
+
`VocabularyTerms.value` actually hold?"* before wiring it — a wrong `keyField` produces a badge with
|
|
812
|
+
the right label and no colour, and logs nothing.
|
|
813
|
+
|
|
814
|
+
Full badge chain (`RecordFields.type='STATUS'` → `Records.statusRecordId` → route → typeValues →
|
|
815
|
+
blox `StatusCell`, which is a plain `typeValues[value]` lookup):
|
|
816
|
+
[transfer-orders-page](./transfer-orders-page.md).
|
|
817
|
+
|
|
744
818
|
## Gotchas
|
|
745
819
|
|
|
820
|
+
- **⚠ Hidden elements are IN the bundle** — a hand-rolled control builder that ignores
|
|
821
|
+
`el.isVisible` ships every element the Core seed turned off (see the section above).
|
|
822
|
+
- **⚠ A STATUS badge renders label-but-no-colour when the vocabulary's `keyField` is wrong** —
|
|
823
|
+
`StatusCell` is a plain map lookup on the cell value, so a name against a slug-keyed vocabulary
|
|
824
|
+
just misses, silently.
|
|
746
825
|
- **A vitest file that reaches `@agilant/toga-blox` must stub the whole package:
|
|
747
826
|
`vi.mock("@agilant/toga-blox", () => ({}))`.** blox's `dist` entry imports `global.css`, which
|
|
748
827
|
node's ESM loader rejects, so **any** import chain that transitively pulls blox in fails to load
|
|
@@ -1002,6 +1081,26 @@ claim is about the `navigation-*` **flags** being inert — still true — not a
|
|
|
1002
1081
|
unused).
|
|
1003
1082
|
|
|
1004
1083
|
## Change history
|
|
1084
|
+
- 2026-09-04 — Fixed the item modal's **More Info → "Restrict to Persona"** field missing in VIEW for
|
|
1085
|
+
Compass USA + Canada. Two causes, both now rules here: (1) the item modal's VIEW is Surface-driven
|
|
1086
|
+
while EDIT is still JSON, so a Core-default-OFF element with no client `SurfaceOverride` vanishes
|
|
1087
|
+
from view yet still renders in edit — element **57** on `item-record-more-info` had **zero**
|
|
1088
|
+
override rows in either Compass tenant, on prod and sandbox; (2) the seed's `computeValueKey`
|
|
1089
|
+
(`personaItems`) was missing from `ItemRecordView`'s `COMPUTE_VALUE` registry, which held only the
|
|
1090
|
+
legacy JSON key `personaNames` — so once the field was visible the raw `[{uuid,name,_joinUuid}]`
|
|
1091
|
+
array hit `BaseDetailField` and killed the route with React **error #31**, shown as the router's
|
|
1092
|
+
"Unexpected Application Error!" because the app has no top-level `ErrorBoundary`.
|
|
1093
|
+
`formatPersonaItems` now accepts both value shapes and is registered under both keys. **Deploy the
|
|
1094
|
+
FE first or together — the SQL alone crashes the modal.** (tcox)
|
|
1095
|
+
- 2026-09-04 — Two shared-infra findings from the transfer-order status badge. (1) ⚠ **Hidden
|
|
1096
|
+
elements arrive in the resolved bundle** — the resolver marks state, it never prunes — so any view
|
|
1097
|
+
model that builds its own controls from `bundle.elements` must filter on `el.isVisible`. The
|
|
1098
|
+
Inventory header-button builder did not; it was symptomless only until `Core/2026-09-03b` seeded a
|
|
1099
|
+
deliberately-hidden button, which would then have shown for every tenant. (2) **`useStatusColors`
|
|
1100
|
+
is now keyed by `{ route, keyField }`, not by route alone**: sales-order terms carry the status
|
|
1101
|
+
**slug** but transfer-order terms carry the stage **NAME** (`TransferOrderStages` has no slug
|
|
1102
|
+
column), and a wrong key field yields a correctly-labelled badge with no colour and no log line.
|
|
1103
|
+
(apeterson)
|
|
1005
1104
|
- 2026-09-03 — Recorded that the 2.5 app **still calls `GET /v2/pages/meta`** from five view
|
|
1006
1105
|
models (SalesOrders — twice per load — VendorItems, Inventory, Bundles, ItemFulfillmentModal)
|
|
1007
1106
|
even though nothing in `src/` reads a field off the result. Found by the new Cypress
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-04
|
|
10
10
|
owners: [apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/components/ToolbarButton/ToolbarButton.tsx
|
|
@@ -64,6 +64,24 @@ than by luck with whatever font metrics resolve.
|
|
|
64
64
|
**The "applied" signal never fills the button.** Instead the glyph moves into a small filled rounded
|
|
65
65
|
square — Group by: 18×18, radius 4, `#3F5DCA`, white glyph.
|
|
66
66
|
|
|
67
|
+
### The API — `shape` + `activeAppearance`, generalised from `ColumnsToolbarButton`
|
|
68
|
+
|
|
69
|
+
`ToolbarButton` was **generalised out of the one-off `ColumnsToolbarButton`**, not written fresh, so
|
|
70
|
+
the Columns button is the reference call site.
|
|
71
|
+
|
|
72
|
+
- **`shape`** picks between the two design shapes above: **`pill`** for actions (Refresh, Reset),
|
|
73
|
+
**`chip`** for management controls (Columns, Group by). One component, two shapes — not two
|
|
74
|
+
components.
|
|
75
|
+
- **`activeAppearance`** separates the **transient** active state (pressed / in-flight) from the
|
|
76
|
+
**persistent** one (a filter or grouping is currently applied). They look different by design and
|
|
77
|
+
had previously been conflated, so a button could look permanently "on" after a single click.
|
|
78
|
+
|
|
79
|
+
### Toolbar spacing — `gap-x-2` (8px), not `gap-x-5` (20px)
|
|
80
|
+
|
|
81
|
+
Three labeled-mode pages (Transfer Orders, Sales Orders, Inventory) shipped with `gap-x-5` = **20px**
|
|
82
|
+
between toolbar buttons; the mockup is **8px**. Corrected to `gap-x-2` on all three. Worth stating
|
|
83
|
+
explicitly because 20px looks deliberate rather than wrong until it is next to the design.
|
|
84
|
+
|
|
67
85
|
**Buttons the design does not specify keep `BaseButton`:** PRIMARY create actions, and the Approvals
|
|
68
86
|
filter button (SurfaceElement 22, `config.role = filterButton`), whose navy fill is a clearer "on"
|
|
69
87
|
signal than a chip.
|
|
@@ -84,6 +102,13 @@ signal than a chip.
|
|
|
84
102
|
`Columns (N)` label when the columns differ from default.
|
|
85
103
|
|
|
86
104
|
## Change history
|
|
105
|
+
- 2026-09-04 — Recorded the component's actual API and the spacing fix: `ToolbarButton` was
|
|
106
|
+
**generalised out of `ColumnsToolbarButton`** and takes a **`shape`** prop (`pill` for actions,
|
|
107
|
+
`chip` for management controls) plus an **`activeAppearance`** prop that separates a **transient**
|
|
108
|
+
active state (pressed/in-flight) from a **persistent** one (a filter or grouping is applied) —
|
|
109
|
+
previously conflated, which left a button looking permanently on. Also corrected the toolbar gap
|
|
110
|
+
from `gap-x-5` (20px) to **`gap-x-2` (8px)** on the three labeled-mode pages (Transfer Orders,
|
|
111
|
+
Sales Orders, Inventory) to match the mockup. (apeterson)
|
|
87
112
|
- 2026-09-03 — Created. A page toolbar rendered three buttons at three different heights; the cause is
|
|
88
113
|
that blox `.secondaryBtnAction` hard-codes `height: 26px` with **no theme token**, while
|
|
89
114
|
`.primaryBtn` sets no height at all. Rethemeing would hit every button in the app, so the toolbar
|
|
@@ -98,6 +98,14 @@ to but distinct from Compass USA. Like Compass USA it spans the **2.0** commerce
|
|
|
98
98
|
see [Config-Driven Expedited Shipping Gating](../../2.0/apps/toga2-commerce/features/expedited-shipping-gating.md).
|
|
99
99
|
|
|
100
100
|
## Notes
|
|
101
|
+
- **Item modal "Restrict to Persona" needed a Surface opt-in that was never written (2026-09-04).**
|
|
102
|
+
Same gap as Compass USA: Core seeds the More-Info `restrictToPersona` field **OFF** (surface 19 /
|
|
103
|
+
element 57) and Canada had **no** override, so the item modal's **More Info** section rendered
|
|
104
|
+
empty in view (the field appeared only in Edit mode).
|
|
105
|
+
`dbchanges2/Client_CompassCanada/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql` adds the
|
|
106
|
+
client-wide `IS_VISIBLE`+`IS_ENABLED` rows — **not yet run in any environment**.
|
|
107
|
+
⚠ **Deploy the toga25-supply FE first or together: the SQL alone crashes the modal** (React error
|
|
108
|
+
#31). See [Surface Frontend](../../2.0/apps/toga25-supply/features/surface-frontend.md).
|
|
101
109
|
- **Surface layer (beta):** like Quad, `Client_CompassCanada` had **no** `AclRecordScripts` dispatch
|
|
102
110
|
grant for the surfaces `meta-group` script (only `meta`, to client role 1) → `GET /v2/surfaces/meta-group`
|
|
103
111
|
403'd EZ-1 while `meta` worked. Fixed 2026-07-01 via
|
|
@@ -205,6 +205,16 @@ separate, related client (see its own profile).
|
|
|
205
205
|
the ⚠ rule that **deactivation is raw bulk SQL, so no model hook ever fires on it**.
|
|
206
206
|
|
|
207
207
|
## Notes
|
|
208
|
+
- **Item modal "Restrict to Persona" needed a Surface opt-in that was never written (2026-09-04).**
|
|
209
|
+
Core seeds the item modal's More-Info `restrictToPersona` field **OFF** for every client
|
|
210
|
+
(surface 19 / element 57), expecting a per-client override — Compass USA had **none**, so the
|
|
211
|
+
modal's **More Info** section rendered **empty in view** while the field still showed in Edit
|
|
212
|
+
mode. Fixed by `dbchanges2/Client_Compass/2026-09-04a - ItemRecordRestrictToPersonaVisible.sql`
|
|
213
|
+
(client-wide `IS_VISIBLE`+`IS_ENABLED`). **Run on client-sandbox only — prod pending.**
|
|
214
|
+
⚠ **Deploy the toga25-supply FE first or together: the SQL alone crashes the modal** (React error
|
|
215
|
+
#31, whole modal route). See
|
|
216
|
+
[Surface Frontend](../../2.0/apps/toga25-supply/features/surface-frontend.md) and
|
|
217
|
+
[Surface Layer Schema](../../2.0/apps/dbchanges2/features/surface-layer-schema.md).
|
|
208
218
|
- **Order status is shipped-only (2026-06-30).** Compass imports all IF stages
|
|
209
219
|
(picked/packed/shipped) but its order `_status` (`_underscore/Model/Compass/SalesOrder.php`,
|
|
210
220
|
shared by Compass USA + Canada) counts **shipped only** — picked/packed never advance a Compass
|
package/package.json
CHANGED