Skip to content

fix(app-shell): name Studio's group-title, Description, Help text and nav-item inputs - #26926

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-dq6ksb
Oct 27, 2026
Merged

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #26732

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio 里五个输入框以前读屏软件读不出名字:表单设计器里分组标题的行内输入框、字段属性面板的「描述」和「帮助文本」、界面导航项属性面板的「链接到对象」下拉和「标签」输入框。现在每个都有可读的名字,点击标签也会聚焦到对应输入框。外观和保存内容都不变。
  • 为什么改:QA 读无障碍树时发现这几处是无名编辑框(studio-qa-2026-10-27,U7),自动化无障碍检查也会报错。
  • 风险与回滚:很低。只加了 id/htmlFor 关联和一个 aria-label,没有新文案键,不动元数据和 spec。一个旧测试钉住了「对象下拉没有名字」,本 PR 把它改为钉住新名字。回滚即 revert。
  • 先看:StudioDesignSurface.tsx 里 StudioNavItemInspector 的两处 htmlFor;ObjectFieldInspector.tsx 的 TextareaField;StudioDesignSurface.sharedSelect-11865.test.tsx 改掉的那条断言。
  • 两分钟验证:在 Studio 打开一个应用的导航项,点「链接到对象」这几个字,预期下拉获得焦点;或在浏览器无障碍面板里看到该下拉名为 "Link to object"。
  • 需要你做的:无,席位落地。

What changes

  • Form designer group title (ObjectFormDesigner.tsx): a declared group's inline title input element had no label, aria-label or id. No visible label sits beside it, so it takes aria-label from the label the group inspector already gives the same value, engine.studio.designer.group.nameLabel ("Group name" / 「分组名称」). No new key.
  • Field inspector Description and Help text (ObjectFieldInspector.tsx): the file-local TextareaField drew its Label beside the textarea element without closing the pair. It now mints a per-instance React.useId() and sets htmlFor ⇄ id, the way _shared.tsx's form atoms (InspectorTextField, InspectorNumberField) close theirs. Every TextareaField in the inspector gets its name from this one change.
  • Interfaces nav-item inspector (StudioDesignSurface.tsx, StudioNavItemInspector only): the Link to object label and the Label label were drawn above their controls without htmlFor. Both now close the pair with a useId(), as the same inspector's target, URL, Open in and icon fields already did. The object picker is the shared StudioPicker, which already forwards id to its Radix trigger, so no component changed; its header comment now says the object picker is named like the others.

