toga-ai 1.0.583 → 1.0.585
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/1.0/apps/tools/INDEX.md +1 -1
- package/knowledge/1.0/apps/tools/features/developer-tools.md +25 -5
- package/knowledge/2.0/apps/_underscore/features/surface-resolver.md +39 -0
- package/knowledge/2.0/apps/dbchanges2/INDEX.md +1 -1
- package/knowledge/2.0/apps/dbchanges2/features/surface-layer-schema.md +56 -0
- package/knowledge/2.0/apps/toga-blox/INDEX.md +1 -0
- package/knowledge/2.0/apps/toga-blox/features/add-notes-template.md +68 -0
- package/knowledge/2.0/apps/toga25-supply/INDEX.md +1 -1
- package/knowledge/2.0/apps/toga25-supply/features/surface-frontend.md +40 -0
- package/knowledge/INDEX.md +1 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| [ClickUp Sprint Dashboard (tools /clickup/react)](features/clickup-sprint-dashboard.md) | A native **ClickUp sprint dashboard** in the 1.0 `tools` app at route `/clickup/react`, built for a wall-mounted **TV display** ("TOGa IQ" internal sprint metri | tools/_/app/clickup/sprint.php, tools/v2/sprints/tile/index.php, tools/v2/sprints/current/index.php, tools/v2/sprints/status-breakdown/index.php, tools/v2/sprints/worktype-breakdown/index.php, tools/v2/sprints/points-by-dev/index.php, tools/v2/sprints/burndown/index.php, tools/assets/clickup/sprint-dashboard.html, tools/mvc/clickup/react/get.php, tools/mvc/login/get.php, tools/_/app/nav.php |
|
|
7
7
|
| [CloudFront Client Setup](features/cloudfront-client-setup.md) | An SSO-gated admin tool at **`/devops/cloudfront-clients`** in the Tools 1.0 app that onboards a client onto **CloudFront + Route 53 across multiple AWS account | tools/_/app/devops/cloudfront.php, tools/mvc/devops/cloudfront-clients/get.php, tools/mvc/devops/cloudfront-clients/post.php, tools/assets/js/cloudfront-clients.js, tools/assets/css/cloudfront-clients.css, tools/_/app/nav.php, tools/_/app/frameworkindex.php, tools/config.production.ini |
|
|
8
8
|
| [Design Demo Admin](features/design-demo-admin.md) | A self-serve admin UI at **`/design`** in the SSO-protected **Tools** app that lets the design team publish self-contained "Claude Design" HTML exports as **ver | tools/_/app/design/github.php, tools/mvc/design/get.php, tools/mvc/design/post.php, tools/assets/css/design.css, tools/assets/js/design.js, tools/_/app/frameworkindex.php, tools/_/app/nav.php, tools/composer.json |
|
|
9
|
-
| [Tools — Developers Folder (UUID & Password Generators)](features/developer-tools.md) | The first two tools shipped in the Tools app, both under the **Developers** folder and gated to personas **Development Team** / **TOGa Technology**. | tools/mvc/developers/uuid/get.php, tools/mvc/developers/password/get.php |
|
|
9
|
+
| [Tools — Developers Folder (UUID & Password Generators)](features/developer-tools.md) | The first two tools shipped in the Tools app, both under the **Developers** folder and gated to personas **Development Team** / **TOGa Technology**. | tools/mvc/developers/uuid/get.php, tools/mvc/developers/password/get.php, tools/mvc/developers/password/post.php |
|
|
10
10
|
| [/errors Curation Console (Tools → shared Core Logs DB)](features/errors-curation-console.md) | Internal-only triage/curation screen for the 2.0 Issue/Event error-reporting pipeline, built as a 1.0 Tools MVC page reading the **shared Core Logs DB** through | tools/mvc/errors/get.php, tools/mvc/errors/post.php, tools/mvc/errors/issue/get.php, tools/assets/css/style.css, tools/_/app/nav.php, tools/config.production.ini |
|
|
11
11
|
| [Legacy Email Notifier (tools /email-migration/notify)](features/legacy-email-notifier.md) | An SSO-gated admin tool at **`/email-migration/notify`** (nav group **Email Migration** > **Legacy Notifier**, personas `['TOGa Technology','Development Team']` | tools/mvc/email-migration/notify/get.php, tools/mvc/email-migration/notify/post.php, tools/_/app/nav.php |
|
|
12
12
|
| [Tools MVC — Routing, CSRF & App_Database Access Patterns](features/mvc-data-access-patterns.md) | The load-bearing 1.0 (`App_`) framework conventions a developer needs when adding a page to the Tools app — URL routing, CSRF, and DB access through `App_Databa | tools/_/app/nav.php, tools/mvc/get.php, library/app/error.php, library/app/database.php |
|
|
@@ -6,14 +6,16 @@ project: Tools
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
9
|
+
updated: 2026-08-14
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- tools/mvc/developers/uuid/get.php
|
|
13
13
|
- tools/mvc/developers/password/get.php
|
|
14
|
+
- tools/mvc/developers/password/post.php
|
|
14
15
|
related:
|
|
15
16
|
- ../architecture.md
|
|
16
17
|
- ./persona-gated-navigation.md
|
|
18
|
+
- ./mvc-data-access-patterns.md
|
|
17
19
|
---
|
|
18
20
|
|
|
19
21
|
## Summary
|
|
@@ -28,10 +30,28 @@ personas **Development Team** / **TOGa Technology**. They are the reference exam
|
|
|
28
30
|
- Server generates an RFC 4122 **v4** UUID via `random_bytes(16)` with version/variant bits set.
|
|
29
31
|
- UI is click-to-copy, then instant **client-side** regenerate using `crypto.getRandomValues`.
|
|
30
32
|
|
|
31
|
-
### Generate Password (`mvc/developers/password/get.php`)
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
produces the bcrypt hash. The page shows **both** the
|
|
33
|
+
### Generate Password (`mvc/developers/password/get.php` + `post.php`)
|
|
34
|
+
- **Random support-code card (default, on page load):** reproduces the standalone
|
|
35
|
+
`test/team/generate_password.php` script. `App_String::generateSupportCode(8)` produces the
|
|
36
|
+
password; `App_String::passwordHash()` produces the bcrypt hash. The page shows **both** the
|
|
37
|
+
password and the hash, each copyable. Unchanged.
|
|
38
|
+
- **Hash-your-own-password card:** the user types a password and gets its bcrypt hash without a
|
|
39
|
+
full page reload. bcrypt cannot run client-side, so the UI `fetch`es a sibling
|
|
40
|
+
`post.php` — the framework routes any non-GET for `/developers/password` to
|
|
41
|
+
`mvc/developers/password/post.php` (folder == route 1:1). `post.php` exposes one JSON action
|
|
42
|
+
`hash`, guarded with the standard tools pair `App_Auth::requireAuth()` then
|
|
43
|
+
`App_Page::validateCrossSiteRequestForgery()`. That CSRF check is **Origin/Referer-based, not
|
|
44
|
+
a token**, so a same-origin `fetch` passes with no embedded token (see
|
|
45
|
+
[mvc-data-access-patterns](./mvc-data-access-patterns.md)).
|
|
46
|
+
- **Security discipline:** the clear-text password is **never logged or persisted**. A
|
|
47
|
+
`MAX_PASSWORD_BYTES = 4096` guard bounds input, and the endpoint returns a `truncated` flag
|
|
48
|
+
because bcrypt only consumes the first 72 bytes — the UI shows a note when that is exceeded.
|
|
49
|
+
|
|
50
|
+
## Gotcha — bcrypt's 72-byte limit
|
|
51
|
+
`password_hash`/`App_String::passwordHash()` silently ignores everything past the first **72
|
|
52
|
+
bytes** of the input. The hash-your-own card surfaces this to the user (`truncated` flag + UI
|
|
53
|
+
note) rather than letting a longer password appear to "work" while extra characters are dead.
|
|
35
54
|
|
|
36
55
|
## Change history
|
|
56
|
+
- 2026-08-14 — Added a "hash your own password" card to the Generate Password tool: a new sibling `mvc/developers/password/post.php` exposes one JSON `hash` action (requireAuth + Origin/Referer CSRF), so the UI bcrypt-hashes user-typed input via `fetch` without a page reload; clear-text is never logged/persisted, `MAX_PASSWORD_BYTES=4096` guard, and a `truncated` flag surfaces bcrypt's 72-byte limit. Also fixed missing inter-card spacing by adding a `tool--password` wrapper modifier + `.tool--password .card { margin-bottom }` (mirroring `.tool--errors`; note style.scss is dead — edit style.css directly). (jcardinal)
|
|
37
57
|
- 2026-06-25 — Built the first two Developers tools: RFC 4122 v4 UUID generator and a password+bcrypt-hash generator (ported from test/team/generate_password.php), both gated to Development Team / TOGa Technology personas (jcardinal)
|
|
@@ -142,6 +142,36 @@ breaks logic.
|
|
|
142
142
|
> LABEL_MESSAGE` value stores a **message id** or a **raw message key** is not yet confirmed. Verify
|
|
143
143
|
> against `Model/Core/Surface.php` `_loadOverrides`/`_buildBundle` before relying on either form.
|
|
144
144
|
|
|
145
|
+
## Vocabulary emission is ELEMENT-DRIVEN (surfacing a vocabulary with no visible UI)
|
|
146
|
+
|
|
147
|
+
A vocabulary is emitted into the bundle (`bundle.vocabularies[<slug>]`) **only if a resolved
|
|
148
|
+
`SurfaceElement` on that surface references its `vocabularyId`** — the resolver batch-loads
|
|
149
|
+
`Vocabularies`+`VocabularyTerms` for *referenced* ids only (step 5), so an unreferenced vocabulary
|
|
150
|
+
never ships. **Pattern to surface a vocabulary that has no visible widget:** add a **hidden
|
|
151
|
+
(`isVisible=0`) carrier `SurfaceElement`** tagged via `config.role` whose only job is to reference the
|
|
152
|
+
`vocabularyId`. The Admin Notes component uses two such carriers on the `admin-notes` surface
|
|
153
|
+
(`config.role` = `noteBadges` / `notesChrome`) so the `note-badges` and `notes-chrome` vocabularies
|
|
154
|
+
emit even though neither renders a control itself. Seed side:
|
|
155
|
+
[surface-layer-schema](../../dbchanges2/features/surface-layer-schema.md).
|
|
156
|
+
|
|
157
|
+
## Vocabulary TERMS are Core-global — there is NO per-client term gating
|
|
158
|
+
|
|
159
|
+
`SurfaceOverrides` keys only on **`surfaceElementId`** — never on a `VocabularyTerm`. So a Vocabulary
|
|
160
|
+
and all its terms live in **Core** and are the same for every tenant; a client **cannot** hide or add
|
|
161
|
+
a term. Per-client differentiation of a Core-global vocabulary is therefore achieved two other ways,
|
|
162
|
+
**not** by term gating:
|
|
163
|
+
|
|
164
|
+
1. **Data presence** — only the tenants that generate a given value ever surface it (e.g. only
|
|
165
|
+
Compass / Compass Canada generate `delegate` notes, so only they show the delegate badge).
|
|
166
|
+
2. **Per-tenant `ThemeTokens`** — a term references a **theme-token SLUG** (e.g. `color.note.delegate`
|
|
167
|
+
/ `bg.note.delegate`) which resolves to hex **per tenant** via `Client.ThemeTokens` → `bundle.theme`.
|
|
168
|
+
A token seeded only in Compass / Compass Canada gives those tenants the color; other tenants simply
|
|
169
|
+
have no such token.
|
|
170
|
+
|
|
171
|
+
This let the FE delete its hardcoded `DELEGATE_NOTE_CLIENT_SLUGS` allowlist entirely (see
|
|
172
|
+
[surface-frontend](../../toga25-supply/features/surface-frontend.md)) — client scope became data +
|
|
173
|
+
theme tokens, not code.
|
|
174
|
+
|
|
145
175
|
## Caching & invalidation
|
|
146
176
|
|
|
147
177
|
- Disk cache keyed `surface:meta:{app}:{slug}:{client}:{sortedPersonaIds}:{sortedRoleIds}:{lang}`.
|
|
@@ -432,6 +462,15 @@ Core record grants + their logic-group expressions all evaluate `all`/`"1"`. The
|
|
|
432
462
|
match Compass, a follow-up migration aligning both `meta` and `meta-group` to roles 1,3,4 is needed.
|
|
433
463
|
|
|
434
464
|
## Change history
|
|
465
|
+
- 2026-08-14 — Documented two durable resolver mechanics surfaced by the Admin Notes migration:
|
|
466
|
+
(1) **vocabulary emission is element-driven** — a vocabulary emits only if a resolved element
|
|
467
|
+
references its `vocabularyId`, so the pattern to surface a UI-less vocabulary is a **hidden carrier
|
|
468
|
+
element** tagged via `config.role` (Admin Notes uses `noteBadges`/`notesChrome` carriers on the
|
|
469
|
+
`admin-notes` surface); (2) **vocabulary TERMS are Core-global — no per-client term gating**
|
|
470
|
+
(`SurfaceOverrides` keys on `surfaceElementId`, never a term), so per-client differentiation of a
|
|
471
|
+
Core-global vocab is by **data presence** + **per-tenant `ThemeTokens`** (token slug → hex per
|
|
472
|
+
tenant), not by hiding terms. This let the FE delete its hardcoded `DELEGATE_NOTE_CLIENT_SLUGS`
|
|
473
|
+
allowlist. (apeterson)
|
|
435
474
|
- 2026-08-14 — **Discovered/documented** why a surface meta request returns an empty bundle
|
|
436
475
|
(`surface:null`, empty elements/vocabularies/messages/theme): `_buildBundle()` short-circuits when the
|
|
437
476
|
slug-only `Surfaces` load fails, and the lookup filters by slug ONLY (no appId/isVisible/client/role/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
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
|
-
| [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/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 |
|
|
6
|
+
| [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/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 |
|
|
7
7
|
| [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/ |
|
|
8
8
|
| [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 |
|
|
9
9
|
| [Local vs prod MySQL config parity — why “it passed locally” is not evidence](workflows/local-vs-prod-mysql-config-parity.md) | Several migration failures that look like "prod-only bugs" are actually **per-machine MySQL server-configuration differences**. | |
|
|
@@ -68,6 +68,11 @@ files:
|
|
|
68
68
|
- dbchanges2/Core/2026-07-23a - PoNumberDetailFieldValueKey.sql
|
|
69
69
|
- dbchanges2/Core/2026-07-29a - SalesOrderApprovalDetailsSurfaceSeed.sql
|
|
70
70
|
- dbchanges2/Core/2026-08-05b - ApprovalDetailsShippingMethodConcatCharge.sql
|
|
71
|
+
- dbchanges2/Core/2026-08-14a - NoteBadgesVocabularySurface.sql
|
|
72
|
+
- dbchanges2/Client/2026-08-14a - NoteBadgeThemeTokens.sql
|
|
73
|
+
- dbchanges2/Client/2026-08-14b - NoteBadgeUserColorFix.sql
|
|
74
|
+
- dbchanges2/Client_Compass/2026-08-14a - NoteBadgeDelegateThemeTokens.sql
|
|
75
|
+
- dbchanges2/Client_CompassCanada/2026-08-14a - NoteBadgeDelegateThemeTokens.sql
|
|
71
76
|
related:
|
|
72
77
|
- ../../_underscore/features/surface-resolver.md
|
|
73
78
|
---
|
|
@@ -366,6 +371,45 @@ The `category` enum already includes `SPACING`/`RADIUS`/`TYPOGRAPHY`/`ICON`, so
|
|
|
366
371
|
the foundation into `ThemeTokens` rows is the target end-state (see the theming-architecture
|
|
367
372
|
decision, held for senior review).
|
|
368
373
|
|
|
374
|
+
## Admin Notes component — whole component surface-driven (note-badges + notes-chrome, 2026-08-14)
|
|
375
|
+
|
|
376
|
+
The Sales Order **Admin Notes** component (badges, chrome labels, toggles, colors) was moved out of the
|
|
377
|
+
hardcoded FE `addNotesFields.json` into Surface. Seed:
|
|
378
|
+
`Core/2026-08-14a - NoteBadgesVocabularySurface.sql`. FE adapter side:
|
|
379
|
+
[surface-frontend](../../toga25-supply/features/surface-frontend.md).
|
|
380
|
+
|
|
381
|
+
- **`note-badges` vocabulary** — terms `admin` / `user` / `delegate`, each carrying a **theme-token
|
|
382
|
+
SLUG** pair (`color.note.<term>` / `bg.note.<term>`) resolved to hex per tenant via
|
|
383
|
+
`Client.ThemeTokens` (**not** a literal hex in Core).
|
|
384
|
+
- **`notes-chrome` vocabulary** — 8 terms = chrome label slots (`viewAll` / `addNote` / `placeholder` /
|
|
385
|
+
`cancel` / `publish` / `modalTitle` / `modalClose` / `noteCount`), each pointing at a `Message`.
|
|
386
|
+
- **Two hidden carrier `SurfaceElements`** on the `admin-notes` surface (`config.role` =
|
|
387
|
+
`noteBadges` / `notesChrome`), `isVisible=0`, whose only job is to reference each vocabulary so the
|
|
388
|
+
**element-driven emission** ships it (see the resolver doc — a vocabulary emits only if a resolved
|
|
389
|
+
element references its `vocabularyId`).
|
|
390
|
+
- **Chrome toggles** (`showViewAllButton` / `showBottomNoteCount` / `notesPlacementBottom` /
|
|
391
|
+
`modalCloseIcon`) are merged onto the `admin-notes` `surface.config` via **`JSON_MERGE_PATCH`**.
|
|
392
|
+
|
|
393
|
+
**Per-client scope is data + tokens, NOT term gating.** Vocabulary terms are Core-global (see the
|
|
394
|
+
resolver doc); the delegate badge is scoped to Compass / Compass Canada by (a) only those tenants
|
|
395
|
+
generating `delegate` notes and (b) a per-tenant `delegate` ThemeToken — so the FE's hardcoded
|
|
396
|
+
`DELEGATE_NOTE_CLIENT_SLUGS` allowlist was deleted.
|
|
397
|
+
|
|
398
|
+
### NoteBadge ThemeTokens (per-tenant hex)
|
|
399
|
+
Badge colors live in each tenant's `Client.ThemeTokens` (`slug → hex`), keyed by the `color.note.*` /
|
|
400
|
+
`bg.note.*` slugs the `note-badges` terms reference:
|
|
401
|
+
|
|
402
|
+
- `Client/2026-08-14a - NoteBadgeThemeTokens.sql` — generic **admin + user** tokens for **all** clients.
|
|
403
|
+
- `Client_Compass/2026-08-14a - NoteBadgeDelegateThemeTokens.sql` +
|
|
404
|
+
`Client_CompassCanada/2026-08-14a - NoteBadgeDelegateThemeTokens.sql` — the **delegate** color, only
|
|
405
|
+
for those two tenants.
|
|
406
|
+
- **User-badge color fix (sapphire, per Figma).** `user` was a placeholder zinc; corrected to sapphire
|
|
407
|
+
(`#194885` text / `#E6EEF7` bg). Because a **seeded ThemeToken value overrides the FE fallback
|
|
408
|
+
palette**, the stale zinc had to be fixed in the DB, not just the FE: `Client/2026-08-14a` was folded
|
|
409
|
+
to sapphire for fresh installs, and `Client/2026-08-14b - NoteBadgeUserColorFix.sql` UPDATEs
|
|
410
|
+
already-run tenant DBs. (The FE keeps a fallback palette matching the seeded values so the component
|
|
411
|
+
renders identically before migrations run.)
|
|
412
|
+
|
|
369
413
|
## Migration files (typed columns, not EAV)
|
|
370
414
|
|
|
371
415
|
CREATE order is FK-safe (`Messages → Actions → Vocabularies → VocabularyTerms → Surfaces →
|
|
@@ -536,6 +580,18 @@ rule resumes.
|
|
|
536
580
|
override is added). **Open follow-up.**
|
|
537
581
|
|
|
538
582
|
## Change history
|
|
583
|
+
- 2026-08-14 — Moved the whole Sales Order **Admin Notes** component into Surface
|
|
584
|
+
(`Core/2026-08-14a - NoteBadgesVocabularySurface.sql`): a `note-badges` vocabulary (terms
|
|
585
|
+
admin/user/delegate, each carrying `color.note.*`/`bg.note.*` theme-token slugs), a `notes-chrome`
|
|
586
|
+
vocabulary (8 chrome label slots → Messages), two hidden carrier `SurfaceElements` on `admin-notes`
|
|
587
|
+
(`config.role`=noteBadges/notesChrome) that reference each vocab so element-driven emission ships it,
|
|
588
|
+
and chrome toggles merged onto `surface.config` via `JSON_MERGE_PATCH`. Per-tenant badge colors seeded
|
|
589
|
+
in `Client.ThemeTokens`: generic admin+user for all clients (`Client/2026-08-14a`), delegate only for
|
|
590
|
+
Compass + Compass Canada (`Client_Compass`/`Client_CompassCanada/2026-08-14a`). Fixed the user badge to
|
|
591
|
+
sapphire per Figma — folded into `Client/2026-08-14a` for fresh installs plus
|
|
592
|
+
`Client/2026-08-14b - NoteBadgeUserColorFix.sql` to UPDATE already-run tenant DBs (a seeded ThemeToken
|
|
593
|
+
overrides the FE fallback, so the stale zinc had to be corrected in the DB). Per-client scope is data
|
|
594
|
+
presence + per-tenant tokens, not term gating (terms are Core-global). (apeterson)
|
|
539
595
|
- 2026-08-14 — Recorded a durable idempotency-guard gotcha (below): a `SurfaceElements` seed
|
|
540
596
|
guard keyed on `config.valueKey` is defeated by any later migration that mutates that same
|
|
541
597
|
valueKey, causing duplicate element inserts on re-run. Concrete case: `Core/2026-07-29a`
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [TOGa Blox (toga-blox) Architecture](architecture.md) | `toga-blox` (npm package **`@agilant/toga-blox`**) is the **shared React + TypeScript component / template / utility library** reused across the 2.0 frontends — | toga-blox/package.json, toga-blox/src/components/index.ts, toga-blox/src/api/index.ts, toga-blox/src/templates/index.ts |
|
|
6
|
+
| [AddNotes template — badge style/label decoupling & Badge style passthrough](features/add-notes-template.md) | The `@agilant/toga-blox` `AddNotesTemplate` renders a list of notes, each with a per-note contact **badge** (e.g. | toga-blox-npm/src/templates/AddNotes/types.ts, toga-blox-npm/src/templates/AddNotes/AddNotesTemplate.tsx, toga-blox-npm/src/components/Badge/Badge.types.tsx, toga-blox-npm/src/components/Badge/Badge.tsx |
|
|
6
7
|
| [AdvancedSelect (virtualized single/multi select)](features/advanced-select.md) | `AdvancedSelect<T>` is a **fully controlled, virtualized** single/multi select built from scratch (not react-select) on **`@tanstack/react-virtual`**, for large | toga-blox/src/components/AdvancedSelect/AdvancedSelect.tsx, toga-blox/src/components/AdvancedSelect/AdvancedSelect.types.ts, toga-blox/src/components/AdvancedSelect/AdvancedSelect.module.css |
|
|
7
8
|
| [API client (axios wrapper, auth, table-data fetchers)](features/api-client.md) | `src/api/` is a thin **axios** wrapper that standardizes the **2.0 API envelope**, manages auth (Bearer + refresh), serializes complex query options, and provid | toga-blox/src/api/index.ts, toga-blox/src/api/axiosInstance.ts, toga-blox/src/api/apiFunctions.ts, toga-blox/src/api/auth.ts, toga-blox/src/api/genericApi.ts, toga-blox/src/api/types.ts, toga-blox/src/api/tableData |
|
|
8
9
|
| [BaseInput (react-hook-form field factory)](features/base-input.md) | `BaseInput` is a **form-field factory** driven by react-hook-form. | toga-blox/src/components/BaseInput/BaseInput.tsx, toga-blox/src/components/BaseInput/BaseInput.types.ts, toga-blox/src/components/BaseInput/BaseInput.module.css, toga-blox/src/components/BaseInput/components |
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AddNotes template — badge style/label decoupling & Badge style passthrough
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: toga-blox
|
|
5
|
+
project: TOGa Blox
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-14
|
|
10
|
+
owners: [apeterson]
|
|
11
|
+
files:
|
|
12
|
+
- toga-blox-npm/src/templates/AddNotes/types.ts
|
|
13
|
+
- toga-blox-npm/src/templates/AddNotes/AddNotesTemplate.tsx
|
|
14
|
+
- toga-blox-npm/src/components/Badge/Badge.types.tsx
|
|
15
|
+
- toga-blox-npm/src/components/Badge/Badge.tsx
|
|
16
|
+
related:
|
|
17
|
+
- ../../toga25-supply/features/surface-frontend.md
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## What it is
|
|
21
|
+
|
|
22
|
+
The `@agilant/toga-blox` `AddNotesTemplate` renders a list of notes, each with a per-note contact
|
|
23
|
+
**badge** (e.g. `Admin` / `User` / `Delegate Manager Updated`). This doc covers the durable
|
|
24
|
+
component contract used by the Surface-driven Admin Notes component in toga25-supply (adapter:
|
|
25
|
+
[surface-frontend](../../toga25-supply/features/surface-frontend.md)).
|
|
26
|
+
|
|
27
|
+
## Badge style/label are DECOUPLED — `badgeVariant` is the style key, `badgeTitle` is the label
|
|
28
|
+
|
|
29
|
+
Originally the template used **`note.contact.badgeTitle` as BOTH** the visible label **and** the
|
|
30
|
+
`badgeStyles[]` lookup key. So relabeling a badge (e.g. `"Delegate"` → `"Delegate Manager Updated"`)
|
|
31
|
+
silently **orphaned its style** — the style map no longer had a key matching the new label, and the
|
|
32
|
+
badge rendered unstyled. This was the root cause of the original reported bug.
|
|
33
|
+
|
|
34
|
+
- **`badgeVariant`** (optional, `types.ts`) is now the **stable style-lookup key**; it **falls back to
|
|
35
|
+
`badgeTitle`** when unset (backward-compatible). `badgeStyles[]` is keyed by `badgeVariant`.
|
|
36
|
+
- **`badgeTitle`** is now **only** the displayed label and can be relabeled freely without breaking
|
|
37
|
+
the style.
|
|
38
|
+
|
|
39
|
+
**Rule:** anything that looks a badge up by identity (style, color, theme token) keys on the stable
|
|
40
|
+
**variant**, never the human label. This mirrors the Surface layer's "slug is internal identity,
|
|
41
|
+
Message is the label" separation.
|
|
42
|
+
|
|
43
|
+
## Two-badge layout — `contact.badges[]`
|
|
44
|
+
|
|
45
|
+
Delegate notes render **two badges side by side** (`[User][Delegate Manager Updated]`, per Figma). The
|
|
46
|
+
template now accepts a `contact.badges[]` **array** (each entry `{badgeTitle, badgeVariant, ...}`) and
|
|
47
|
+
renders them in order, and remains **back-compatible** with the single `badgeTitle`/`badgeVariant`
|
|
48
|
+
shape. The consuming app (toga25-supply `getAdminNotes.ts`) composes the array from a
|
|
49
|
+
`NOTE_BADGE_COMPOSITION` map (delegate → `[user, delegate]`) and resolves each variant's label + color
|
|
50
|
+
from the Surface bundle.
|
|
51
|
+
|
|
52
|
+
## `Badge` inline `style` passthrough
|
|
53
|
+
|
|
54
|
+
`Badge` previously accepted only `className` strings. A **runtime-resolved theme hex** cannot be a
|
|
55
|
+
Tailwind arbitrary class (the JIT will not safelist a value only known at runtime), so a new optional
|
|
56
|
+
**`style?: React.CSSProperties`** (`Badge.types.tsx`) is applied on the badge `span` (`Badge.tsx`). This
|
|
57
|
+
lets Surface theme-token hex (from `Client.ThemeTokens`, resolved per tenant) drive the badge color
|
|
58
|
+
directly.
|
|
59
|
+
|
|
60
|
+
## Change history
|
|
61
|
+
- 2026-08-14 — Decoupled badge **style** from **label** in `AddNotesTemplate`: added optional
|
|
62
|
+
`badgeVariant` as the stable `badgeStyles` lookup key (falls back to `badgeTitle`), fixing the
|
|
63
|
+
root-cause bug where relabeling a badge orphaned its style. Added a `contact.badges[]` array for the
|
|
64
|
+
two-badge delegate layout (back-compat with single `badgeTitle`). Added an optional `style` prop to
|
|
65
|
+
`Badge` so runtime-resolved theme-token hex (which can't be a Tailwind arbitrary class) can color a
|
|
66
|
+
badge. Consumed by the Surface-driven Admin Notes component in toga25-supply. (apeterson)
|
|
67
|
+
</content>
|
|
68
|
+
</invoke>
|
|
@@ -10,6 +10,6 @@
|
|
|
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/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
|
| [Record Modals & Nested Tables](features/record-modals-and-nested-tables.md) | The repo's family of modal + nested-table patterns layered over toga-blox `TableRecordModal` and `PrimaryTable*Layout`. | toga25-supply/src/layout/ItemRecordModalLayout/, toga25-supply/src/layout/SalesOrderRecordModalLayout/, toga25-supply/src/layout/SalesOrderItemsTableLayout/, toga25-supply/src/layout/ItemFulfillmentModal/, toga25-supply/src/layout/GenericNestedTables/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/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 |
|
|
13
|
-
| [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/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/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderNotesSection.tsx, toga25-supply/src/pages/SalesOrders/helpers/cleanOrder.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/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 |
|
|
13
|
+
| [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/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/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/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/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 |
|
|
14
14
|
| [AWS Amplify Multi-Environment Deployment](workflows/amplify-deployment.md) | How `toga25-supply` deploys to **all** of its environments on AWS Amplify from a **single shared `amplify.yml`**. | toga25-supply/amplify.yml, toga25-supply/src/api/api.ts, toga25-supply/src/hooks/useAuthenticationFlow.ts, toga25-supply/vite.config.ts, toga25-supply/package.json |
|
|
15
15
|
| [Cypress Testing Harness (component + e2e)](workflows/cypress-testing.md) | The Cypress test harness for the `toga25-supply` frontend, bootstrapped from scratch (`cypress` was already a dependency but there was no config, no `cypress/` | toga25-supply/cypress.config.ts, toga25-supply/cypress/tsconfig.json, toga25-supply/cypress/support/component.tsx, toga25-supply/cypress/support/component-index.html, toga25-supply/cypress/support/e2e.ts, toga25-supply/cypress/support/commands.ts, toga25-supply/cypress/support/fixtures.ts, toga25-supply/cypress/support/mocks/useApprovalModalViewModel.ts, toga25-supply/cypress/component/SalesOrderApprovalModalsLayout.cy.tsx, toga25-supply/cypress/component/RecordApprovalModalLayout.cy.tsx, toga25-supply/cypress/component/EnterPoNumberModal.cy.tsx, toga25-supply/cypress/e2e/salesOrderApproval.cy.ts |
|
|
@@ -22,6 +22,8 @@ files:
|
|
|
22
22
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx
|
|
23
23
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderNotesSection.tsx
|
|
24
24
|
- toga25-supply/src/pages/SalesOrders/helpers/cleanOrder.ts
|
|
25
|
+
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/AdminNotesSection.tsx
|
|
26
|
+
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getAdminNotes.ts
|
|
25
27
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts
|
|
26
28
|
- toga25-supply/src/surface/evaluateSurfaceRule.ts
|
|
27
29
|
- toga25-supply/src/surface/resolveElementState.ts
|
|
@@ -482,6 +484,32 @@ per-element span is therefore semantically impossible across differing column co
|
|
|
482
484
|
`orderContentDetailsWorkflow` at one array), so those two grids currently **share one span value**;
|
|
483
485
|
splitting them requires two arrays.
|
|
484
486
|
|
|
487
|
+
## Admin Notes component — whole component surface-driven (not just badges)
|
|
488
|
+
|
|
489
|
+
The Sales Order **Admin Notes** component (badge labels/colors, chrome labels, layout toggles) was
|
|
490
|
+
moved entirely out of the hardcoded `viewModel/FIELDS/DEFAULT/addNotesFields.json` into Surface — the
|
|
491
|
+
developer asked for the **whole component**, not just badges. The old
|
|
492
|
+
`addNotesFields.json → fieldsConfig → model → view` plumbing was **retired**. Seed side:
|
|
493
|
+
[surface-layer-schema](../../dbchanges2/features/surface-layer-schema.md); blox template:
|
|
494
|
+
[add-notes-template](../../toga-blox/features/add-notes-template.md).
|
|
495
|
+
|
|
496
|
+
- **`buildNotesComponent()`** (in `surfaceBundleToTenantFields.ts`) reads
|
|
497
|
+
`bundle.vocabularies['note-badges' | 'notes-chrome']` + the `admin-notes` `surface.config` and builds
|
|
498
|
+
`adminNotes.component = { labels, toggles, badges }`. Badge colors resolve via `bundle.theme` (the
|
|
499
|
+
per-tenant `ThemeTokens` slug→hex map) with an **FE fallback palette** matching the seeded values, so
|
|
500
|
+
the component renders identically **before** the migrations run (decouples deploy order).
|
|
501
|
+
- **`AdminNotesSection.tsx`** consumes `adminNotes.component` with pre-seed fallbacks (the former
|
|
502
|
+
`addNotesFields.json` defaults + seeded hex). It builds each note's `contact.badges[]` from badge
|
|
503
|
+
**variants**, resolving each variant's label + color from the surface.
|
|
504
|
+
- **`getAdminNotes.ts`** composes the two-badge delegate layout via a **`NOTE_BADGE_COMPOSITION`** map
|
|
505
|
+
(delegate → `[user, delegate]`), so a delegate note renders `[User][Delegate Manager Updated]` side by
|
|
506
|
+
side.
|
|
507
|
+
- **`cleanOrder.ts`** — the hardcoded `DELEGATE_NOTE_CLIENT_SLUGS` allowlist was **deleted**: delegate
|
|
508
|
+
scope is now backend data (only Compass / Compass Canada generate delegate notes) + a per-tenant
|
|
509
|
+
delegate ThemeToken, never an FE client list (see
|
|
510
|
+
[surface-resolver](../../_underscore/features/surface-resolver.md) — terms are Core-global, no
|
|
511
|
+
per-term gating).
|
|
512
|
+
|
|
485
513
|
## Gotchas
|
|
486
514
|
|
|
487
515
|
- **A named predicate that FAILS OPEN silently enables a button when its data isn't fetched.**
|
|
@@ -606,6 +634,18 @@ per-element span is therefore semantically impossible across differing column co
|
|
|
606
634
|
treat type-checking as pending. Runtime `GET /v2/surfaces/{slug}/meta` also not yet exercised.
|
|
607
635
|
|
|
608
636
|
## Change history
|
|
637
|
+
- 2026-08-14 — Moved the whole Sales Order **Admin Notes** component into Surface (badge labels/colors,
|
|
638
|
+
chrome labels, layout toggles — not just badges), retiring the hardcoded
|
|
639
|
+
`addNotesFields.json → fieldsConfig → model → view` plumbing. New **`buildNotesComponent()`**
|
|
640
|
+
(`surfaceBundleToTenantFields.ts`) reads `bundle.vocabularies['note-badges'|'notes-chrome']` +
|
|
641
|
+
`admin-notes` `surface.config` into `adminNotes.component = {labels, toggles, badges}`, resolving
|
|
642
|
+
colors via `bundle.theme` with an FE fallback palette so it renders identically before migrations run.
|
|
643
|
+
`AdminNotesSection.tsx` consumes it; `getAdminNotes.ts` composes the two-badge delegate layout via
|
|
644
|
+
`NOTE_BADGE_COMPOSITION` (delegate → `[user, delegate]`). Deleted the hardcoded
|
|
645
|
+
`DELEGATE_NOTE_CLIENT_SLUGS` allowlist from `cleanOrder.ts` — delegate scope is now backend data +
|
|
646
|
+
per-tenant ThemeToken (terms are Core-global, no per-term gating). Depends on the blox
|
|
647
|
+
`AddNotesTemplate` badge-variant/`contact.badges[]`/`Badge.style` changes (see
|
|
648
|
+
[add-notes-template](../../toga-blox/features/add-notes-template.md)). (apeterson)
|
|
609
649
|
- 2026-08-14 — **DECIDED (CTO-reviewed, AGREE)** where per-field grid `colSpan` lives in the FE Surface
|
|
610
650
|
layer: span VALUES stay per-consumer/adapter keyed by `valueKey` (the adapter IS the grid scope, since
|
|
611
651
|
each adapter renders into exactly one grid), NOT centralized as a universal per-element value and NOT
|
package/knowledge/INDEX.md
CHANGED
|
@@ -31,7 +31,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
31
31
|
- **ai-bdr** (AI-BDR) — 9 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
|
|
32
32
|
- **toga2-commerce** (TOGa Commerce) — 15 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
|
|
33
33
|
- **toga25-supply** (TOGa 2.5 Supply) — 11 doc(s) → [2.0/apps/toga25-supply/INDEX.md](2.0/apps/toga25-supply/INDEX.md)
|
|
34
|
-
- **toga-blox** (TOGa Blox) —
|
|
34
|
+
- **toga-blox** (TOGa Blox) — 9 doc(s) → [2.0/apps/toga-blox/INDEX.md](2.0/apps/toga-blox/INDEX.md)
|
|
35
35
|
- **bdr** (BDR) — 0 doc(s) → [2.0/apps/bdr/INDEX.md](2.0/apps/bdr/INDEX.md)
|
|
36
36
|
|
|
37
37
|
## standalone framework
|
package/package.json
CHANGED