feat(approvals): point the account app's Approvals nav at the inbox component (#7234) - #7298
Conversation
…omponent (#7234) The account menu's Approvals entry opened the raw sys_approval_request grid, which cannot show an approver a single decision button: all eight actions on that object gate on `record.viewer.can_act || record.viewer.can_override`, and the `viewer` block is attached only by the approvals REST path, never by the generic data API an object route reads. A correct-looking, completely inert list. The entry point does not move — same id, label and icon in every locale, which also keeps #7271's cross-package parity pin green. Only the DESTINATION changes, to `{ type: 'component', componentRef: 'approvals:inbox' }`, gated by `requiresService: 'approvals'` (requiresObject cannot gate a component entry; the service gate is enforced server-side by filterAppForUser, ADR-0057 D10). Setup gains an Approvals Inbox entry above the three raw tables, which stay put as the admin/diagnostic surface. Docs document the approver's real surface and how to mount the inbox in any business app. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9U1G2piXmYrhYQX96XUyv
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 2 package(s): 4 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also reference the affected code. These are read-only:
|
Fixes #7234
Entry C of #7213: the account app's Approvals entry opened the raw
sys_approval_requestgrid. That surface cannot show an approver a single decision button — all eight actions on the object gate onrecord.viewer.can_act || record.viewer.can_override, and theviewerblock is computed and attached only by the approvals REST path (approval-service.ts,attachViewers()), never by the generic data API an object route reads. The result was a correct-looking, completely inert list of rows nobody could act on.The entry point does not move. Same id, same label, same icon, in every locale — which is also what keeps #7271's cross-package parity pin (
my_pendingview label ===nav_account_approvalslabel, zh/ja/es) green. Only the destination changes.What changed
account.app.ts—nav_account_approvalsbecomes{ type: 'component', componentRef: 'approvals:inbox' }, gated byrequiresService: 'approvals'.requiresObjectwas the right gate for an object route and is not a gate at all for a component one — it names the object the entry routes to. The capability that must actually be present is the approvals service (ctx.registerService('approvals', …)), which is also what backs the REST path the inbox reads. Verified rather than assumed:requiresServicelives onBaseNavItemSchema, whichComponentNavItemSchemaspreads, andfilterAppForUser/filterNavreadse.requiresServicevariant-agnostically (rest-server.ts:2731/:2744, ADR-0057 D10) —packages/rest/src/meta-app-area-nav-gate.test.ts:34already pins that atype: 'component'item is stripped this way. Without the gate the entry would render a dead component route whereverplugin-approvalsis absent.requiredPermissionsadded anywhere — the account app deliberately has none, and the inbox enforces its own data access through the approvals REST path.approvals-plugin.ts— a newnav_approvals_inboxcomponent entry at the top ofgroup_approvals. Order is array order (applyNavContributionsdoesgroup.children.push(...c.items)), so its position in the array is the assertion, not a by-product. The three raw tables are untouched and stay behindgroup_approvals'manage_platform_settingsgate as the admin/diagnostic surface.nav_approvals_inboxin all four locales (enApprovals Inbox, zh-CN审批中心, ja-JP承認センター, es-ESCentro de aprobaciones).nav_account_approvalsdeliberately untouched.content/docs/automation/approvals.mdx: "The approver finds it in their queue" now names the Approvals Inbox as the canonical approver surface and explains, in a callout, why the raw table is not it; plus a new "Mount the approvals inbox in your app" section with the one-entry snippet.content/docs/ui/setup-app.mdx'sgroup_approvalsrow now enumerates the entries..changeset/approvals-nav-points-at-inbox.md(minor, both packages; user-visible navigation change).Tests
packages/platform-objects/src/apps/account-approvals-nav.test.ts(7 cases). The two shapes are one keyword apart and both parseAppSchemacleanly, so nothing else in the repo could see a regression back totype: 'object'.nav-contribution.test.ts. The old case opened with a.map(…).sort()overobjectName— a set-shaped assertion that cannot see ordering, and putting the working surface below three raw tables is most of what [approvals][console] 「待我审批」有三个并存入口、三套不同 UI —— 其中 sys_approval_request 原生视图是无决策动作的开发者原始表 #7213 reported. It now pins the id order, the inbox's component shape, that it carries no object gate, and that the raw tables are unchanged and still gated.Reverse verification
Both new gates were taken out and confirmed red, in the predicted direction:
account.app.tstoorigin/main→ 5 of the 7 new cases fail (expected 'sys_approval_request' to be undefined,expected undefined to be 'approvals', …). The 2 that stay green are the deliberate ones: the label/icon pin (unchanged by design) and theAppSchema.parsecase — both shapes are valid metadata, which is precisely why the rest of the file exists.nav_approvals_inboxlabel →check:app-nav-i18ngoes red naming exactly that id:apps.setup.navigation — locale 'zh-CN' has no label for 1 runtime-merged nav id(s): nav_approvals_inbox contributed by @objectstack/plugin-approvals. This proves the new Setup entry really is merged and judged by the gate, not merely declared.Local results
plugin-approvals'approval-status-vocabulary.test.ts— including the cross-package parity case #7271 added today — is inside that green 452 and was run explicitly against this change.Not in this PR
.objectui-sha) is tracked separately as chore: bump the console pin to pick up objectui#4071 (approvals:inboxcomponent ref) #7268.approvals:inboxresolves in the console registry as of objectui#4071 (objectui main28c38567b), but end-to-end browser behavior needs that pin bump — deliberately not ridden here.vieweron the generic data API (objectui#2763 A1) and the vocabulary alignment ([approvals] Unify the approval-status vocabulary across i18n bundles (zh "待处理"→"待审批", my_pending view label; humanize the en status options) #7232, merged as fix(plugin-approvals): unify the approval-status vocabulary across the i18n bundles #7271) stay out of scope.Generated by Claude Code