Skip to content

finding(components/plugin-dashboard): data-table 的访问键归一化读一个自身类型未声明的 col.name 别名,而唯一在交付前解析列身份的生产者只有 RelatedList #5120

Description

@yinlianghui

Blocked-by: #5149

发现于 #5022 的实施(RelatedList 对象列写回 accessorKey)。Filed unassigned, not claiming。观察类:今天没有用户经已声明的授权面撞到,记录的是「适配器长出元数据味别名 + 生产端各自为政」这条分叉。基线 objectui main @ d729ce0

事实一:适配器容忍一个自己没声明的键

TableColumn(packages/types/src/data-display.ts:218-226)把访问键声明为必填accessorKey: string,没有 name、没有 field

而 data-table 的访问键归一化读两个键(packages/components/src/renderers/complex/data-table.tsx:777,自动列宽处 :786 同形):

accessorKey: col.accessorKey || col.name

col.name 不在 TableColumn 里。也就是说:声明面只认 accessorKey,运行面额外接受 name —— 与 #5068 记录的形状同族(那边是 ObjectGrid 容忍未声明的 accessorKey/header,方向相反),都属 AGENTS.md #0.1 说的「消费端容忍别名」。

这条别名正是 #5022 那个 bug 的形状成因:legacy name 拼写端到端能用,而 ListColumnSchema 唯一声明的 field 拼写渲染成空格子 —— 不是因为 field 更差,而是因为适配器恰好长了 name 这一条支路、没长 field 那条。#5022 的处置是让生产者(RelatedList)在交付前把身份写进 accessorKey,刻意不去动适配器(column-identity.tsTABLE_ADAPTER_COLUMN_KEY 边界);别名本身仍在。

事实二:另一个生产者把对象列原样透传,且从不读 field

packages/plugin-dashboard/src/ObjectDataTable.tsx:57-65:

export function normalizeColumns(columns) {
return columns.map((col) => {
if (typeof col === 'string') return { header: humanizeFieldKey(col), accessorKey: col };
return col; // 对象条目原样返回
});
}

同文件 :110 的身份读法是 (c.accessorKey || c.name) —— name-first 的 legacy 顺序,完全不读 field,也没接到 #3104columnIdentity。于是 object-data-table 走的是 #5022 修复前 RelatedList 的老路:对象列若以 field 拼写,访问键为 undefined,格子全空,而 $expand 白名单那一步也解析不出字段。

object-data-tablepackages/types 里没有对应的 schema 声明类型(插件注册的 widget),所以这里的 field未声明输入,和 #5068 一样是「声明面与运行面分叉」,不是今天可复现的用户故障 —— 因此定为观察类。

为什么现在记下来

  1. RelatedList object columns: spec-canonical field spelling passes every RelatedList read, then renders header + blank cells at the data-table accessor #5022 只治了一个生产者。同一条 data-table 适配器现在有三个生产者(RelatedList / ObjectGrid / ObjectDataTable),只有 RelatedList 在交付前做身份解析,另两个各有各的拼法。
  2. 既有门禁看不见这两处列身份双读家族:field ?? name 两种优先序并存于 15+ 处——ingestion 归一 + 单键消费 + 禁新增闸门(objectstack#4115) #3104 的 ratchet(packages/core/src/utils/__tests__/column-identity.ratchet.test.ts)要求同一行出现两个以上身份键|| / ?? 链才计数,而 accessorKey 被显式列为 COMPANION_KEYS;col.accessorKey || col.name 这一行只有 name 一个身份键,distinct.size 为 1,不进扫描面。ratchet 的 CONVERGED 清单里也没有 plugin-dashboard
  3. finding(plugin-grid): ObjectGrid 在 ObjectGridSchema.columns 上容忍未声明的 accessorKey / header 拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068 是同族但不同处:那卡问的是 ObjectGrid 该不该声明 accessorKey;本卡记的是适配器该不该继续读 name、以及第三个生产者该不该接上同一个解析。裁定方向可能一致(向 [fields] grid columns have two incompatible key spellings: declared type says name, GridField reads field — spec-compliant grid metadata renders empty cells #3951 看齐:生产端统一为一种拼法,消费端不留容忍别名),但落点是不同文件,故另立而非并入。

复核方式

sed -n '218,227p' packages/types/src/data-display.ts # TableColumn:accessorKey 必填
sed -n '772,790p' packages/components/src/renderers/complex/data-table.tsx # 未声明的 name 别名
sed -n '49,66p;104,115p' packages/plugin-dashboard/src/ObjectDataTable.tsx # 原样透传 + name-first 读
grep -n "COMPANION_KEYS\|CONVERGED" packages/core/src/utils/__tests__/column-identity.ratchet.test.ts

分级

finding,不入 pm:queue。要不要动、往哪边动(退役 name 别名 / 让另两个生产者接上 columnIdentity / 两者都做),取决于维护者对 #5068 同一个二选一的裁定;本卡只把分叉与门禁盲区记在案。


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions