Repository navigation
feat(plugin-detail): record:path stage press moves the record when allowStageChange is set - #28303
Conversation
…(wip) Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibyyvCaZXvGAh38AKjD
…age press Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibyyvCaZXvGAh38AKjD
…t for the record:path stage press Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibyyvCaZXvGAh38AKjD
…e press Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibyyvCaZXvGAh38AKjD
|
domain:ui#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
domain:ui#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: Inputs: card #28199 (body and all five comments: triage 6528549948, the unblock 6533351162, the seat's claim 6537955118, the dev report 6538697224, the claim amendment 6538708352 which flips Clause-② to yes and accepts the generated registry half, the ① Derived judgments
② Semver level
③ Boundary flags
Verdict reasoning. The diff does exactly the console half #28061 named: an opt-in press gated by the reader's row-scoped edit right, one update path with the concurrency token, the server's refusal shown in place, the input published with its exemption cleared, every want pinned with an ablation shown red; nothing an author writes moves and nothing released changes signature. Implemented-by: VERDICT: PASS |
|
domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN 席位核对ACCEPT · seat 席位意见:记录路径组件声明
|
Requested by Tesla · project thread
Fixes #28199
Refs #28061
Clause-②: yes
Metadata-protocol: none
维护者速读
record:path设了allowStageChange: true后,有权编辑状态字段的用户可以点击阶段(当前阶段除外),确认后把记录移到该阶段;没设这个键或无编辑权的用户,看到的仍是原来的只读进度条。ifMatch并发令牌,合法与否由服务端状态机/校验/权限判定,前端不做第二套判定。回滚即 revert 本 PR,未开启的页面零影响。ui/packages/plugin-detail/src/renderers/recordPathStageChange.tsx(谁能点、写入、拒绝文案)、ui/packages/plugin-detail/src/renderers/record-path.tsx(阶段按钮与就地拒绝区)、ui/packages/plugin-detail/src/index.tsx(注册表新增输入)。pnpm --dir ui exec vitest run packages/plugin-detail/src/renderers/__tests__/record-path.stageChange-28199.test.tsx,预期 14 个用例全过。What changes
record:pathhonoursallowStageChange. WithallowStageChange: true, each stage other than the current one carries a realbutton(accessible name "Move to STAGE") inside its existinglistitem, on both the desktop and the phone row. A press opens a confirmation (AlertDialog); confirming writes{ [statusField]: value }and re-reads the record. Without the key, or withfalse, the DOM is the readout it was.useStageChange, newrenderers/recordPathStageChange.tsx): the record is stored and its data source can update; the record page's edit session allows editing the record (useInlineEdit().canEdit, the page host's record-level verdict); the status field is not read-only, computed or a system field; the caller'srecordEditfield grant holds (resolveFieldAffordance).RecordPathRenderernow mountsRecordFieldAccessForRecordaround the body when the key is on, so that grant is asked of this stored row, asrecord:detailsandrecord:highlightsask it. While the edit session holds an inline draft, the path is a readout again.updateVia(now exported fromInlineEditSaveBar.tsx, not from the package index), the function the inline-edit save bar uses, with the record'supdated_atasifMatch.stageRefusalLines), under the rails, once for both rows: aCONCURRENT_UPDATE409 gets a fixed line and the record is re-read; a producer-markeduserMessageverbatim; a field-scoped refusal (VALIDATION_FAILEDfields[], the shape an illegalstate_machinetransition and a missing required field arrive in) one line per entry, an entry about another field prefixed with its label; a permission refusal the delegated-scope reason or a fixed line; anything else the server message or a fixed line. The next press clears it.allowStageChangejoins the block's registryinputs(boolean, renderer-accurate description), sosdui.manifest.json,scripts/sdui-manifest.record.jsonand the generated component reference (content/docs/ui/components/record.mdx,index.mdx) are regenerated, and theUNPUBLISHED_EXEMPTIONSentryrecord:path.allowStageChangeis deleted fromregistry-inputs-spec-parity.test.ts.detail.pathStageChange*keys in all ten packs and inDETAIL_DEFAULT_TRANSLATIONS..changeset/28199-record-path-stage-change.md,@object-ui/plugin-detailand@object-ui/i18npatch.Why
The spec half (#28198) declared
RecordPathProps.allowStageChange, and the console registry carried it as unpublished because nothing read it. Authors who set it got the read-only rail. This is the console half that #28061 names.Tests
ui/packages/plugin-detail/src/renderers/__tests__/record-path.stageChange-28199.test.tsx, 14 cases:update('crm_quote', 'q1', { status: 'in_review' }, { ifMatch: VERSION })andrefresh; cancel writes nothing;state_machinetransition (the server sentence alone), a required field elsewhere (label-prefixed), a 403 (fixed line, not the raw text), a stale token (fixed line plus a re-read), and the next press clears it;false, the page's edit session refusing the record, the field edit grant denied, a read-only status field, an inline draft in progress.Ablations (one-shot, each through
scripts/ablation-replace.mjs, which proved the mutation landed and restoredgit diff HEADempty; the subject resolves to source through the vitest alias, so no rebuild applies):recordPathStageChange.tsxifMatchtoken dropped from the updateallowStageChangeremoved from the verdict!inline.editingremovedresolveFieldAffordance(...)removedsetRefusal(...)removedAcceptance notes
state_machinetransitions to hide stages: that would be a second evaluator of a rule the server owns. Every drawn stage the record is not on is pressable, and an illegal move comes back as the server's refusal, shown in place. Stages a record's own columns rule out (optionvisibleWhen) are already not drawn.ConcurrentUpdateDialog's overwrite: a stage move is one field, and the re-read record plus a second press is the whole recovery.AGENTS.mdrequires ("A registry change has a second half"):sdui.manifest.json,scripts/sdui-manifest.record.json, and the generated reference pagescontent/docs/ui/components/record.mdxandindex.mdx(node scripts/gen-sdui-reference.mjs, gated bycheck:sdui-reference). No hand edit in any of them.inputsgain a key (the manifest and the component reference grow by one input). The claim recordednoas the seat's expectation; the dispatch order says publishing the input counts.ui/AGENTS.md✨ Set up Copilot instructions #2 (package README and docs): the docs page for this input is the generated component reference (content/docs/ui/components/record.mdx), regenerated here.plugin-detail's README coversrecord:details/record:highlights/record:quick_actions/record:related_listbinding and says nothing aboutrecord:pathtoday; it is outside the claimed surface and left untouched — the seat may want a README line.Verification
Every reading below is on head
2837cf76unless it says otherwise.Tests (local, under the shared verify lock)
pnpm --dir ui exec vitest run packages/i18n/ packages/app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsx apps/console/src/__tests__/registry-inputs-spec-parity.test.ts packages/plugin-detail/onbc74bc54→ Test Files 442 passed, 1 skipped (443); Tests 4842 passed, 31 skipped. The only later commit types two object-definition reads in the new module.pnpm --dir ui exec vitest run packages/plugin-detail/src/renderers/__tests__/record-path.stageChange-28199.test.tsx→ 14 passed on2837cf76.pnpm --filter @object-ui/plugin-detail run type-checkandpnpm --filter @object-ui/i18n run type-check→ exit 0 (full declaration build of the closure).eslinton the changedplugin-detailfiles → 0 errors; the new module adds no warning.Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack→ 76 families; every one run with stdin closed and its exit code recorded;--ranreconciliation: 76 derived, 76 run, 0 NOT-MEASURED, 0 UNRUN.bc74bc54)check:skill-examplesanswered exit 3 (PREREQUISITE NOT MET: nopackages/specdeclarations) and exit 0 after a declaration build; on2837cf76all 76 answered exit 0 in one pass.node scripts/check-sdui-manifest.mjs→ exit 0 (present and intact, recorded by the in-tree producer).pnpm check:new-line-citations(ui) → 0 new citations.Human Minimum
packages/specholds no runtime logic. (packages/specuntouched.)pnpm lintpasses. (Changed files linted locally; the repo-wide run is CI's.)main, one pull request.packages/spectouched: n/a.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code