Skip to content

record:related_list has no groupBy, and its columns cannot cross a lookup — the two things a related list needs to stop being a flat strip of rows #7301

Description

@os-warren

Two authoring limits met on the same component while building a record page over sys_user (objectstack-ai/duly#13). Both are expressiveness gaps rather than defects — nothing renders wrong, the page just cannot say the thing.

1. No grouping

RecordRelatedListProps declares columns, sort, filter, limit. There is no groupBy, and RelatedList draws its own table rather than a list view, so the grid's grouping block (which does support nested levels with per-level collapse, and which this same app uses on a duly_duty list view) is unreachable from a related list.

The requirement was "their governed duties, grouped by frequency, so a monthly rhythm reads differently from an annual one". The closest authorable thing is putting frequency first in columns and first in sort, which makes each rhythm a contiguous block. It reads acceptably and it is not grouping — no group headers, no counts per group, no collapse, and the ordering is alphabetical (annual, daily, fortnightly, monthly, …) rather than by cadence.

Since grouping already exists and is already implemented for grids, the ask is mostly plumbing: let a related list accept the same block.

2. Columns cannot cross a lookup

RelatedList resolves lookup labels (it batch-fetches display names for FK cells) but has no dotted-path column support — columns: ['assignment.assigner'] names nothing.

Concretely: the page needed "assigned work, showing who assigned each". The task carries assignment (an FK); the assigner is duly_assignment.assigner, one hop on. So the column can show which assignment the task came from but not who raised it, and the reader has to click through.

The other route to the same value — a related list on duly_assignment itself, bound on its multi-value assignees field — is closed for an unrelated reason (filed separately as #7299), so on this page the requirement could not be met at all.

Given the label-resolution machinery is already there, a columns: ['assignment.assigner'] that expands the lookup one level would cover most of what related lists need; deeper paths can stay refused.


Neither is urgent on its own. Filed because both were hit inside one component on one page, and together they are the difference between a related list and a report.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SqkTcrxUFci7nqXdbBSe2p

Activity

  1. added
    enhancementNew feature or request
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 5, 2026
  2. os-zhuang commented on Sep 5, 2026

    @os-zhuang
    Contributor

    分诊 — domain:ui / priority:p3 / pm:blocked / enhancement

    锚定 (anchoring):渲染落点是 packages/plugin-detail/src/RelatedList.tsx ⇒ domain:ui。与 #7300 同理,两个新键都要先在上游 @objectstack/spec 的 RecordRelatedListProps 上有位置(packages/types/src/record-components.ts:94 明写 "Aligned with @objectstack/spec RecordRelatedListProps")。

    在 origin/main a472b07 上复核的锚点

    RecordRelatedListProps 的完整已声明键,逐个读出来(不是抽样):

    objectName · relationshipField · columns · sort · limit · filter · title · showViewAll · actions · add · aria
    

    groupBy 不在其中 —— 在 packages/types/src/record-components.ts 全文 grep groupBy:0 命中。正控制:同一次读里 columns / sort / filter / limit 全部命中。所以卡片第 1 条的前提("declares columns, sort, filter, limit,没有 groupBy")是实测的完整枚举,不是分页窗口里的观察。

    卡片第 2 条(列不能跨 lookup)与 #7299 的复核相互印证:RelatedList.tsx 自己画表而不是走 list view,:516 / :586 两处 filter 合成都只认平铺字段名,全文无点号路径解析。

    定级理由

    priority:p3 —— 采纳卡片自己的定性并复核为真:"Both are expressiveness gaps rather than defects — nothing renders wrong."

    ⛔ 定型:两条都是 Feature,都踩 manual floor

    新增 groupBy、新增点号列语法,都加宽公共可授权面;⊕ 键落在 spec 的组件 props ⇒ 协议变更。⛔ 分诊席不裁决、不派单。

    Restart-when(可执行探针):与 #7300 同法,⛔ 判据是装得上而非上游合并 ——

    pnpm add -D @objectstack/spec@latest >/dev/null 2>&1 \
      && node -e "const s=require('@objectstack/spec/ui');const k=Object.keys(s.RecordRelatedListPropsSchema?.shape??{});console.log(k.join(','));process.exit(k.includes('groupBy')?0:1)"

    ⚠️ 这张卡该拆,但本席不代拆

    两半不是同一份工作,卡片的合并理由是"在同一个组件、同一个页面上撞到的",是位置上的而非修法上的:

    工作性质 已有可复用机器
    ① groupBy 主要是接线 —— grid 的 grouping 块已实现(含嵌套层级与逐层折叠),让 related list 收同一个块 有,卡片指名
    ② 点号列跨 lookup 新的解析逻辑 —— 要在取数与渲染两侧都展开一跳 只有 label 批量解析可借,路径展开是新的

    ②的风险面也大得多(一跳的展开很容易变成 N+1 取数)。建议 domain:ui 席在动手时拆成两张,①先做;⛔ 拆不拆由执行席定,本席不代拆 —— 因为两者的上游键很可能在同一次 spec 裁决里一起谈,过早拆卡会把那次裁决割成两半。

    给执行席的两条注意

    1. ①若接 grid 的 grouping 块,⛔ 不要新造一套 group 语法 —— 卡片说的"mostly plumbing"成立的前提正是复用同一个块;另造一套会让同一个概念在本仓有两种拼写,是 finding(types): KanbanCard / KanbanColumn are declared four times in this tree and the published copies disagree (cards vs items, badges vs labels) #6155 那类缺陷的制造方式。
    2. ②卡片自己划了边界并且是对的:"expands the lookup one level would cover most of what related lists need; deeper paths can stay refused"。⛔ 不要顺手做任意深度 —— 那是另一个数量级的取数问题,且没有实测需求支撑。

    Generated by Claude Code

  3. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    分诊 — 维护者同意分诊建议:暂不做 · 按 not planned 关闭

    分诊席 #6015,2026-09-24T18:06Z。

    维护者裁决(原文)

    分诊席今天把本卡作为待决事项④提给维护者:

    • 问题:record:related_list 要不要支持 groupBy,列能不能跨 lookup(例如 assignment.assigner)?
    • 本席的建议:暂不做,按 not planned 关闭,重开条件是「有第二个项目提出同样的需求」。理由是本卡自己也写了「nothing renders wrong, the page just cannot say the thing」。

    维护者答复原文:

    「需要我决定的 6 件事: 6947 7300 不做;其他同意」

    ④ 在「其他」里 ⇒ 按建议关闭。

    关闭后的现状(照实记录)

    什么情况下重开

    出现第二个项目(duly 之外)提出同样的需求时重开。重开时附上那个项目的卡号。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions