Repository navigation
[approvals][console] 「待我审批」有三个并存入口、三套不同 UI —— 其中 sys_approval_request 原生视图是无决策动作的开发者原始表 #7213
Description
Activity
- assignedand unassignedandos-zhuang
on Aug 10, 2026 - added sub-issues
on Aug 10, 2026 Triage + v17 plan (maintainer-directed, 2026-08-10)
Maintainer directive (chat, 2026-08-10, quoted verbatim): 「按照你的建议继续,相关任务作为子任务,开始派发并开发。」
Code-level findings behind the plan (verified on both repos' origin/main today):
- Entry A (Approvals Inbox) is a bespoke objectui console page (
apps/console/src/pages/system/ApprovalsInboxPage.tsx) whose relative routesystem/approvalsalready resolves under any app (AppContent.tsx:261passessystemRoutesas bothextraRoutesandextraRoutesNoApp). It is "under setup" only because every hardcoded entry link sayssetup; no navigation metadata points at it, and the component registry has noapprovals:*key. - Entry C is exactly one metadata declaration:
platform-objects/src/apps/account.app.ts:100-108(type:'object'→sys_approval_request/my_pending) in an app with norequiredPermissions. Its record page has no decision actions because the 8 server-declared actions gate onrecord.viewer.can_act || record.viewer.can_override, and theviewerblock is only attached by the approvals REST path (approval-service.tsattachViewers()), never by the generic data API. - The vocabulary split is structural: three independent i18n sources with no shared keys (plugin-approvals object bundle 待处理/我的待办; platform-objects nav 待我审批; objectui
approvalsInbox.*审批中心/待审批). The en object bundle even ships raw enum values (pending: "pending"). - The bell badge is
unread notification topics + pending approvalswhile the home card and inbox tab show approvals only — hence 8 vs 9+.
Boundaries with the sibling issues: objectui#2762 (queued) polishes the bespoke page in place; objectui#2763 (approved epic, on hold until after v17) rebuilds the whole surface on standard SDUI renderers. This issue therefore converges entries, vocabulary, and positioning at the metadata level only — no new investment in the bespoke page, and the
approvals:inboxcomponent-registry key is the stable indirection the v18 rebuild will simply repoint (zero nav-metadata churn at that time).Sub-issues (this issue stays open as the coordination node):
# Scope Repo Order #7231 Register approvals:inboxcomponent-registry key; de-hardcode Home entry link; keepsystem/approvalsdeep linksobjectui round 1 (dispatched) #7232 Unify status vocabulary in the plugin-approvals i18n bundles (zh 待处理→待审批, view label; humanize en) objectstack round 1 (dispatched) #7234 Account-app nav → approvals:inboxcomponent; Setup inbox entry; docs for mounting in business appsobjectstack round 2, Blocked-by: #7231#7233 Bell badge breakdown (notifications vs approvals) objectui queued, independent Entry B (record-page header decisions) intentionally unchanged in v17 — it is the in-context surface, and component unification is #2763 B1/B2.
sys_approval_requeststays an admin/diagnostic raw table under Setup (manage_platform_settings); attachingvieweron the generic data API is deliberately deferred to #2763 A1.End-to-end console behavior for #7234 additionally lands with the next console pin bump (standing chore, not a rider).
Generated by Claude Code
- Entry A (Approvals Inbox) is a bespoke objectui console page (
Triage note — three observations, no label action taken:
- Truncation dual-read: the REST
bodyread ends mid-sentence inside 入口 B's route; the rendered page is complete (entries A/B/C, 汇总的问题, 期望, 环境). The two reads do NOT break at the same place ⇒ reading-end artifact, not sanitizer truncation. The stored body is intact and needs no repair. - Claim state: assigned minutes after filing — in flight. Per the state model this seat applies no queue labels to a claimed card and does not touch the claim. Skip-by-design.
- Routing observation, for whenever the claim resolves into scoped work: the face spans the console rendering side (approval center UI, entry C's raw
sys_approval_requestview — objectui),plugin-approvals(decision actions / notification deep-links), andpackages/platform-objects(thesetup/accountapp mounts), with an embedded product call (which entry is canonical; whether business apps can mount the approval center). If it returns to the backlog unclaimed, it is a contract-first split candidate, not a single dispatch.
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Truncation dual-read: the REST
Epic complete — all five sub-issues merged
Every entry reported here has been converged at the metadata level, and the bundled console now carries it. Closing this parent as the coordination node.
Sub-issue What shipped PR #7231 approvals:inboxregistered in the component registry; Home's approvals card stops routing every user throughsetupobjectstack-ai/objectui#4071 #7232 One vocabulary across the bundles (zh 待审批/待我审批, en humanized), plus a cross-package parity pin so the layers cannot drift apart again#7271 #7233 The bell badge's N notifications + M pending approvalsbreakdown, unclamped, so9+is explainableobjectstack-ai/objectui#4073 #7234 The account app's Approvals entry now opens the inbox component; Setup gains an Approvals Inbox entry above the raw tables; docs teach mounting it in any app #7298 #7268 Console pin 09987b680d53→8aad9fd50b16, so the bundled console actually carries the above#7308 Against the five problems as reported
- Entry fragmentation — one canonical approver surface, the Approvals Inbox, reachable from the account app (every authenticated user), from Setup (admins), and mountable in any business app with a single nav entry naming
approvals:inbox. The registry key is the indirection, so nav metadata never spells a console path. - The complete entry lived in the admin app — no longer: it was never actually bound to
setup(system/approvalsis mounted app-agnostically), only every link to it was hardcoded. Those are fixed, and the mountable entry is documented incontent/docs/automation/approvals.mdx. sys_approval_requestexposed raw to end users — removed from the account app; it remains under Setup → Approvals behindmanage_platform_settingsas the admin/diagnostic surface, which is what an engine-owned table is good for. The docs now say why it can never be the approver surface: its decision actions gate onrecord.viewer.can_act, andvieweris attached only on the approvals REST path.- Vocabulary — aligned, and pinned across packages.
- Counts — the bell's total is now shown as its two addends, matching the number Home and the inbox tab display.
Entry B converged too, and by a route this epic did not plan. The pin in #7268 carries objectui
99782f961— "Runsys_approval_request's server-declared decision actions on the business record page, and retire the hard-coded two-button approval path" (objectui#3055). The bespoke record-page Approve/Reject path this issue reported as the third UI is retired upstream, onto the same server-declared actions the inbox uses. So all three entries converged, not two.Residuals — recorded, none blocking
- [console] Four remaining inbox/activity entries still hardcode
/apps/setup/..., so a business user without setup access has no working "all notifications" or "all activity" link #7266 (repo:objectui, unassigned): four sibling/apps/setup/...hardcodes for the inbox/activity "see all" targets — same defect class as [approvals][console] Register anapprovals:inboxcomponent-registry key and de-hardcode the Approvals Inbox entry links #7231, filed rather than swept in. Explicitly not browser-verified; stated as routing-level inference on the issue. - finding: the ADR-0082 D4 ratchet's only trigger needs a Playwright browser the dev containers cannot supply at the expected revision #7315 (
finding,domain:devx, unassigned): the ADR-0082 D4 declaration-parity ratchet's only trigger is the pin bump, and the dev containers cannot supply Playwright chromium at the expected revision — so it silently degrades to "nobody ran it" with no gate going red. It did run for chore: bump the console pin to pick up objectui#4071 (approvals:inboxcomponent ref) #7268 (green, no drift) via a workaround the issue records. Worth a real grade. - ja-JP
status.options.pendingis保留中while the same bundle uses承認待ちelsewhere; [approvals] Unify the approval-status vocabulary across i18n bundles (zh "待处理"→"待审批", my_pending view label; humanize the en status options) #7232's glossary scoped ja/es to the view label, so it was documented in fix(plugin-approvals): unify the approval-status vocabulary across the i18n bundles #7271's body rather than changed. - Browser verification of the converged surface is not yet done and is the honest gap: the unit tests deliberately stop short of proving the registration survives bundling, that a non-admin session actually reaches the entry, and that decision actions render under the component mount. Awaiting a maintainer call on whether to run it now or fold it into the normal QA cadence; the approvals checklist (
docs/qa/platform-checklist/areas/approvals.json) also still drives every case through/system/approvalsand has no coverage for the two new nav entries.
Boundaries kept
objectui#2762 (polish of the bespoke page) and objectui#2763 (the approved SDUI rebuild, on hold until after v17) remain their own tracks. Nothing here started #2763's work: when it lands, it repoints
approvals:inboxand no navigation metadata churns — which is the reason the registry key exists.
Generated by Claude Code
- Entry fragmentation — one canonical approver surface, the Approvals Inbox, reachable from the account app (every authenticated user), from Setup (admins), and mountable in any business app with a single nav entry naming
Browser verification of the converged surface — done, and it holds
The close-out above records browser verification as "the honest gap". It has now been run against
main(88154bee1) with the vendored console rebuilt at the current pin (.objectui-sha=8aad9fd50b16), onexamples/app-showcasewith a fresh seeded DB, zh-CN, dev admin.Confirmed live, all five reported problems:
- [approvals][console] Register an
approvals:inboxcomponent-registry key and de-hardcode the Approvals Inbox entry links #7231 — Home's 「N 条待审批」 lands on/_console/apps/**com.example.showcase**/system/approvals. A business app, notsetup. - [approvals] Point the account app's Approvals nav at the inbox component; contribute a Setup inbox entry; document mounting the inbox in business apps #7234, account — 账户 → 收件箱 → 待我审批 renders the full inbox at
/_console/apps/com.objectstack.account/**component/approvals/inbox**.sys_approval_requestis gone from that app. - [approvals] Point the account app's Approvals nav at the inbox component; contribute a Setup inbox entry; document mounting the inbox in business apps #7234, Setup — 审批 group order is 审批中心 → 审批申请 → 审批历史 → 审批委派(外出): the inbox above the raw tables, same component route.
- Decision actions under the component mount — the drawer carries all five server-declared actions (通过 / 拒绝 / 转签 / 退回修改 / 退回补充). Approving one drives it end to end:
sys_approval_request.status→approved. This was one of the three things the close-out said the unit tests deliberately stop short of proving. - Registration survives bundling — the
approvals:inboxkey resolves from a built vendored console, not a dev server, in both apps. - [approvals] Unify the approval-status vocabulary across i18n bundles (zh "待处理"→"待审批", my_pending view label; humanize the en status options) #7232 — 待审批 / 待我审批 read the same in the inbox, the account nav, and the raw table's view tab.
- [approvals][console] Bell badge sums unread notifications + pending approvals into one opaque number — surface the breakdown #7233 — bell reads 「共 4 项 · 1 条通知 + 3 条待审批」; after approving one it reads 「共 3 项 · 1 条通知 + 2 条待审批」, matching Home and the inbox tab. The addends track, not just the total.
- Entry B — the business record page (
showcase_invoice/ INV-1010) header now carries the same five actions, so objectui#3055's retirement of the hard-coded two-button path is live in the bundle. - Both sides of the
requiresService: 'approvals'gate — bootedexamples/app-crm(requires: ['ui','automation'], no approvals plugin): the account app's approvals entry is correctly absent, so the entry never degrades into a dead component route.
Still not verified, and it is the one thing left from the close-out's list: a real non-admin session. The seeded instance had no second account with a usable password and none was created. Server-side the account app declares no
requiredPermissionsand the entry gates only onrequiresService, so a non-admin should reach it — but that is inference, not measurement.Residuals, updated:
- [console] Four remaining inbox/activity entries still hardcode
/apps/setup/..., so a business user without setup access has no working "all notifications" or "all activity" link #7266 → objectui#4074 — browser-verified there (comment). The inferred symptom is real and slightly worse than filed: from inside a business app, 查看全部通知 and 查看全部动态 hard-switch the console into the Setup app for every user, not just those without access. - [console][nav]
filterNavnever drops a group DECLARED withchildren: []— Setup renders an inert 「Approvals」 group on a runtime without plugin-approvals #7380 (new,finding) —filterNavnever drops a group declared withchildren: [], only one that became empty under filtering. On a runtime without plugin-approvals, Setup renders an inert 「审批」 group. Pre-existing, same nav face. - [showcase][approvals] Approving the Invoice Dual Sign-off demo strands its flow run —
notify_clearedreads{record.account.owner}with noexpandon the start node #7381 (new,finding) — unrelated to this epic but found in the same session: approving the showcase's Invoice Dual Sign-off demo strands its flow run (notify_clearedreads{record.account.owner}with noexpandon the start node). The decision records; the run does not resume. - The approvals checklist (
docs/qa/platform-checklist/areas/approvals.json) still drives every case through/system/approvalsand has no case for the two new nav entries — unchanged, still worth a case.
- [approvals][console] Register an
- added a commit that references this issue
on Aug 17, 2026
在应用项目(v17.0.0-rc.5,Console + plugin-approvals)实测中发现:同一个「我有待审批的事」在 Console 里同时存在三个入口,三套完全不同的 UI、不同的词表、不同的能力,其中一个入口是没有任何决策动作的开发者原始数据表。终端用户无法判断哪个才是"正确"的入口。
下面按入口逐一列事实(同一条待审批记录,同一个账号)。
入口 A —— 首页「待办事项 → N 条待审批」→ 审批中心
路由:
/_console/apps/setup/system/approvals待我审批(8) | 我发起的 | 全部,带搜索 + 流程/对象筛选 + 排序。待审批)、提交时间。这是三者中唯一完整、且面向业务语义的一套。但它挂在
setup应用(系统设置)下面 —— 而日常审批是业务用户的高频操作,业务角色一般不会开放系统设置应用的访问权;也没有办法把这个页面挂到业务应用自己的导航里。入口 B —— 首页待办里的通知 →(业务对象)记录页
路由:
/_console/apps/<app>/<object>/record/<id>① 质检部部长 | ② 多部门并行会审 | ③ 工厂长 | 归档 | 审批驳回。第三套视觉与信息组织,和入口 A 的抽屉不共用摘要/决策组件。
入口 C —— 账户应用 → 审批请求 → 「我的待办」
列表路由:
/_console/apps/com.objectstack.account/sys_approval_request/view/my_pending这是
sys_approval_request的原生对象列表,呈现的全是开发者视角的原始值:flow:qif_approvalos_..._qif-2kQ8hM_wiI5xPrClv1_qc_director点进记录页
/_console/apps/com.objectstack.account/sys_approval_request/record/areq_<uuid>:flow:qif_approval · -2kQ8hM_wiI5xPrC;待处理;阶段条是请求状态:待处理 | 已批准 | 已拒绝 | 已撤回 | 已退回修改;请求 ID = areq_…、当前步骤索引 = 0、FLOW RUN = run_<uuid>、FLOW NODE = lv1_qc_director;airUFxCipivl1VYMACC…),同 [approvals] 转签审计默认 comment 落裸用户 ID("<from_id> → <to_id>"),审批动态里看不出谁转给谁 #4365 的形态;汇总的问题
setup应用,业务用户通常没有该应用的访问权;也无法挂到业务应用导航。sys_approval_request的原生视图直接面向终端用户暴露:显示流程 id / 对象 API 名 / 记录 ID / 节点 id / 裸用户 ID,且记录页无决策动作,是一条死路。如果这张表定位为系统内部实例表,它不应该出现在终端用户的「待我审批」导航里;如果它要面向用户,就得渲染人类可读标签并带上决策动作。待审批,sys_approval_request显示待处理;阶段条一处是流程节点、一处是请求状态,同样的横条控件表达两种完全不同的轴。待我审批 8、铃铛9+,用户侧同时看到多个不一致的数字。期望(方向,不指定实现)
setup;sys_approval_request的可见性与呈现按上面第 3 点明确定位。环境
@objectstack/*@17.0.0-rc.5,Console 预览版,zh-CN。PM epic registration (
pm:epic) — ✅ CLOSED OUT 2026-08-10session_01L9U1G2piXmYrhYQX96XUyv— registered 2026-08-10, maintainer-directed dispatch (plan in the triage comment below).approvals:inboxcomponent-registry key and de-hardcode the Approvals Inbox entry links #7231 [approvals] Unify the approval-status vocabulary across i18n bundles (zh "待处理"→"待审批", my_pending view label; humanize the en status options) #7232 [approvals][console] Bell badge sums unread notifications + pending approvals into one opaque number — surface the breakdown #7233 [approvals] Point the account app's Approvals nav at the inbox component; contribute a Setup inbox entry; document mounting the inbox in business apps #7234 chore: bump the console pin to pick up objectui#4071 (approvals:inboxcomponent ref) #7268. Outcome and residuals are in the close-out comment at the end of this thread.packages/platform-objects/src/apps/**(account/setup nav + app translations),packages/plugins/plugin-approvals/**(nav contributions + i18n bundles),content/docs/automation/approvals.mdx,content/docs/ui/setup-app.mdx,.objectui-shaapps/console/src/**(component registration/wiring),packages/app-shell/src/console/home/HomePage.tsx,packages/app-shell/src/layout/InboxPopover.tsx,packages/app-shell/src/hooks/useHomeInbox.tspm:epicremoved, this section marked closed out.(Note: the two route examples in 入口 B / 入口 C above now spell their placeholders as HTML entities so this body survives GitHub's sanitizer on rewrite; the wording is otherwise unchanged from the original report.)