Skip to content

fix(app-shell): on a read-only item, the Properties panel shown with nothing selected says why its controls are disabled - #29958

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-mdirva
Nov 3, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-mdirva

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Yibo Wang · project thread

Fixes #29897

维护者速读

  • 改了什么:元数据编辑页(Studio「所有元数据」条目页)在锁定、只读包等只读状态下,未选中任何元素时显示的「属性」面板,以及无画布页面的通用表单,现在会说明控件为何被禁用:悬停禁用控件或用 Tab 键停到面板时弹出原因提示,读屏器也能读到同一句原因。
  • 为什么改:选中节点时的检查器早已给出原因,但默认属性面板一直静默置灰,键盘与读屏用户完全得不到原因,违反「禁用控件须说明原因」约定(QA 实测 3/3、2/2 复现)。
  • 风险与回滚:低。只在页面层用已有的 InspectorReadOnlyReason 包一层,不改任何注册检查器的契约;可写条目渲染与之前完全一致。回滚即还原 ResourceEditPage.tsx 一个文件。
  • 先看:ResourceEditPage.tsx 的 withReadOnlyReason 及三处包裹点;ResourceEditPage.inspectorReadOnlyReason-29079.test.tsx 新增的 objectstack#29897 describe 块。
  • 两分钟验证:在 showcase 中打开 /_console/studio/~all/metadata/object/showcase_task,不选中任何字段,悬停「Label」输入框,应弹出以「This item is locked and cannot be edited or deleted.」开头的原因提示;按 Tab 能停到属性面板并弹出同一句;换一个可写包的条目,面板可编辑且无提示。
  • 需要你做的:无,席位落地。

Clause-②: no
Metadata-protocol: none

