Repository navigation
fix(plugin-approvals): the approval request page's highlights strip names the current step by its label - #24374
Conversation
…ames the current step by its label The approvals get's row builder serves `current_step_label`, the member `ApprovalRequestRow` declares for the step label under the column's own name, with the value `step_label` carries. The served record page's strip and the object's `highlightFields` list `current_step_label` where they listed `current_step`, the Approval node's machine id. Claude-Session: https://claude.ai/code/session_01Nk17Z26X5DB59iQztDBADH Co-authored-by: Claude <noreply@anthropic.com>
…d helper The open result is a union with the auto-outcome, so reading `.id` off it added seven TS2339 entries to the file's test-typecheck debt. The helper narrows it the way the file's other id helpers do. Claude-Session: https://claude.ai/code/session_01Nk17Z26X5DB59iQztDBADH Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 21 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 8 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3d59d8fe5c3721e51599e2ce3e8f11370b6a0f6e && git checkout 3d59d8fe5c3721e51599e2ce3e8f11370b6a0f6e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6a49efb9c452ff63870171434d9b996ae1746585 2ff7f0350be9e5a42ffa88025f7abfc51ec9107b && git checkout -B drift-repro 6a49efb9c452ff63870171434d9b996ae1746585 && git merge --no-ff 2ff7f0350be9e5a42ffa88025f7abfc51ec9107b
node scripts/docs-audit/affected-docs.mjs --json 6a49efb9c452ff63870171434d9b996ae1746585
|
席位核对ACCEPT ·
Generated by Claude Code |
Fixes #24281
Clause-②: no
The served
sys_approval_request_detailrecord page's highlights strip now names the current step by its label. It listscurrent_step_label(the "Approval Step" field) where it listedcurrent_step, the Approval node's machine id, so a request waiting on thelead_reviewnode readsLead Reviewthere. The approvals get's row builder now servescurrent_step_label, the memberApprovalRequestRowdeclares for this (370833a303, #24309), with the valuestep_labelcarries. The object'shighlightFieldsmakes the same swap.Responsibility:
plugin-approvals' own row builder and page declaration | the platform path is the declared columncurrent_step_labeland its contract member, both onmain, which the row builder did not serve under that name | reached by every user who opens a pending request's served page, whose Current Step chip showed the node's machine id.Readings are against objectstack
c4526a705(this branch's base) and objectui at the console pin.objectui-sha=0707b4ae3, bygit showandgit grep, plus one wire reading on a booted showcase (below). The page was not driven in a browser.Which of the card's two routes, and why
The card asks the fix to say which: the get now serves the label under a field name the page can list. The page names its object's declared fields, and
step_labelis not one.current_step_labelis a declared field ofsys_approval_requestand a declared member ofApprovalRequestRow, sorowFromRequestserves it from the samerequestDisplayLabelsvalue asstep_label. No new column, field, formula or contract member, and nopackages/specedit.Which doors gain the member
rowFromRequestis the only builder of a servedApprovalRequestRow. It has three call sites, and no other site builds a row:openNodeRequest's return;listRequests, behindGET /api/v1/approvals/requests;loadRequest, behindgetRequest(GET /api/v1/approvals/requests/ID) andreadBackRequest.readBackRequestbuilds therequestthatdecideNode,recall,sendBack,resubmit,reassign,remind,requestInfoandcommentecho back. The action-token chain behind the emailed links also reads throughgetRequest.The two REST routes pass the rows through unchanged (
res.json,packages/rest/src/approvals-routes.ts). So every one of these doors now servescurrent_step_labelbesidestep_label.Readers of
step_label, measuredstep_labelstays served, with the same value. No reader moves.action-link-pages.ts:66(req.step_label || req.current_step), the emailed confirm and result pages. Unchanged.apps/console/src/pages/system/ApprovalsInboxPage.tsx:314,:1525; the type inapprovalsApi.ts:68) and the record page's approvals panel (packages/app-shell/src/views/RecordApprovalsPanel.tsx:372; the type inuseRecordApprovals.ts:97). Unchanged.current_step_labelat the pin, so the added key changes nothing for an existing reader.The strip and the object's list change together
The rule in the page header still holds at the pin. The Details tab is a bare
record:detailsnode. objectui'srecord-details.tsxdraws the object'shighlightFieldsminus the mounted strip when a node authors neithersectionsnorfields(bodyFieldsOmitted, objectui#12433). A strip-only swap would have put a "Current Step: lead_review" row into that tab. So both lists swapcurrent_stepforcurrent_step_label, and the object's list minus the strip is still exactlyrecord_id.Other readers of the object's
highlightFields, re-read at the pin (the same census PR #24279 took):ObjectViewandObjectGriddefault columns: only for a list view that declares nocolumns. All foursys_approval_requestlist views declare columns, and three already listcurrent_step_label. Not reached.InterfaceListPagedefault columns,ObjectKanbancard fields,RelatedListdefault columns: no interface page, kanban view or related list of requests is declared in this repository. Not reached.deriveLookupColumns(lookup picker preview): the two lookups to a request,sys_approval_action.request_idandsys_approval_approver.request_id, sit on objects whoseenable.apiMethodsis['get', 'list'], so no create or edit form opens that picker. Not reached.RecordDetailView's synthesized default page: not used, since this page is assigned (isDefault: true).RecordPreviewCard, the card areferenceViapointer pair draws: reached only where a pointer pair names a request row. Whether such rows exist is NOT MEASURED. Where they do, the card shows the step's label where it showed the node id.@objectstack/lintfield references and semantic roles,metadata-core's field-security fold,metadata-protocol's build probes): none changes behaviour for a list of existing fields.current_step_labelis the fifth entry, outside the first four that the field-group shadow rule reads. The page test's build-rule leg stays green.The null case: what the chip shows
The console reads a request through the approvals get (
routeApprovalRecordReads). The get servescurrent_step_labelby the one chain indisplay-labels.ts:openNodeRequeststores the authored node label, else the humanized node id.__nodeLabel.approve_stepbecomesApprove Step), never the raw id.current_stepnull and no label anywhere): neither field is served. The strip draws no step chip, as it drew nocurrent_stepchip before.The
object_namechip: measured, the same family, not fixed hereobject_nameas stored, the target object's API name. On the booted showcase below it answersshowcase_announcement. At the pin,HeaderHighlightdraws atextfield through the text cell renderer, which prints the stored string. The pointer-pair handling (resolveRecordPointer) applies only to therecord_idid half, and only in the details grid and the list grid. So the Object chip readsshowcase_announcement. That is a static reading of the renderer plus a wire reading of the value, not a screen reading.object_label(Announcementon the same request), butsys_approval_requestdeclares no field that holds the target object's label (its 23 declared fields were read). A page bound to the object names declared fields only: this page's own pin, "every field the page names exists on its object", holds that. So a label chip needs a new member, which this card's claim excludes. It is reported to the seat with its reach and is not built.Tests (at
2ff7f0350)pnpm --filter '@objectstack/plugin-approvals^...' build: VERDICT command-exit 0.pnpm --filter @objectstack/plugin-approvals build: exit 0, atb62923f9d. The one commit after it changes only a test file.pnpm --filter @objectstack/plugin-approvals test:Test Files 81 passed (81),Tests 1111 passed (1111)(1108 before, plus the 3 below).pnpm --filter @objectstack/plugin-approvals typecheck: exit 0,check:test-typecheck: OK — … 8 file(s) / 324 error(s) / 27 pinned signature(s) held. The first spelling of the new test read.idoff the open result, a union with the auto-outcome, and grewapproval-service.test.ts's debt by 7 (189 type error(s), ledger records 182). The second commit narrows it with a typed id helper, as the file's other helpers do.--reporter=verbose -t current_step_label):approval-service.test.ts› the get serves the step label as current_step_label, beside step_label › a labelled row serves its stored label. It also asserts that the list door serves the same three fields as the get.sys-approval-request-page.test.ts› names the step by its label, current_step_label, in the strip and in the object's list alike.current_stepis still served raw (approve_step) and is still a declared field.Ablation (once, then restored; repeated on the final head).
node scripts/ablation-replace.mjs --deletedropped the served linecurrent_step_label: labels.current_step_label,fromrowFromRequest, inside a script with its owntraprestore. The test imports the service by relative path, sosrc/is what runs and nodist/is involved. On-disk evidence: anchor x1 → x0, blobb137eedb4067→2739baafe590. Expected direction: red. Observed:Tests 2 failed | 1 passed. Both get cases failed withexpected { current_step_label: undefined, …(2) } to deeply equal { …(3) }, and the page pin stayed green (it does not read the get). Restore leg: blob after restore == HEAD (b137eedb4067),git diff HEADempty,git statusclean. No test file is left behind.Wire reading (booted showcase, this branch's build).
pnpm dev -- --fresh -p 38241, signed in as the seeded admin. Retitling ashowcase_announcement(theshowcase_dynamic_approvalflow's trigger) opened a pending request at thelead_reviewnode.GET /api/v1/approvals/requests/IDansweredcurrent_step_label: "Lead Review",step_label: "Lead Review",current_step: "lead_review",object_name: "showcase_announcement",object_label: "Announcement".GET /api/v1/approvals/requestsanswered the same step fields. The served metadata lists the strip["process_label","object_name","status","current_step_label","submitter_id","updated_at"]and the object'shighlightFields["process_label","object_name","record_id","status","current_step_label","submitter_id","updated_at"]. The server was stopped after the reading.Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat2ff7f0350derived 69 commands for this diff, the same 69 the seat derived at83dfbc046. All 69 ran locally at2ff7f0350, each exit code captured before any pipe. All 69 exited 0, and none printed a PREREQUISITE NOT MET refusal of its own (the CLI and the showcase closure had been built for the wire reading).node scripts/pm/dispatch-gates.mjs --ranwith the exit-coded record:69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN("a DERIVED zero — all 69 recorded an exit code and none of them is 3").The longest local runs were
check:query-options-erasure(235 s),check:slot-lookup(123 s) andcheck-comment-mask-corpus(107 s).Not run locally, declared to CI:
test:repo(the vitestrepoproject; the diff touches neither its tests nor a list naming it), and the repo-wide scans (pnpm lintand the rest of the battery). The PR's check-runs are the reading.check:dev-prereqsandcheck:skill-frame-freshnessare not derived and not owed (nopackages/specbuild input and no frame file changed).Acceptance notes
apps/console/src/services/approvalRequestsDataSource.servedPage*.test.tsx, 8 files at the pin) copy the strip and the object's list withcurrent_step. Their field maps declare nocurrent_step_label, and their row fixtures are shaped as the get served a request before this PR, without it. approvals B1 closing card (ruling C on objectui#12438): the inbox opens a request on the served sys_approval_request page where the side sheet is, deletes the sheet, and lists each retired pin against its user report objectui#12484 carries them. They are not touched here.ApprovalRequestRow.current_step_label's TSDoc says the member was "declared ahead of its producer", which this PR is. The sentence names this card as the producer's, so it stays true. It is apackages/specfile and is not touched here.origin/mainmoved one commit past this branch's base (a2a3777bf, docs-only, none of the touched paths). The branch is not merged with it. CI's merge ref and the queue read the merged tree.Generated by Claude Code