Skip to content

fix: auto-generate RelatedList columns from object schema metadata#997

Merged
hotlong merged 3 commits intomainfrom
copilot/fix-related-subtable-issue
Mar 3, 2026
Merged

fix: auto-generate RelatedList columns from object schema metadata#997
hotlong merged 3 commits intomainfrom
copilot/fix-related-subtable-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 3, 2026

Detail page "Related" tab renders empty tables for all child objects — title and record count appear but zero columns/rows. The data flow never passes the child object name (api) to RelatedList, and RelatedList never consults dataSource.getObjectSchema() to derive columns, so columns falls back to [].

Changes

  • RecordDetailView.tsx — Pass api: childObject in related entries so downstream components know which object to query
  • RelatedList.tsx — When api and dataSource are available but columns is empty, fetch the child object schema and auto-generate column definitions from objectSchema.fields, filtering out _-prefixed internal fields:
const effectiveColumns = React.useMemo(() => {
  if (columns && columns.length > 0) return columns;
  if (!objectSchema?.fields) return [];
  return Object.entries(objectSchema.fields)
    .filter(([key]) => !key.startsWith('_'))
    .map(([key, def]: [string, any]) => ({
      accessorKey: key,
      header: def.label || key,
    }));
}, [columns, objectSchema]);

This aligns RelatedList with how ObjectGrid, ObjectAgGrid, and ObjectMap already use getObjectSchema() for metadata-driven column generation.

Tests

Added tests verifying schema-derived columns render correctly (including _-prefix exclusion) and that explicit columns prop bypasses schema fetching.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug] 详情页相关子表未从元数据生成列定义,导致表格内容为空</issue_title>
<issue_description>## 问题描述

在详情页面(任何业务对象),"相关"tab 下的子表仅显示标题、记录数和搜索框,表格内容(行和列)完全为空。该问题是平台级 bug,影响所有通过元数据驱动的相关列表。

image1 image2

根因分析