Tests

  • ObjectFieldInspector.textareaNames-26732.test.tsx: Description and Help text found by getByRole('textbox', { name }) and getByLabelText in en; a zh case awaits loadStudioCatalogue('zh') at module scope (the test(app-shell): flowCanvasChip-11665 awaits the lazy studio zh catalogue before reading the tooltip #26800 pattern) and finds both by 「描述」 / 「帮助文本」.
  • ObjectFormDesigner.groupTitleName-26732.test.tsx: the group-title input found by getByRole('textbox', { name: 'Group name' }), holding the group's label.
  • StudioDesignSurface.navItemInspectorNames-26732.test.tsx: the object picker found by getByRole('combobox', { name: 'Link to object' }) (and it is the nav-link-object trigger), the Label input by getByRole('textbox', { name: 'Label' }).
  • StudioDesignSurface.sharedSelect-11865.test.tsx: its pin "the object picker had none" now reads the object picker's name as Link to object.
  • Ablation (one-off, not kept), each with the fix committed, through node scripts/ablation-replace.mjs (anchor 1 → 0, restored blob equal to HEAD each time): dropping the group input's aria-label reds its test (1 failed of 1); dropping htmlFor={id} from TextareaField reds both textarea cases (2 failed of 2); dropping the object picker's id reds the nav test, and so does dropping the Label input's id (1 failed of 1 each). git diff HEAD empty after all four.

Acceptance notes

  • Sweep of the three files for the same hole. ObjectFormDesigner.tsx has no other unnamed input (its icon buttons all carry aria-label). In ObjectFieldInspector.tsx, every control other than TextareaField is a _shared.tsx atom that already closes its pair, an InspectorComboField with a label or ariaLabel, or a checkbox inside its label element; the picklist option rows' value and label inputs are named by their placeholders ("Value", "Label") and the color swatch by its title, so they are not unnamed and are left as they are. In the nav-item inspector, the type radios sit inside their labels and the remaining fields were already tied.
  • A pinned behaviour is reversed on purpose. StudioDesignSurface.sharedSelect-11865 pinned that the object picker kept the native control's lack of a name; this card asks for that name, so the pin now reads it.

Verification

All readings at head 67406db6 (base 2720874a), under scripts/pm/os-verify-lock.sh with --maxWorkers=1.

Touched package: @object-ui/app-shell
  • Dependency closure: pnpm exec turbo run build --concurrency=2 --filter='@object-ui/app-shell^...', 63 tasks, VERDICT command-exit 0. Then pnpm --filter @object-ui/app-shell type-check (tsc --noEmit and tsc -p tsconfig.test.json, so the tests too): VERDICT command-exit 0.
  • The four new or edited test files: Test Files 3 passed (3), Tests 4 passed (4); StudioDesignSurface.sharedSelect-11865: Tests 79 passed (79).
  • Narrowed app-shell run: every test file naming ObjectFormDesigner, ObjectFieldInspector, StudioNavItemInspector, nav-link-object or InterfacesPillar (89 files). First run at a3764046: 1 failed, 892 passed, the sharedSelect-11865 pin of the unnamed object picker, updated in 67406db6 and green after. The rest of app-shell is left to CI's Test UI shards.
  • ESLint with ui/eslint.config.js on the seven touched files: 0 errors, and no warning on a changed line.
Derived gates
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 34 commands for the 8 changed paths (same list at both heads); all 34 exit 0, each code captured before any pipe, among them check:nul-bytes, check:test-source-alias, check:cross-package-test-inputs, check:type-check-coverage, check:type-check-debt, check-sdui-manifest, check-empty-changeset and check-changeset-no-major. pnpm --dir ui exec vitest run scripts/: Test Files 178 passed, 2 skipped (180), Tests 5065 passed, 2 skipped.
  • --ran reconciled: "34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED".
  • PR-body gates on this body: check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-partof-closing-keyword, all exit 0. pnpm --dir ui run check:new-line-citations: 0 new citations.
  • Families CI runs over the whole tree (type-check lanes, lint, artifact rosters) are CI's; the PR's check-runs are the reading.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (lint is CI's)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (not touched)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QsR2jT6kwaZ4RiKsDR3s5f


Generated by Claude Code

… nav-item inputs

The form designer's inline group-title input takes the group inspector's
"Group name" label as its aria-label. The field inspector's local
TextareaField closes its label/textarea pair with a per-instance useId(),
which names Description and Help text. The nav-item inspector ties its
"Link to object" and "Label" labels to their controls with htmlFor.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jT6kwaZ4RiKsDR3s5f
…by its Link to object label

The shared-Select suite pinned that the object picker had no accessible
name, as its native control had none. The picker is now tied to its
visible label, so the pin reads that name instead.

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

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · seat domain:ui#4 · session_01QsR2jTfvjNTaR29ehLk26T · 2026-10-27T21:49Z · head 67406db6830d639495c117ebea029a5c84db2b5a

  1. Shape: draft, base main, Fixes #26732. Clause-②: no and Metadata-protocol: none are in the body and the changeset, and they match the claim (6453119914). Eight files, all inside the claimed surface: ObjectFormDesigner.tsx (+3), ObjectFieldInspector.tsx (+5/−1, TextareaField), StudioDesignSurface.tsx (+12/−3, the nav-item inspector and the StudioPicker doc line), three new test files beside, the sharedSelect-11865 pin, and one @object-ui/app-shell patch changeset. No i18n row, no key, no new component, no packages/spec/**.
  2. Premise, measured: the seat read the diff.
    • The inline group-title input takes aria-label from the existing engine.studio.designer.group.nameLabel, the group inspector's own name label.
    • TextareaField mints an id with useId and ties its Label htmlFor to it, so Description and Help text are named.
    • The nav-item inspector's "Label" input and "Link to object" StudioPicker are tied to their drawn labels by useId plus htmlFor.
    • The thread's sweep found no other unnamed input in the surface.
    • Three new files with 4 tests are green, and each of the 4 ablations reddens.
  3. Gates, pinned to the head: check-runs?filter=latest 43 success, 9 skipped, 0 failing or pending · check-governed-merges --pr 26926: NOT governed, +219/−11. mergeable_state: clean. origin/main 8074feb6 carries none of these names (no group.nameLabel aria-label in ObjectFormDesigner.tsx, no objectFieldId in StudioDesignSurface.tsx), so nothing here is already landed.
  4. Accepted deviations: StudioDesignSurface.sharedSelect-11865.test.tsx pinned "the object picker had none". That is now false by design, so the pin is updated to assert the label names the trigger, and StudioPicker's header comment is updated with it. Neither is a weakened assertion.
  5. Out of scope: none. No skip, quarantine or raised timeout. Skills-docs: is not owed.
  6. Prose face, checked against the diff: the changeset names the five inputs the code changes, and says nothing visual and nothing saved changes, which the diff bears out (ids, htmlFor, one aria-label).

Landing: no contract review is owed (no published schema, no governed text, Clause-②: no). The seat marks the PR ready and arms auto-merge. On MERGED, Fixes #26732 closes the card.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 21:50
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 21:50
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 7a2818c Oct 27, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-dq6ksb branch October 27, 2026 22:16
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

2 participants