Skip to content

fix(app-shell): the metadata editor page tells its scoped inspector why it is read-only - #29203

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-bh1y5h
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-bh1y5h

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #29079

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:元数据编辑页(Setup 的条目页,以及 Studio「全部元数据」下的 /studio/包/metadata/flow/名称)现在会把「为什么只读」告诉右侧的节点属性栏。属性栏显示的原因,就是编辑器上方提示条对当前原因说的那句话:只读软件包、锁定、缺少 manage_metadata 能力、代码包提供的条目、运行时只读的类型,以及安全目录的隔离墙。没有新增文案。
  • 为什么改:Studio flow node inspector: on a read-only package every control is disabled with no reason on hover, keyboard focus or to assistive tech #28985 之后,Studio 自动化页的流程节点属性栏会解释灰掉的控件,但同一个属性栏放在元数据编辑页上时,宿主不传原因,控件仍然灰着却没有任何说明。
  • 风险与回滚:低。只多传一个可选属性 readOnlyReason,且只传给按选中项打开的属性栏;可写时不传,渲染与之前相同。未选中时的默认属性栏不变。回滚即还原本 PR。
  • 先看:ResourceEditPage.tsx 中 formReadOnly 下方新增的 inspectorReadOnlyReason(原因的先后顺序与上方提示条一致),以及 InspectorComponent 调用处新增的一行。
  • 两分钟验证:在 ui/ 下运行 pnpm exec vitest run packages/app-shell/src/views/metadata-admin/ResourceEditPage.inspectorReadOnlyReason-29079.test.tsx,预期 6 个测试全绿;去掉调用处那一行后 5 个变红。
  • 需要你做的:无,席位落地。

