Repository navigation
feat(plugin-list): a reader can add any field they may read to their own list (#30077) - #30162
Merged
objectstack-fleet[bot] merged 10 commits intoNov 5, 2026
Merged
Conversation
…t (WIP) Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
…eset (WIP) Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
…anded Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
…bel in Hide Fields Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
…its definition label Claude-Session: https://claude.ai/code/session_01QSeKYnE9YNkSZen7sijLA3 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3 维护者速读
席位意见:ACCEPT。真实浏览器 14+3 项断言通过,席位亲看截图 04、11。 席位核对
|
This was referenced Nov 4, 2026
Contributor
Author
|
domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3 席位核对 · head moved by a merge of main only · 2026-11-05T01:25Z
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
domain:ui#2 · os-justin · session_01QSeKYnE9YNkSZen7sijLA3
Fixes #30077
Clause-②: no
Metadata-protocol: none
维护者速读
sys_user_preference的ui.list.OBJECT行新增addedFields),不写视图、不改元数据和 spec;回滚即 revert,旧版本的清洗函数会丢掉addedFields,没有残留副作用。ui/packages/plugin-list/src/ListView.tsx(addableFields的取数与updateListedFields里「取消勾选已加列」的分支);ui/packages/app-shell/src/views/objectViewListRenderer.tsx(withAddedListColumns与columns那一级的拼接);ui/packages/app-shell/src/context/ListPreferencesProvider.tsx(addedFields的清洗)。pnpm --dir ui exec vitest run packages/plugin-list/src/__tests__/ListView.fieldListRead-11984.test.tsx packages/app-shell/src/views/ObjectView.userListState-12418.test.tsx,预期两个文件全部通过。What changes
@object-ui/plugin-list). Two newListViewhost props:addedFields(the names amongschema.columnsthe reader added) andonAddedFieldsChange(the door that stores them). When the door is wired, both hide-fields lists — the wide toolbar's Hide fields popover and the Hide Fields section of the Display panel (ViewSettingsPopover, the same door: it writes through the sameupdateHiddenFieldscallback) — list, after the view's columns, every other field of the object's definition that the caller may read (canReadField, the predicate every toolbar field list asks), that the definition does not markhidden: true, and that is not already a column; business fields first, then system fields (isSystemManagedField), unticked. Ticking one callsonAddedFieldsChangewith the whole new list; unticking an added column calls it without that name instead of hiding it; adding a name a stale hidden entry carries clears that entry too. A reader-added column is labelled from the definition in the popover. Without the door the popover is byte-for-byte today's.@object-ui/app-shell).ListViewPreferencegainsaddedFieldsbesidehiddenFieldsin the reader'sui.list.OBJECTrow: sanitized to unique names, and an empty list is dropped (nothing added is the view's own). "Reset to view" removes it with the rest of the view's entry (resetViewPreference), unchanged code path.objectViewListRenderer).withAddedListColumnsappends the stored added names to thecolumnsrung in the view's own column shape (bare names beside bare names,{ field }beside column objects), skipping any name the view itself declares; the list therefore fetches ($select), expands ($expand, throughbuildExpandFieldsoverschema.columns) and draws an added column exactly as a declared one. The door is wired where a Hide Fields choice is stored (a view that declarescolumns, or a saved view); on a system view or fallback tab that declares no columns it is not wired, matching the session-only hide there.objectViewListUrlState). A storedaddedFieldsreports the existingcolumnspart, so the Personalized marker draws and names "Column layout" with no new copy.ui/packages/plugin-list/README.mddocuments the two host props (ui/AGENTS.md ✨ Set up Copilot instructions #2).Tests
All runs on this branch's worktree, under
scripts/pm/os-verify-lock.sh; head at the final run:916241ae1.ListView.fieldListRead-11984.test.tsx(top-level describe, objectstack#30077): wide and compact, restricted caller is offeredTitle, Status, Priorityand not the two unreadable fields; full-read control offers them; door absent offers the view's columns alone; tick adds through the door and leaves hide/show of a view column unchanged; untick of an added column removes it and writes no hidden list; a stale hidden entry is cleared on add; the Display panel adds through the same door; ahidden: truefield is not offered and system fields follow business fields; an added lookup is in the next$selectand$expand.ObjectView.userListState-12418.test.tsx(top-level describe): adding writes no view and lands as one save ofaddedFields; the list is handed the column appended; a fresh browser opens with it; another user does not see it; "Reset to view" drops it (the stored addition alone draws the marker); a name the view declares is not duplicated; a saved view that declares columns stores it the same way.ListPreferencesProvider.slot-12418.test.ts: sanitize, patch/clear and reset ofaddedFields.Readings
916241ae1: see Verification.pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-list/(pre-merge head):Test Files 1 failed | 188 passed (189),Tests 1 failed | 1805 passed (1806); the one failure was this PR's own new lookup pin, which asserted a grid header this harness does not render (the grid registers lazily here). The pin was narrowed to the$select/$expandand popover assertions and re-run:ListView.fieldListRead-11984.test.tsxTests 31 passed (31).ObjectView*andInterfaceListPage*test plus thegit grephits forListPreferences/listPrefs/personaliz/onHiddenFieldsChange):Test Files 101 passed (101),Tests 880 passed (880). The full app-shell suite (2172 files) is declared to CI's sharded Test UI.pnpm --filter @object-ui/plugin-list type-checkexit 0;pnpm --filter @object-ui/app-shell type-checkexit 0 (pre-merge, and again post-merge, see Verification).addedFields={listColumns.addedFields}replaced byaddedFields={42}withscripts/ablation-replace.mjs(anchor 1 to 0, blob91185df42a4eto8287f4f432e4),tsc --noEmitin app-shell:TSC_EXIT=2,error TS2322: Type 'number' is not assignable to type 'readonly string[]'; restored, blob equal to HEAD (91185df42a4e) andgit diff HEADempty. The rebuiltdist/ListView.d.tscarries both props andListViewPropsdeclares no index signature.Acceptance notes
ui/packages/app-shell/src/views/**; the store isui/packages/app-shell/src/context/ListPreferencesProvider.tsx(its sanitizer drops any undeclared part, so an added list cannot persist without it).objectViewListUrlState.ts(underviews/**) carries the marker part.ui/packages/plugin-list/README.mdis added for ui/AGENTS.md ✨ Set up Copilot instructions #2.$expandis built fromschema.columnsbybuildExpandFields, so an added lookup is expanded as a declared one; pinned. No field type is excluded from the offer.columns(its hide is session-only by ruling 5839344270 on objectui#10694), and every host that does not wireonAddedFieldsChange(InterfaceListPage, page blocks).allFields, so they also list a column the reader added (it is a column of their list); they never list a field not on the list.$selectby one field; the page size and existing caps are unchanged.Verification
Post-merge head and gates
Head
916241ae1(this branch merged withorigin/main; the incoming commits touch none of this diff's files):pnpm turbo run build --filter='@object-ui/app-shell^...' --concurrency=2: exit 0,Tasks: 67 successful, 67 total.pnpm --filter @object-ui/app-shell type-check: exit 0.Test Files 3 passed (3),Tests 84 passed (84).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 36 commands on this head; 35 re-run here on916241ae1, each exit 0;pnpm --dir ui exec vitest run scripts/exit 0 (Test Files 170 passed | 2 skipped (172)) on the pre-merge head, and the merge brings noui/scriptschange.--ranreconciliation:36 derived, 36 run, 0 NOT-MEASURED, 0 UNRUN(a derived zero, every line with its exit code).pnpm check:changeset-fixedexit 0;pnpm check:new-line-citations(underui/) exit 0,0 new citation(s);check:doc-types,check:doc-json,check:doc-fences,check:doc-example-readersexit 0 over the README change. NOT MEASURED:check:doc-snippets/check:doc-examples, reason: each needs its own scoped 33-package build first (exit 2, prerequisite), left to CI.Browser check
Real Chromium (Playwright, real clicks and real typing), head
916241ae1. Example CRM backend (objectstack dev --seed-admin --fresh -p 4377inexamples/app-crm), Console built from this branch'sui/source (vite --port 5377 --strictPort,DEV_PROXY_TARGET=http://localhost:4377), locale en-US, signed in as the seeded admin, on Opportunities / All Opportunities (crm_opportunity.all). The organization's first-run "Set the default currency" dialog was answered once. 14 of 14 assertions passed. The screenshots are kept in the seat's scratchpad, not uploaded; the seat viewed04-grid-added.pngand11-labels.png.owner_id, a lookup) and Days to Close (a formula field) are listed after the view's columns, unticked. Discount (%), Approval Status, Renewal Of and Products Total are offered too. PASSui.list.crm_opportunityreadsperView.crm_opportunity.all.addedFields = ["owner_id","days_to_close"]. PASS{}. PASSaddedFields = ["owner_id"]with nohiddenFields. After a reload it is still absent and still offered, so it was removed, not hidden. PASSRework round 2: labels (head
cfcc48813). The first run listed two of the view's own label-less columns under their machine names (account,expected_revenue) while the grid header read Account and Expected Revenue.allFieldsinListView.tsxnow falls back to the object definition's field label for every column with no label of its own. Order: translation, then the column's own label, then the definition's label, then the field name.Pin:
ListView.fieldListRead-11984.test.tsx, "a column with no label of its own is listed under the definition's label, not its machine name"; ablated red (expected [ 'title', 'status', 'Priority ] to include 'Status'), restored green. The Group and Row color pickers share this list; the one pin that spelled the old raw name (ListView.rowColorSelect-12376.test.tsx,subject→Subject) was updated with its intent unchanged.Not changed here: the list puts a translation before a column's own label, while the grid header puts the column's own label first and prettifies a bare name. They agree whenever a column has no label, which is the case fixed here.
Generated by Claude Code