Skip to content

fix(plugin-detail): on a desktop the enlarged related tab draws the child object's list grid - #28902

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

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-iixlsj

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #28865

Clause-②: no
Metadata-protocol: none

维护者速读

What changes

RelatedList's enlarged face (the record page's active related tab) now renders object-grid on every width, the branch the phone has taken since #28484. On a desktop it fell through to the generic data-table.

  • One branch, phone and desktop. viewSchema returns object-grid over the page of rows this list already read (data: { provider: 'value', items }), with the list's columns, the grid's own pager and search off (showPagination: false, showSearch: false). Under 768 px the grid draws the phone list's card rows, as before.
  • The list stays the source of truth. Its window, page and sort reach the grid on the grid's host channel: React props spread on SchemaRenderer (manualPagination, rowCount, page, pageSize, onPageChange, sort, onSortChange), the same ones plugin-list's ListView hands the grid. Paging and sort stay the server's $top / $skip / $orderby; the list's own pager stays the one pager, because it also answers a window whose total the server did not send (hasMore). objectFields rides along so no column paints withheld while the grid reads the definition (objectui#10657).
  • Row actions come from the grid. The host's localized row actions (list_item, and record_related inside a parent record) ride to the grid's row menu as rowActionDefs, the non-author host key the console's object page uses. Row Edit is the host's onRowEdit; row Delete is this list's confirm-then-delete.
  • Row-action dispatch stays the host's. The grid runs a row action def through the surrounding action runner with the row under params._rowRecord and no object of its own; on the record page that runner's object is the parent's, and nothing would tell the list to read its rows again. RelatedList provides the grid an action context (enlargedGridActions) that sends a dispatch carrying one of its own row action defs and a row to the host's onRowAction (child object, row context, and the related-changed signal that refetches the list), and every other dispatch to the surrounding runner unchanged.
  • One count. While the 全部 chip is on and nothing narrows the rows, the line under the toolbar no longer repeats the chip's count; it keeps the page line when there is one. A narrowing chip (我的 / 逾期) or filter text keeps the line's count, which is then a different number.
  • Compact panels in the right column and lists that are not enlarged are unchanged. No change to plugin-grid.

Why

#27524 item 9: the enlarged tab is "the full-width table (all columns, paging, sort, inline edit where the FK allows — the child object's list face)". Measured on main before this PR (account Acme Corp → 商机, 1440 px, examples/app-crm): rows 65 px against the opportunity list page's 41 px, the name as plain text, and the count shown twice (「全部 4」 and 「4 条」).

Tests

  • New RelatedList.enlargedListGrid-28865.test.tsx (11 tests): the desktop branch is object-grid over the read rows with the grid's pager and search off; the host channel carries the window, page and sort and none of it rides as node keys; a header sort from the grid becomes one server $orderby from page 1; a page from the grid reads the next window ($skip 25); the pinned deviation below; the count shows once on 全部 and a narrowing chip keeps its own count; a grid row-action dispatch reaches onRowAction with the def and the row, and (control) any other dispatch does not; row Edit is the host's and row Delete asks first; control: a list that is not enlarged keeps the data-table with no host props.
  • RelatedList.enlargedPhoneCards-28484.test.tsx: its desktop control now asserts the same object-grid branch.
  • RelatedList.enlargedToolbar-27524.test.tsx: registers a stand-in object-grid (this package cannot import plugin-grid, which depends on it) and asserts the status line is not drawn when the 全部 chip carries the count.
  • app-shell RecordDetailView.childWriteRefreshesParent-12244.test.tsx: the enlarged tab's row menu is now the grid's, so the test opens it by row-action-trigger. The delete still re-reads the parent.

Ablations (each through scripts/ablation-replace.mjs, restored to HEAD byte-identical):

  • desktop branch gated back to the phone (enlargedFace && isMobile && …): 7 of 11 red in the new file;
  • the routed dispatch sent to the surrounding runner instead of onRowAction: 1 red (the routing test);
  • the one-count rule switched off: 2 red (the new count test and the 27524 toolbar test).

Acceptance notes

  • Deviation (pinned): while the filter box has text the list sorts its in-memory rows itself; the grid is still handed that sort on the host channel, and under a host sort the grid offers no header sort on a relational column (its stored value is an id), as on every list page. The data-table sorted such a column by its label in that one state. Pinned in the new test file.
  • Screenshots (1440 px, zh-CN, examples/app-crm, fresh boot) are in the project folder issue-28865/; the seat links them here: before-account-opportunities-1440.png, after-account-opportunities-1440.png, and for comparison opportunity-list-page-1440.png; also after-name-opens-record-1440.png, after-sorted-amount-desc-1440.png, after-leads-row-actions-1440.png and the phone face after-account-opportunities-390.png.
  • Measured in the running app after the change: rows 41 px on the tab and on the list page; a header click sends sort=amount then amount desc and the rows follow; the name opens the record drawer stepping 1 / 4; the 全部 chip says 4 and no line repeats it; on the leads tab the row menu holds 编辑, 删除 and Convert Lead, and Convert Lead posts actions/crm_lead/crm_convert_lead and the list then re-reads crm_lead.
  • The 操作 header over a column with no visible buttons is the grid's own behaviour, the same as on the list page (List grid Actions column: a visible low-emphasis ⋯ on every row at rest, instead of a header over a column that looks empty until the pointer hovers a row #28871); it is not changed here.

Verification

At head 47c53a5a (this branch with origin/main 7fa9873f merged in; 4 later commits on main touch none of the changed files):

  • pnpm exec vitest run packages/plugin-detail/ (from ui/, --maxWorkers=2, under os-verify-lock): 361 files passed, 1 skipped; 3200 tests passed, 18 skipped (run before the main merge; the merge touched no file under plugin-detail, plugin-grid or react).
  • 30 app-shell / console / plugin-view / plugin-grid test files that name RelatedList, the enlarged face or ?related=: 30 / 30 files, 496 / 496 tests after the row-menu update above.
  • The touched test files again at the final head: the three plugin-detail files plus the 30 above, 33 / 33 files, 516 / 516 tests.
  • pnpm --filter @object-ui/plugin-detail run type-check: exit 0. eslint on RelatedList.tsx: 0 errors, 99 warnings, the same count as main.
  • Derived gates (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 34 commands, run at 47c53a5a): 34 / 34 exit 0, reconciled by --ran (34 derived, 34 run, 0 NOT-MEASURED, every line with its exit code); pnpm --dir ui run check:spec-symbols exit 0. node scripts/check-sdui-manifest.mjs: exit 0 (manifest present and intact, 106 components).
  • check-changeset-no-major.mjs --base origin/main with this body as GITHUB_EVENT_PATH: exit 0 (Metadata-protocol: none, patch); check-adr-0087-registration, check-closing-keyword-parity and check-partof-closing-keyword on this body: exit 0.

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.
  • 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: 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_01QsR2jV95ABcxitqSGp6kmv


Generated by Claude Code

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 2, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

席位核对 · ACCEPT · 2026-11-02T04:14Z

Head-sha: 47c53a5a412108623d544a8c6560572ece01db4e


Generated by Claude Code

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 Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

1 participant