Skip to content

fix(plugin-list, app-shell): "Reset to view default" clears the stored list setting instead of copying the view into it - #29044

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

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #28948

Clause-②: yes (widening)
Metadata-protocol: none

维护者速读

  • 改了什么:列表「显示」里的「恢复视图默认设置」和排序面板里的「恢复视图默认排序」,现在清除读者自己存下的那部分偏好(行高、隐藏列、排序),不再把视图当时的默认值当成读者的选择写进去。条目清空后整条删除,⋯ 里的「重置视图」随之消失。
  • 为什么改:原来恢复默认会把旧默认值存成读者的选择,管理员之后修改视图的行高、隐藏列或排序,这位读者仍停在旧值上,⋯ 也一直显示「重置视图」。
  • 风险与回滚:只动 ui/ 的 plugin-list(ListView 新增宿主属性 onRestoreViewDefaults,viewDefaults 多一个 sort)和 app-shell(对象页接上这两个属性,恢复时把对应部分置空)。不动 spec、服务端和元数据。读者主动的「不排序」(sort: [])和「显示全部列」(hiddenFields: [])照旧保存。不接新属性的宿主行为不变。回滚 = revert 本 PR。
  • 先看:ui/packages/plugin-list/src/ListView.tsx 的 resetDisplayToViewDefault 与 handleResetSort;ui/packages/app-shell/src/views/objectViewListRenderer.tsx 的 restoreViewDefaults;新测试 ListView.restoreViewDefaults-28948.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-list/src/__tests__/ListView.restoreViewDefaults-28948.test.tsx packages/app-shell/src/views/ObjectView.userListState-12418.test.tsx,应 2 个文件全部通过(6 + 32 个用例);或在 Console 线索列表改行高后点「恢复视图默认设置」,该用户的 sys_user_preference 条目里不再有 rowHeight。
  • 需要你做的:无,席位落地。

What changes

@object-ui/plugin-list — ListView

  • New host prop onRestoreViewDefaults(parts), where parts is drawn from 'sort' | 'hiddenFields' | 'rowHeight'. When a host wires it, the Display control's "Reset to view default" and the sort popover's "Reset to view default" call it with the parts they returned to the view's own, in one call, and no longer write the view's values through onHiddenFieldsChange, schema.onDensityChange or onSortChange for those parts. The list puts the view's sort and hidden fields back at once; the table density follows schema.rowHeight once the host's clear lays the view's own back there.
  • viewDefaults gains sort (a pick of ListViewSchema's hiddenFields, rowHeight and sort). The sort popover's reset compares against it (enabled state, whether it is drawn) and restores it. As with the other two members, a passed viewDefaults is the whole baseline: an absent sort means the view declares none.
  • Without onRestoreViewDefaults (and without viewDefaults), both resets behave exactly as before. Layout, grouping, row color, row numbers, inline edit and the gallery card size reset as before in every case.

@object-ui/app-shell — the object page's list

  • Hands viewDefaults.sort (the view's own sort, under the link's or user's stored sort that the sort rung lays over it) and wires onRestoreViewDefaults to restoreViewDefaults, which patches each named part to null on the user's list state (listPrefs.patchView). patchViewPreference already treats null as a clear and removes a view left with nothing, so "Reset view" disappears with the last part. A sort reset also takes the sort off the URL (writeListUrlState({ sort: null })).
  • ListPreferencesProvider: docblock only — ListViewPreferencePatch now names the list's per-part reset as the second way back to the view's own.

Tests

  • ui/packages/plugin-list/src/__tests__/ListView.restoreViewDefaults-28948.test.tsx (new, 6 cases): the Display reset names hiddenFields and calls no onHiddenFieldsChange; names rowHeight, calls no onDensityChange, and follows the host's re-rendered schema.rowHeight; both differ ⇒ one call naming both; the sort reset returns to viewDefaults.sort (server $orderby moves from the user's to the view's), names sort, calls no onSortChange; CONTROL: removing the last sort level still emits onSortChange([]); CONTROL: row numbers reset without naming anything.
  • ui/packages/app-shell/src/views/ObjectView.userListState-12418.test.tsx — new describe at the host seam (real ObjectView, real ListPreferencesProvider, recorded list-state family), 6 cases: the list is wired and handed the view's sort; a Display reset leaves neither density nor hidden fields in the saved row; after it, a changed view rowHeight / hiddenFields reaches the user on the next open; a sort reset with nothing else stored saves {} and the ⋯ "Reset view" entry goes; after it, a changed view sort reaches the user; CONTROL: a deliberate sort: [] and hiddenFields: [] are saved and survive a reload. The three viewDefaults equality pins now include sort; the old "the list's reset writes through the doors" case is renamed to what it pins (a choice equal to the view's own is stored as a choice).
Ablation (scripts/ablation-replace.mjs, source-resolved, no dist)
  • Sort reset back to the door (if (onRestoreViewDefaults) onRestoreViewDefaults(['sort']); else emitSortChange(restored); to emitSortChange(restored);): 1 failed (the sort reset case), 5 passed. Restored, blob equal to HEAD, git diff HEAD empty.
  • Density leg removed (the else if (onRestoreViewDefaults) branch dropped, so the density goes through density.setMode): 2 failed (the density case, the both-parts case), 4 passed. Restored, blob equal to HEAD, git diff HEAD empty.
  • Host stores the view's values instead of clearing (patch[part] = null to the view's value per part): 4 failed in the host file (both "leaves nothing stored" cases and both "follows the view on the next open" cases), 28 passed. Restored, blob equal to HEAD, git diff HEAD empty.

Acceptance notes

Verification

All on the final head eda72c06 (base origin/main fed3a51b), after pnpm install --frozen-lockfile and turbo run build --filter='@object-ui/app-shell^...' --filter='@object-ui/plugin-list^...' plus formula, sdui-parser, lint and client (64 tasks, exit 0), under scripts/pm/os-verify-lock.sh.

  • The whole packages/plugin-list/ vitest suite plus 16 app-shell / console / plugin-view test files that name the touched modules or props (git grep -l of objectViewListRenderer, ListPreferencesProvider, viewDefaults, listPrefs, patchView, onHiddenFieldsChange, onDensityChange, the two reset test ids), --maxWorkers=2: 196 files, 1907 tests passed. A declared narrowing for app-shell; CI's Test UI runs the rest.
  • pnpm --filter @object-ui/plugin-list run type-check and pnpm --filter @object-ui/app-shell run type-check (the test programs included): exit 0.
  • ESLint on the five changed tsx files: exit 0, 0 errors (existing warnings only).
  • Derived gates (node scripts/pm/dispatch-gates.mjs --commands): 35 of 35 run, each exit 0 (check:type-check-debt and pnpm --dir ui exec vitest run scripts/ under the lock; the latter 169 files passed, 2 skipped), including node scripts/check-sdui-manifest.mjs and the PR-body gates with this body as GITHUB_EVENT_PATH. --ran reconciles 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. check-partof-closing-keyword with PR_BODY: exit 0. ui check:new-line-citations: 0 new citations.
  • origin/main moved to ab085a04 since the base; none of its commits touch the five changed files, so no merge was taken before opening.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QsR2jTivKAK8N8dfW5mn9D

@github-actions github-actions Bot added size/l 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-02T06:34Z

Head-sha: eda72c067e0cbbc3cfd0af4246fc1be8dad0d3ab

  • Shape:
    • The PR is a draft against main. The first card line is Fixes #28948, and no other card sits beside a closing keyword.
    • 6 files, +471 / −35, inside the claimed surface (6569776892). No governed path: check-governed-merges --pr 29044 reports NOT governed.
    • Clause-②: yes (widening) and Metadata-protocol: none start their lines in the body and the changeset, as claimed: ListView gains the optional host prop onRestoreViewDefaults(parts) and viewDefaults.sort. The changeset is patch.
  • Read in the diff:
    • Both resets ("Reset to view default" in the Display control and in the sort popover) now name the parts they put back instead of writing the view's values through the change callbacks.
    • The Console host patches each named part to null (patchView), so the stored preference no longer pins the old default; a view left with nothing is removed, and "Reset view" goes with it. A sort reset also leaves the URL, which would otherwise seed it again.
    • A deliberate sort: [] or hiddenFields: [] still arrives through persistListSort / persistHiddenFields and stays stored. The provider change is a docblock only.
    • Behaviour note, stated in the PR: the Console's sort reset now returns to the view's own sort, not the sort the list opened with. That is what the card asks (the reader follows the view).
  • Gates (check-runs on this head): 44 success, 11 skipped, 0 failed or pending. mergeable_state is clean.
  • Tests (dev): new restoreViewDefaults-28948 and the extended userListState-12418; plugin-list in full plus 16 host files, 196 files and 1907 tests. Type-check plugin-list and app-shell exit 0. Three ablations each red, then restored. Derived gates 35 of 35.
  • NOT MEASURED: the seat ran no live session.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #28948 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/l tooling

Projects

None yet

1 participant