Repository navigation
feat(app-shell,plugin-list): a personal view's own conditions are Filter panel rows, saved back by 保存 - #30242
Conversation
…o the view (#30073) Claude-Session: https://claude.ai/code/session_01QSeKYpFBMr917PmVkG9up7 Co-authored-by: Claude <noreply@anthropic.com>
…k, source cleared (#30073) Claude-Session: https://claude.ai/code/session_01QSeKYpFBMr917PmVkG9up7 Co-authored-by: Claude <noreply@anthropic.com>
#30073) Claude-Session: https://claude.ai/code/session_01QSeKYpFBMr917PmVkG9up7 Co-authored-by: Claude <noreply@anthropic.com>
…rsonal-view-conditions
… enter its write site (#30073) Claude-Session: https://claude.ai/code/session_01QSeKYpFBMr917PmVkG9up7 Co-authored-by: Claude <noreply@anthropic.com>
…rsonal-view-conditions
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41962404343 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41962914067 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
domain:ui#3 · os-justin · session_01QSeKYpFBMr917PmVkG9up7 Queue red, re-queued once · 2026-11-05T04:05Z Two queue builds went red. The last one dequeued this PR (
Re-queue once, on the three facts:
If the same signature fires again, the seat stops re-queueing and hands it on via #30256. Generated by Claude Code |
Fixes #30073
Clause-②: no
Metadata-protocol: none
维护者速读
ui/packages/app-shell/src/views/ObjectView.tsx(保存与另存后的清理)、ui/packages/app-shell/src/views/personalViews.ts(条件变行、保存体)、ui/packages/plugin-list/src/ListView.tsx(「已个性化」的筛选判断)。pnpm --dir ui exec vitest run packages/app-shell/src/views/ObjectView.personalViews-29635.test.tsx,预期 20 个用例全绿。What changes
Ruling A on #30073 (comment 6631079402), the maintainer's words 「其他全部同意」: a personal view's conditions appear as ordinary rows in the filter panel, editing them offers 保存 to that view, saving a view also clears the source view's temporary conditions, and conditions that cannot be folded keep today's refusal. The stored shape does not change and no key is added.
personalViewPanelFiltersinpersonalViews.ts, reading the stored list through@object-ui/core'sbuilderRulesOfSpecFilter, the read direction of the fold). While the panel holds them they are the list's filter: the renderer no longer applies the storedfilterunder the list as well, so each condition is applied once. A stored list the panel cannot hold (an any-of group beside other conditions), or one naming a field the object does not declare or the reader cannot read, keeps today's behaviour: applied under the list, not drawn as rows. The field gate is the one the list state is read back through, so a row it would drop on reload never makes the view select more records than it declares.ListView): a host that shows the view's own conditions as rows passes them asviewDefaults.filters; the panel's finished conditions are then compared with them (field, operator, value, and the logic once two rows make it matter), so the view's own rows are not a personalization and an edit, a removal or "Clear all" is. Without the key, behaviour is as before.sys_personal_view: it builds the body withbuildPersonalViewConfig(the one Save as my view uses, so the storedListViewshape is the same), replaces the row'sconfigthrough the data API'supdate, then clears the reader's list state for that view and the list opens again on the saved view. Nothing is written before the click. A panel the fold refuses (nested_group) shows the same refusal Save as my view gives and writes nothing.uf_*params (clearSourceListState), so neither Back nor the next open of the source brings the conditions back or reads 已个性化.readPanelFilters), not the address's copy: an emptied panel leaves nouf__filterparam, exactly as an untouched one, so the address alone could not tell "removed every condition" from "unchanged".Landing point:
ui/packages/app-shell/src/views/**and the filter-state region ofui/packages/plugin-list/src/ListView.tsx(theviewDefaultsprop type and the personalization judgement); the hidden-fields panel is untouched.Tests
personalViews.test.ts:personalViewPanelFilters(AND list, the fold's OR group, and the three cases that stay under the list);buildPersonalViewConfigwith panel-held conditions (untouched keeps the stored list, edited is the whole filter and parses underListViewSchema, emptied stores none, nested refuses).ObjectView.personalViews-29635.test.tsx, new top-leveldescribein the shared harness: (1) openingpv_mineshowsFilter, 1 active, theParisrow in the panel,Parisonce in the list query, no marker; (2) an edited panel shows the marker, 保存 callsupdate('sys_personal_view', 'pv_mine', { config })withfilter: [{ field: 'city', operator: 'equals', value: 'Rome' }], the body parses underListViewSchema, and the list reopens unpersonalized onRome; no 保存 without the update grant; (3) Save as my view from a filteredv1stores the conditions in the new view, clearsv1's stored list state, and a fresh open ofv1has no condition and no marker; the nested-group panel keeps the refusal and writes nothing; a stored list the panel cannot hold stays applied under the list.ListView.personalization-28950.test.tsx:viewDefaults.filtersequal rows report nothing, edited or emptied rows reportfilters.Acceptance notes
personalViewPanelFiltersbuilds builder rows the way the Studio inspector's privategroupOfStoredRules(metadata-admin/widgets.tsx) does; that file is outside this card's surface, so the two are not merged here.uf__filternow opens with the link's rows as the whole panel (the panel is the filter), rather than those rows laid over the view's stored conditions. Personal views are the reader's own and the address this page writes already carries the whole panel.Verification
All readings on head
3ee4384a5(after mergingorigin/main), objectstack-ai/objectstack.Tests (isolated, as CI shards run them)
pnpm --dir ui exec vitest run --isolate --maxWorkers=2 packages/plugin-list/: Test Files 189 passed (189), Tests 1799 passed (1799); lock VERDICT command-exit 0.ObjectView,objectViewListRenderer,objectViewListUrlState,personalViews,ListPersonalizedMarker),--isolate --maxWorkers=2: Test Files 128 passed (128), Tests 1125 passed (1125); lock VERDICT command-exit 0. The whole package (2177 files) does not fit a local run at two workers; Test UI in CI runs it. The narrowing is by import and is blind to a test that reaches these modules through another import.pnpm --dir ui exec vitest run scripts/(after the seven@objectstackbuilds): Test Files 170 passed, 2 skipped (172); Tests 4985 passed, 2 skipped.pnpm exec turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/plugin-list(each runstsc --noEmitandtsc -p tsconfig.test.json): Tasks 69 successful, 69 total.Reverse verification (each mutation applied by `scripts/ablation-replace.mjs`, which proved it landed and restored it; tree clean after each)
const base = false ? undefined : (): "applied once" goes red,expected [ 'Paris', 'Paris' ] to have a length of 1 but got 2.clearSourceListState(activeView.id)deleted: "Save as my view leaves the view it came from ..." goes red, the source's storedfiltersstill present.viewDefaults.filtersignored inListView: "applied once ... not personalized" goes red, the marker is drawn.Gates
node scripts/pm/dispatch-gates.mjs --commandsderived 35 commands; all 35 run, each exit 0 (check:type-check-debtfirst returned exit 3 PREREQUISITE NOT MET on a lock queue timeout, then re-run under the lock:re-measure: OK, exit 0).--ranreconciliation: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. Alsopnpm check:changeset-fixed(roster under.changeset) exit 0 andpnpm check:new-line-citations0 new citations.Generated by Claude Code