What changes

  • ResourceEditPage derives inspectorReadOnlyReason next to formReadOnly and passes it to the scoped inspector (InspectorComponent) as readOnlyReason, the prop Studio flow node inspector: on a read-only package every control is disabled with no reason on hover, keyboard focus or to assistive tech #28985 added to MetadataInspectorProps. The sentence is the one the page's own notice gives for the cause in force, in the notices' order:
    1. the walled security catalog: engine.catalog.readOnly.walled;
    2. a read-only package (Studio's "All metadata" area): engine.studio.pkg.readonlyHint, the sentence Studio's Automations pillar passes;
    3. a lock: the lock banner's title, then the lockReason the server serves;
    4. a declaration-only catalog: its engine.catalog.declaredOnly.hint sentence;
    5. a caller without manage_metadata: engine.edit.capabilityReadOnly;
    6. an item a code package ships: engine.edit.artifactLockedBanner;
    7. a type that is read-only at runtime: engine.edit.readOnlyTypeBanner.
      An editable page passes none.
  • No string is new, so no i18n pack changes: every sentence is an existing key the page already shows above the editor.
  • The no-selection default inspector is unchanged. MetadataDefaultInspectorProps declares no readOnlyReason, and widening it is outside this card.

Deviations

The card asks for three causes on the node inspector: no write access, a pending walled decision, and view mode pointing at Edit. Measured on main 87d6baef, only the first can reach the flow node inspector on this page:

  • Walled applies only to the security catalog types (position, permission, capability), and none of them registers a scoped inspector. The page still names the wall first, so an inspector a host registers for one of those types gets the right sentence and not the capability one. The test pins that through a host inspector registered for position.
  • View mode does not reach a scoped inspector. The inspector renders only beside a designer canvas. A designer type enters editing as soon as the item can be written (the designer auto-on effect), stays in editing after save and reset, and has no Edit button (the Edit button renders only when there is no preview). A sentence pointing at Edit would point at nothing, so view mode passes no reason. The seat accepted this shape before code.

Tests

  • New: ResourceEditPage.inspectorReadOnlyReason-29079.test.tsx, 6 cases. The real page, gates and FlowInspector → FlowNodeInspector; only the canvases (to emit a selection) and the data reads are stubbed. Each case opens the item, selects on the canvas and reads the accessible description of the node inspector's reason group:
    • a writable flow: no reason group, and Remove node is enabled;
    • a read-only package's area, a caller without manage_metadata, a locked item with a served reason, and a flow a code package ships: each shows its own sentence;
    • the walled catalog: a host inspector registered for position receives readOnly and the wall's sentence.
  • Red on main: the same file on 87d6baef reads 5 failed, 1 passed (only the writable control passes).
  • Ablation: deleting the readOnlyReason={inspectorReadOnlyReason} line through scripts/ablation-replace.mjs reads 5 failed, 1 passed; restored, blob equals HEAD and git diff HEAD is empty.

Verification

All readings on head 162f85c0, base 87d6baef.

Tests
  • pnpm exec vitest run (from ui/) on ResourceEditPage.inspectorReadOnlyReason-29079.test.tsx: 6 of 6 passed. The same file on 87d6baef: 5 failed, 1 passed.
  • Ablation of the readOnlyReason={inspectorReadOnlyReason} line (scripts/ablation-replace.mjs, anchor 1 to 0, blob 9e74e863 to 5d2abee0): 5 failed, 1 passed; restored to the HEAD blob, git diff HEAD empty.
  • Sweep of the 120 ui test files that git grep finds naming ResourceEditPage, MetadataResourceEditPage or readOnlyReason, in three locked batches at --maxWorkers=2: 40/40 files (364 tests), 40/40 (204), 40/40 (547). Narrowed on purpose: CI's Test UI runs the rest of app-shell.
  • pnpm exec turbo run type-check --filter=@object-ui/app-shell: 65 of 65 tasks successful.
  • eslint on the two changed ui files: 0 errors; 51 warnings, the same count ResourceEditPage.tsx carries on main, none in the new test.
Gates
  • node scripts/pm/dispatch-gates.mjs --commands derived 34 families; all 34 ran with exit 0: the 33 unlocked ones with this body as the PR event (check-adr-0087-registration, check-changeset-no-major, check-closing-keyword-parity and check-sdui-manifest among them), and pnpm --dir ui exec vitest run scripts/ locked: 169 files passed, 2 skipped (4,900 tests).
  • dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN.
  • check:new-line-citations: 0 new citations.

Generated by Claude Code

… its scoped inspector

ResourceEditPage passed formReadOnly to the scoped inspector with no
readOnlyReason, so a flow's node inspector on the metadata editor page
showed disabled controls with nothing to say why. The page now passes the
sentence its own notice gives for the cause in force: the walled catalog,
a read-only package, a lock, a declaration-only catalog, a caller without
manage_metadata, a code-package item, or a runtime read-only type. View
mode passes none: a designer type is always editing while writable.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jUgMp6a6PrErVUDx8h
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling labels Nov 2, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

席位核对 · ACCEPT · 2026-11-02T09:30Z

Head-sha: 162f85c0a31bef819bd0effbee669de229ffa2e4

  • Shape:
  • Read in the diff:
    • inspectorReadOnlyReason is undefined whenever formReadOnly is false, so a writable page renders as before.
    • The causes follow the notices' order: walled, then the read-only package, lock (banner title plus the served lockReason), declaration-only, capability, code-package artifact, and runtime read-only type. Each one reuses the sentence its notice already shows.
    • View mode passes no sentence, as accepted before code. The no-selection default inspector is untouched.
  • Gates (check-runs on this head): 44 success, 11 skipped, 0 failed or pending. mergeable_state is clean.
  • Tests (dev):
    • 6 new cases on the real page and FlowNodeInspector. On 87d6baef the file reads 5 failed and 1 passed.
    • Ablation of the readOnlyReason line: 5 failed; restored.
    • Sweep: 120 files, 1,115 tests. Type-check 65 of 65. Derived gates 34 of 34.
  • NOT MEASURED: the seat ran no live session.
  • Findings: none. Walled reaches no registered scoped inspector today, and the test pins it through a host inspector registered for position.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #29079 closes the card on merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

1 participant