What changes

  • @object-ui/app-shell, ResourceEditPage.tsx. The page wraps the panels it draws itself in InspectorReadOnlyReason (the wrapper the flow node and edge inspectors already use), handing them the same inspectorReadOnlyReason the scoped inspector gets. Three sites: the registered default inspector shown with nothing selected (object, view, dashboard, page, report, dataset, action, hook), the generic SchemaForm beside a canvas when the type registers no default inspector (flow), and the SchemaForm of a page with no canvas. The wrapper draws nothing unless the form is read-only and the reason is non-blank, so a writable item and view mode render exactly as before.
  • No contract change. MetadataDefaultInspectorProps is untouched and no registered default inspector was edited: the host draws the reason around whatever is registered. The scoped-inspector branch is unchanged (the inspector wraps itself, as since fix(app-shell): the metadata editor page tells its scoped inspector why it is read-only #29203).
  • The group's accessible name is the panel's own label (engine.edit.inspector.properties, "Properties"), an existing key in every locale.

Tests

New top-level describe in the existing page harness ResourceEditPage.inspectorReadOnlyReason-29079.test.tsx (the real page, the real ObjectDefaultInspector and the real SchemaForm; only the canvases and data reads are stubbed):

  • Locked object and locked flow, nothing selected: the Properties panel is a tabindex=0 group named "Properties" whose accessible description is the lock sentence plus the served lock reason, and every form control in it is disabled (or, for the generic form's text inputs, read-only).
  • Locked object and locked flow: hovering the first disabled control opens a tooltip with the reason.
  • Locked object and locked flow: tabbing from the top of the page lands on the panel, which opens the tooltip with the reason.
  • CONTROL: a writable object renders the panel live (the Label input enabled) with no wrapper and no reason.
Ablation (drop the prop)

node scripts/ablation-replace.mjs replaced the wrapper's reason={inspectorReadOnlyReason} with reason={undefined /* ablated-29897 */} (anchor 1 → 0, blob a324e465 → 520890e8), then ran the file: 6 failed | 7 passed (13). The six failures are exactly the six new locked-item cases; the control and the six existing #29079 cases stayed green. Restored: blob == HEAD (a324e465), git diff HEAD empty.

Acceptance notes

  • The generic form's text inputs (mdf-name, mdf-label on a flow) are rendered readonly, not disabled, so they still take focus on their own; the reason reaches them through the described panel group around them. The disabled controls (the flow's Type select, the object panel's inputs) are the ones the tooltip and the group speak for.
  • A page without a canvas in view mode (writable, not editing) still draws no reason: the page offers an Edit button there and inspectorReadOnlyReason returns none for view mode, as before. The comment on inspectorReadOnlyReason now says so.
  • The Source tab (JsonSourceEditor) is unchanged; it is out of this card's scope.
  • No README or docs page change: this is an accessibility fix to an existing panel, not a new feature or prop.

Verification

All readings at head d9aae973 on objectstack-ai/objectstack, merge base 21510bba; heavy runs under scripts/pm/os-verify-lock.sh on a shared box.

Local package checks
  • pnpm turbo run build --filter='@object-ui/app-shell^...' --concurrency=2: 64/64 tasks, exit 0.
  • pnpm --filter @object-ui/app-shell build: exit 0.
  • pnpm --filter @object-ui/app-shell run type-check (tsc --noEmit and tsc -p tsconfig.test.json): exit 0.
  • pnpm --dir ui exec eslint on the two touched ui files: 0 errors, 51 warnings, none on a line this PR adds or changes.
  • pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/ResourceEditPage.inspectorReadOnlyReason-29079.test.tsx: 13 passed (13).
  • pnpm --dir ui exec vitest run --maxWorkers=3 packages/app-shell/: Test Files 2166 passed, 1 skipped (2167); Tests 19243 passed, 9 skipped; exit 0.
Derived gates (dispatch-gates --commands, 35 families)

node scripts/pm/dispatch-gates.mjs --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN, exit 0.

node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0

🤖 Generated with Claude Code

https://claude.ai/code/session_01WGufziRkHRHwEC3eQwnrwx

…ays why

The metadata editor page now wraps the panels it draws itself (the
registered default inspector shown with nothing selected, and the generic
SchemaForm beside or without a canvas) in InspectorReadOnlyReason, handing
them the same reason the scoped inspector already gets. A locked item's
disabled controls explain themselves on hover, on keyboard focus and as an
accessible description; a writable item renders as before.

Claude-Session: https://claude.ai/code/session_01WGufziRkHRHwEC3eQwnrwx
Co-authored-by: Claude <noreply@anthropic.com>
…on; add changeset

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

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · os-support-ai · session_01WGufzjDyeFwq6AuFu3vwTd

维护者速读(席位终稿)

  • 改了什么:Studio「所有元数据」条目页在锁定或只读时,没选中任何元素时显示的「属性」面板(以及没有画布的页面的通用表单)现在会说明控件为什么不能改:鼠标悬停、键盘 Tab 停到面板、读屏器都能拿到同一句原因。
  • 为什么改:选中节点时的检查器早就会说原因,默认属性面板却一直静默置灰,键盘和读屏用户完全不知道原因,违反「禁用控件须说明原因」的约定。
  • 风险与回滚:低。只在页面层用已有的 InspectorReadOnlyReason 包一层,不改任何注册检查器的契约;可写条目渲染不变。回滚即还原 ResourceEditPage.tsx。
  • 先看:ResourceEditPage.tsx 的 withReadOnlyReason 与三处包裹点。
  • 两分钟验证:打开 /_console/studio/~all/metadata/object/showcase_task,不选中字段,悬停「Label」输入框,出现以「This item is locked and cannot be edited or deleted.」开头的提示;换可写包条目,面板可编辑且无提示。
  • 需要你做的:无,非受管面,CI 全绿后席位落地。
  • 席位意见:ACCEPT。复用 fix(app-shell): the metadata editor page tells its scoped inspector why it is read-only #29203 的同一个包裹组件,三处入口都覆盖,消融 6 条全红、对照保持绿。

席位核对 · ACCEPT · head d9aae973998d2bcf71dce3bd4bdca658b3ac8db6 · 2026-11-03T17:48Z

  1. Shape: draft, base main, attribution block then Fixes #29897 (whole card lands). One changeset (@object-ui/app-shell patch) with Clause-②: no / Metadata-protocol: none; no content/docs/releases/; 3 files, +194/−54. check-governed-merges --pr 29958: NOT governed, 248 lines ≤ 3000. No contract face; this seat's read is the review of record.
  2. Premise, measured: read in the diff against origin/main 21510bba: the default inspector (~L3566), the canvas-side SchemaForm and the no-canvas SchemaForm received only readOnly. The diff wraps all three in InspectorReadOnlyReason (inspectors/_shared.js, the wrapper fix(app-shell): the metadata editor page tells its scoped inspector why it is read-only #29203 introduced) with the page's existing inspectorReadOnlyReason; no registered-inspector prop changed, so no implementer outside this file is touched. The wrapper draws nothing unless read-only with a non-blank reason, so writable items render as before.
  3. Gates: dev's local union at d9aae973: the test file 13/13, full app-shell suite green, dispatch-gates --commands 35/35 exit 0; ablation (reason dropped) turns exactly the 6 new locked-item cases red, the CONTROL and the 6 Studio metadata editor page: the flow node inspector on /studio/PKG/metadata/flow/NAME is read-only with no reason, because ResourceEditPage folds three causes into formReadOnly and passes no readOnlyReason #29079 cases stay green. CI on this head was in progress at this reading; landing waits for every check green or expected-skip.
  4. Accepted deviation: on a flow's generic form the text inputs render readonly (focusable), not disabled; the reason reaches them through the described panel group around them. That meets the convention's three readers (hover, focus, screen reader) through the group. Accepted.
  5. Out of scope: the Source tab (JsonSourceEditor) unchanged — dropped, not in the card's clauses. Skills-docs: not owed. mcp_calls: 2 reads, no write tool.
  6. Landing: ordinary queue. When every check on this head is green or expected-skip: relay pr_ready + automerge_enable, follow to MERGED, record the landing on Studio All-metadata item page: on a locked item the Properties panel shown with nothing selected disables every control with no reason on hover, keyboard focus or screen reader #29897, then dispatch Studio metadata editor: after the server refuses an autosave 422, the status chip keeps reading "Auto-saving…" although no further save is attempted #29901 (same file, serial).

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 3, 2026 18:17
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 3, 2026
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 04cbdf7 Nov 3, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-mdirva branch November 3, 2026 19:50
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