Skip to content

fix(plugin-list): a list view locked by lockedBy alone shows its lock indicator - #29312

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

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-cet2if

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #29009

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:列表视图的 sharing 只写了 lockedBy、没写 type 时,工具栏现在会显示锁定标记「Locked by 用户」,旁边的类型标签按 spec 默认值显示为「Shared view」。写了 type 的视图显示不变;sharing 里两个键都没写时什么都不显示。
  • 为什么改:spec 把 type 默认为 collaborative,但下发的视图是作者原文、不带默认值,而工具栏只在 type 存在时才画这个标记,所以「只写 lockedBy」的已锁定视图对其他人看不出被锁。现在锁定标记只看 lockedBy,以后 spec: retire the two inert personal declarations — a view marked personal is visible to everyone, and the docs promise personal views that do not exist #29037 退役 personal 或 type 也不会再把它藏掉。
  • 风险与回滚:只改工具栏一个只读标记的显示条件,没有新的元数据键、选项或文案;默认类型从 spec 的 ViewSharingSchema 读取,不在 ui 里重抄。回滚即 revert 本 PR。
  • 先看:ui/packages/plugin-list/src/ListView.tsx 里 hasSharingIndicator 和 SPEC_DEFAULT_SHARING_TYPE,以及 sharing 标记块与分隔线的 hasLeftSideItems;ListView.test.tsx 的 sharing spec format — additional。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-list/src/__tests__/ListView.test.tsx,应 158/158 通过,其中「shows the lock from sharing.lockedBy with no type」一条。
  • 需要你做的:无,席位落地。

What changes

  • The lock keys on lockedBy, not on type. The toolbar's read-only sharing indicator rendered only under schema.sharing?.type, so a view authored as sharing: { lockedBy: 'admin@objectos.ai' } showed no lock at all. It now renders when sharing declares a type or a lockedBy (hasSharingIndicator), and the lock part depends on lockedBy alone. The toolbar separator's hasLeftSideItems reads the same predicate, so the separator follows the indicator.
  • An absent type shows the spec's default type label. The served view carries the authored body, and nothing on the render path parses it, so type arrives absent. The indicator reads the default from the contract, ViewSharingSchema.parse({}).type (today collaborative, shown as "Shared view"), once at module load, the same way ListView already reads the pagination page size from PaginationConfigSchema. Why the default and not "no badge": per the spec the view IS collaborative, and a view that writes type: 'collaborative' with the same lock already shows "Shared view · Locked by USER", so the two spellings of one contract value now render the same. If spec: retire the two inert personal declarations — a view marked personal is visible to everyone, and the docs promise personal views that do not exist #29037 later retires type, this read stops compiling, which points the author at this spot.
  • Unchanged. A view with type set renders exactly as before; a sharing block with neither key, and a view with no sharing, show nothing; the copy (list.sharingLockedBy, list.sharingPersonal, list.sharingCollaborative) is untouched. No spec edit.

Tests

  • ListView.test.tsx, sharing spec format — additional:
    • The card's reproduction, three rows: sharing: { lockedBy: 'admin@objectos.ai' } with no type, with type: 'collaborative', and with type: 'personal'. Each shows "Locked by admin@objectos.ai" and the title TYPE_LABEL · Locked by admin@objectos.ai.
    • sharing: {} (neither key) shows no indicator and no lock.

Acceptance notes

Verification

Head 57e2c4d1 merges origin/main f2bf2938, which does not touch ui/packages/plugin-list/ or packages/spec/src/ui/; the delta against main is still exactly the three files of this PR. The runs below were taken on b6269b70 (base 8a8a03d3).

Tests and the ablation
  • vitest run packages/plugin-list/src/__tests__/ListView.test.tsx: 158/158 passed.
  • Ablation with scripts/ablation-replace.mjs, replacing the guard {hasSharingIndicator(schema.sharing) && (() => { with the old {schema.sharing?.type && (() => { (anchor 1 to 0, blob ccc95a10 to 9518d23b): 1 failed, 157 passed. The failing case is "shows the lock from sharing.lockedBy with no type (the spec default)". Restored: blob equals HEAD and git diff HEAD is empty.
Package suite, type-check, lint and gates
  • Whole packages/plugin-list/ suite under the verify lock, --maxWorkers=2, two batches: 185 files passed, 1767 tests passed.
  • turbo run type-check --filter=@object-ui/plugin-list: 50/50 tasks, exit 0 (tsc --noEmit && tsc -p tsconfig.test.json, so the test file is compiled).
  • eslint on the two touched files (from ui/): 0 errors.
  • dispatch-gates --commands: 34 derived families, all exit 0, including node scripts/check-sdui-manifest.mjs and pnpm --dir ui exec vitest run scripts/ (169 files passed, 2 skipped). dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED.
  • pnpm check:new-line-citations (ui): 0 new citations.
  • check-closing-keyword-parity, check-changeset-no-major and check-adr-0087-registration were also run against this body.

Generated by Claude Code

… indicator

The toolbar's sharing indicator rendered only under a declared sharing.type,
so a view authored with only lockedBy (the spec defaults type to
collaborative, and the served view carries the authored body) showed no
lock. The indicator now keys on type or lockedBy, and an absent type reads
the spec's ViewSharingSchema default instead of restating it.

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

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m

席位核对 · ACCEPT · 2026-11-02T11:54Z

Head-sha: 57e2c4d1823f038ca73f378edf3f79912ec966f4

  • Shape: draft → main, Fixes #29009 in the body only. 3 files, +74 / −6 (80 lines ≤ 3000). No governed path: check-governed-merges --pr 29312 reports NOT governed (0 of 3 paths). Clause-②: no and Metadata-protocol: none are line-initial in the body and the changeset, as claimed (6575333547). The changeset is patch for @object-ui/plugin-list.
  • Contract review: none owed (Clause-②: no; no export, key, value or copy changes; no spec edit).
  • File surface: inside the claim (ListView.tsx, its test, the changeset), with one declared deviation accepted: the ViewSharingSchema import joins the existing @objectstack/spec/ui import line, and one module-level block (the spec-default read and the hasSharingIndicator predicate) sits beside the existing readSpecDisplayPageSize read rather than inside the sharing block.
  • Read in the diff: the indicator now draws on type or lockedBy; the lock keys on lockedBy alone, so spec: retire the two inert personal declarations — a view marked personal is visible to everyone, and the docs promise personal views that do not exist #29037 retiring personal cannot hide it again. An absent type shows the spec default, read once as ViewSharingSchema.parse({}).type, not restated. The separator uses the same predicate. A block with neither key still shows nothing; a declared type renders as before.
  • Serial: the os-dev merged origin/main f2bf2938 before pr_create. feat(ui): one Personalized marker beside the list title holds the one reset to the view #29266 has since landed and fix(ui): the list flow at phone width: 44 px targets, inset panels, a card pager, the active sort on the bar, and Back that pops cleanly #29273 is still open; their ListView.tsx hunks do not overlap this one, and mergeable_state is clean against today's main.
  • Tests (dev): ListView.test.tsx 158 / 158; whole plugin-list 185 files / 1767 tests; type-check 50 / 50; ablation (back to the type guard) reds exactly the no-type row, restored. Derived gates 34 of 34.
  • Gates (check-runs on this head): 44 success, 11 skipped, 0 failed or pending.
  • NOT MEASURED: a real Console run; covered by the component tests only.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #29009 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/s tooling

Projects

None yet

1 participant