整条数据流链路中,没有任何一层利用 dataSource.getObjectSchema() 获取子对象的字段元数据来生成 columns:

  1. RecordDetailView 构建 related 时只传了 titletypedata没有传 columns 也没有传子对象名称(api
  2. DetailView 原样透传给 RelatedList,不做 columns 补全。
  3. RelatedList 生成 viewSchemacolumns fallback 到 [],SchemaRenderer 收到空列配置,不渲染任何内容。
RecordDetailView                    DetailView                        RelatedList
related = [{                   →    <RelatedList                  →   viewSchema = {
  title: 'Order Item',               data={related.data}               type: 'data-table',
  type: 'table',                     columns={undefined}               data: [...],
  data: [7条记录]                     api={undefined}                   columns: [] ← 空!
}]                                  />                                }

对比主流平台做法

平台 策略
Salesforce 读取子对象的 Object Metadata + Page Layout,自动生成列(label、type、顺序)
Retool 绑定查询后自动检查返回数据的 key 生成列
Appsmith 类似 Retool,表格绑定数据后自动推断列定义

ObjectUI 作为元数据驱动平台,应走 Salesforce 路线:利用已有的 dataSource.getObjectSchema(childObjectName) 获取子对象字段定义来生成 columns。

平台其他组件(ObjectGridObjectAgGridObjectMap)都已正确使用该方法,RelatedList 是唯一缺失的。

建议修复方案

RelatedList 组件内自动获取元数据(推荐)

RelatedList 中,当 api(objectName)和 dataSource 存在但 columns 为空时,调用 dataSource.getObjectSchema(api) 获取子对象字段定义,自动生成 columns:

// RelatedList.tsx — 新增 objectSchema 获取逻辑
const [objectSchema, setObjectSchema] = React.useState<any>(null);

React.useEffect(() => {
  if (api && dataSource?.getObjectSchema && (!columns || columns.length === 0)) {
    dataSource.getObjectSchema(api).then(setObjectSchema).catch(() => {});
  }
}, [api, dataSource, columns]);

// 从 objectSchema 生成 columns
const effectiveColumns = React.useMemo(() => {
  if (columns && columns.length > 0) return columns;
  if (!objectSchema?.fields) return [];
  return Object.entries(objectSchema.fields)
    .filter(([key]) => !key.startsWith('_'))
    .map(([key, def]: [string, any]) => ({
      accessorKey: key,
      header: def.label || key,
    }));
}, [columns, objectSchema]);

影响范围

平台级 bug,所有通过元数据驱动生成的相关子表均受影响。修复后需全面测试各类业务对象详情页。</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui Ready Ready Preview, Comment Mar 3, 2026 8:09am
objectui-demo Ready Ready Preview, Comment Mar 3, 2026 8:09am
objectui-storybook Ready Ready Preview, Comment Mar 3, 2026 8:09am

Request Review

…umns missing

- RecordDetailView: pass api (childObject name) in related entries
- RelatedList: fetch object schema via dataSource.getObjectSchema() when
  api/dataSource available but no explicit columns, then generate columns
  from field metadata (filtering out _-prefixed internal fields)
- Add tests for auto-column generation behavior

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…, simplify condition

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix empty content in related subtable on detail page fix: auto-generate RelatedList columns from object schema metadata Mar 3, 2026
@hotlong hotlong marked this pull request as ready for review March 3, 2026 08:18
Copilot AI review requested due to automatic review settings March 3, 2026 08:18
@hotlong hotlong merged commit f65b757 into main Mar 3, 2026
5 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a platform-level bug where the "Related" tab on detail pages rendered empty tables because no column definitions were ever passed to RelatedList. The fix adds schema-driven column auto-generation inside RelatedList using dataSource.getObjectSchema(), consistent with how ObjectGrid, ObjectAgGrid, and ObjectMap already work. It also threads api: childObject from RecordDetailView so RelatedList knows which object to query.

Changes:

  • RelatedList.tsx — Adds a useEffect to fetch the child object's schema and a useMemo (effectiveColumns) to derive column definitions from objectSchema.fields when no explicit columns prop is supplied
  • RecordDetailView.tsx — Passes api: childObject in each related entry so RelatedList can identify the schema to fetch
  • RelatedList.test.tsx — Adds tests verifying schema-driven column generation and that explicit columns bypass schema fetching

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/plugin-detail/src/RelatedList.tsx Core fix: schema fetch effect + effectiveColumns memoization, used in viewSchema
apps/console/src/components/RecordDetailView.tsx Threads api: childObject into each related entry
packages/plugin-detail/src/__tests__/RelatedList.test.tsx New tests for schema-derived columns and bypass behavior

Two issues found:

1. sortable header rendering doesn't use effectiveColumns (bug)

The sortable column header buttons block (around line 261 in the unchanged portion of RelatedList.tsx) checks columns && columns.length > 0 and iterates columns — the raw prop — instead of effectiveColumns. When sortable={true} is used with no explicit columns (the exact scenario this PR is fixing), the sort buttons will never render even though effectiveColumns contains the schema-derived columns. Only viewSchema was updated to use effectiveColumns; the sort UI was not.

2. Stale objectSchema state when api changes

In the schema fetch useEffect (lines 88–94), there is no setObjectSchema(null) call before the async fetch. If the api prop changes to a new value, the stale schema from the previous object remains visible in effectiveColumns until the new request resolves, potentially briefly showing wrong columns.

Comment on lines 180 to +201
@@ -176,7 +198,7 @@ export const RelatedList: React.FC<RelatedListProps> = ({
return {
type: 'data-table',
data: paginatedData,
columns: columns || [],
columns: effectiveColumns,
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new effectiveColumns variable (derived from schema when no explicit columns prop is set) is correctly used in viewSchema (line 201), but the sortable column headers rendering block elsewhere in the component still checks columns && columns.length > 0 and iterates over columns (the raw prop), not effectiveColumns. As a result, when sortable={true} is used without an explicit columns prop, the sort buttons will never render even when effectiveColumns has schema-derived values. That block should use effectiveColumns instead of columns.

Copilot uses AI. Check for mistakes.
Comment on lines +88 to +94
React.useEffect(() => {
if (api && dataSource?.getObjectSchema && !columns?.length) {
dataSource.getObjectSchema(api).then(setObjectSchema).catch((err: unknown) => {
console.warn(`[RelatedList] Failed to fetch schema for ${api}:`, err);
});
}
}, [api, dataSource, columns]);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the api prop changes (e.g., when the component is reused for a different child object), the objectSchema state is not reset to null before the new getObjectSchema() call resolves. This means there's a brief window where the stale schema from the previous api is used to generate effectiveColumns. Adding a setObjectSchema(null) call at the start of the effect (before the async fetch) would prevent briefly showing wrong columns from the old schema.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 详情页相关子表未从元数据生成列定义,导致表格内容为空

3 participants