Repository navigation
fix(app-shell): the approval step line draws the route the request's run took, not the flow graph's first branch - #26666
Conversation
…run took, not the flow graph's first branch The step line drew the request's served `flow_steps`, which the approvals read builds by walking the flow graph from its start along the `approve`, then `true`, then first edge. A request routed down another branch was drawn on rungs it never visits. The record approvals panel now builds the line from the run's own request rows (same flow run, another node, approved, opened before the pending one), then the pending step, and draws nothing ahead of it. The approval request page holds only its bound row, so its decision panel draws no line until the approvals read serves the route. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jThx2NXgeJ4uCUi1qo
席位核对ACCEPT · seat
Landing: no contract review is owed (no published schema, no governed text, Generated by Claude Code |
Requested by Steedos · project thread
Fixes #26563
Clause-②: no
Metadata-protocol: none
维护者速读
flow_steps(流程图从起点沿 approve/true/第一条边走出的那一条主干),改为只画本次流程运行真实走过的步骤:同一flow_run_id下已通过的审批请求,按到达先后排列,最后是当前待审步骤;当前步骤之后一概不画。业务记录的审批面板照此绘制;审批请求页只持有自身这一行,证明不了任何已走步骤,所以暂不画步骤线。ui/packages/app-shell/src/views/RecordApprovalsPanel.tsx新增的visitedApprovalSteps(哪些请求算「已走过」);②ui/packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.tsx删去的那一行步骤线;③RecordApprovalsPanel.visitedRoute-26563.test.tsx。pnpm --dir ui exec vitest run packages/app-shell/src/views/RecordApprovalsPanel.visitedRoute-26563.test.tsx,预期 11 个测试全绿,其中报告的路由只画出「直属上级、财务负责人」两步。What changes
The approval step line drew the request's
flow_steps. That field is built byplugin-approvals'attachFlowSteps, which walks the flow graph from its start node and takes theapproveedge, else thetrueedge, else the first edge at each node. It marks done, current and upcoming against that one trunk. It is not the route the request takes. A request that a decision sent down another branch was drawn on rungs it never visits. When the request's own node is off the trunk, it is drawn on none of the trunk's rungs as current. A rung reached after a side branch rejoins showed the trunk's branch as done.Measured first, as the triage asked: the single request read (
GET /api/v1/approvals/requests/:id) carries neither a resolved route nor the visited nodes. Beyondflow_steps, the row names only its own node (flow_node_id,current_step,step_label) and its run (flow_run_id). So the route read is aplugin-approvalschild (see Acceptance notes), and this PR draws only what a request row proves:visitedApprovalSteps(pendingRequest, requests)builds the line from the request rows the panel already holds (the list read, no new request). A passed step is a request with the sameflow_run_id, on another node,approved, and opened before the pending one. A node approved in several rounds is drawn once, at its latest round. The pending request comes last. Nothing ahead of it is drawn, because no request row says which branch the run takes next.record:approval_decision). The decision panel no longer draws a step line. Its bound row proves only its own step, which the page header already names, and one step is no line.ApprovalRequestLitedeclares the servedflow_run_idandflow_node_id. Theflow_stepsdoc says why no surface draws it.ApprovalStepLine's markup is unchanged. Its header now says the caller owns the proof of the steps it hands in, and the stale paragraph about the inbox sheet's copy of the stepper is gone (that sheet no longer draws one).Tests
RecordApprovalsPanel.visitedRoute-26563.test.tsx, 11 tests. The panel cases use the reported route (manager → finance only) with the served trunk attached. They pin a branch that rejoins the trunk (manager → legal only → executive), a request at the run's first rung, and a viewer served only the pending row. The unit cases forvisitedApprovalStepspin ordering, another run, a step not approved (returned,rejected), a row opened after the pending one, round dedup, an earlier round of the pending node, a decided request, an unlabeled step, and the controls for a missing run, node or open time.RecordApprovalsPanel.stepProgressVertical.test.tsx: the layout contract is unchanged. Its fixtures are now a run's request rows, so they reach the line the way the panel builds it. The connector-tint case now pins that every segment is green, because the line draws nothing ahead of the pending step.ApprovalDecisionPanel.stepLine-12491.test.tsx: rewritten to pin the absence of the line. The reported row with its served trunk draws no line and none of the trunk's rungs, a decided row draws none either, and the tally still draws above the decisions. The deleted layout cases duplicate the onesRecordApprovalsPanel.stepProgressVertical.test.tsxpins over the sameApprovalStepLinemarkup.approvalRequestsDataSource.servedPageStepLine-12491.test.tsx(console, the real served page): the step-line cases now pin that no line and no other trunk rung is drawn, at pending, at decided, and for a person-submitted request. The flow-origin cases are unchanged.Test readings, head 4743eb8 (all under scripts/pm/os-verify-lock.sh, run from ui/)
vitest runoverRecordApprovalsPanel.visitedRoute-26563,RecordApprovalsPanel.stepProgressVertical,ApprovalDecisionPanel.stepLine-12491and the consoleapprovalRequestsDataSource.servedPageStepLine-12491: Test Files 4 passed (4), Tests 24 passed (24), VERDICT command-exit 0.packages/app-shellandapps/console(by file name, plus every test that namesRecordApprovalsPanel,ApprovalDecisionPanel,ApprovalStepLine,useRecordApprovals,approval-decisionorapproval-progress): Test Files 68 passed (68), Tests 765 passed (765), VERDICT command-exit 0, 7m00s. The wholepackages/app-shellsuite (1757 test files) was not run locally; CI's Test UI shards run it.pnpm --filter @object-ui/app-shell run type-check(both projects;tsconfig.test.json --listFilesOnlylists the three touched app-shell test files): VERDICT command-exit 0.pnpm --filter @object-ui/console run type-check(--listFilesOnlylists the touched console test): VERDICT command-exit 0.Reverse verification, one-shot (no test file kept for it)
node scripts/ablation-replace.mjsreplaced the panel's step linesteps={visitedApprovalSteps(pendingRequest, requests)}with the oldsteps={pendingRequest?.flow_steps}. The mutation landed: anchor 1 to 0, blobddd69d0e14ebto347c203eb6ff.RecordApprovalsPanel.visitedRoute-26563then failed its 4 panel tests (Tests 4 failed, 7 passed; the 7 are the unit cases, which callvisitedApprovalStepsdirectly). The tool restored the file: blobddd69d0e14ebequal to HEAD,git diff HEADempty.ApprovalDecisionPanel.tsxwas restored to the merge base blob (f61253e4b319, which still drawssteps={request.flow_steps}) under an EXIT trap. The decision panel suite and the console served-page suite then failed 6 of 9 tests (Test Files 2 failed). The 3 still passing are the page-parse case, the flow-origin case and the one-step control. Restored to HEAD blob4bf7bdb3f704, withgit statusclean.Acceptance notes
plugin-approvals.ApprovalService.attachFlowStepsserves the flow graph's trunk asflow_stepson every single read. For the reported request (nodefinance_only), every trunk entry isupcomingand its own node is absent. The child should serve the route the run took and only the steps ahead that the run's state determines. Then the request page can draw its line again, andvisitedApprovalStepscan be deleted in favour of the served route.flow_steps' contract text inpackages/spec/src/contracts/approval-service.tsreads "The owning flow's approval steps in graph order", so the child either changes that text or adds a field. Either way it is a contract change.ApprovalStepLine's own gate draws nothing under two steps, so the page draws none.rejectedge routes to an approval node, and a rung sent back for revision, are not "passed" (notapproved), so they are left out. A route that passes through them shows only its approved rungs.upcomingstyling inApprovalStepLinehas no caller today. It stays for the served route the child brings back.Verification
Derived gate sweep, head 4743eb8
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 34 commands from the change set against merge basefb91e9793. Each command ran with its exit code captured before any pipe, and all 34 exited 0.check:type-check-debtran under the verify lock, with VERDICT command-exit 0. The PR-body gates (check-changeset-no-major,check-closing-keyword-parity,check-adr-0087-registration) read this body throughGITHUB_EVENT_PATH.dispatch-gates --ranreconciliation:✓ 34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED.origin/maingained 12 commits after the branch point, and none of them touches a file of this diff. The branch was not merged with main before opening, and CI runs on the merge ref.!andClause-②carries no(narrowing)arm.Generated by Claude Code