Skip to content

fix: strip objectName prefix from recordId in detail page, show "Record not found" on null#928

Merged
hotlong merged 3 commits intomainfrom
copilot/fix-recordid-prefix-issue
Mar 1, 2026
Merged

fix: strip objectName prefix from recordId in detail page, show "Record not found" on null#928
hotlong merged 3 commits intomainfrom
copilot/fix-recordid-prefix-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 1, 2026

Detail pages render blank when navigating via URL (e.g. /contact/record/contact-1772355903654-1) because the URL recordId includes an objectName- prefix that the backend doesn't store. findOne("contact", "contact-1772355903654-1") returns null silently.

Changes

  • RecordDetailView: Compute pureRecordId once at component top, use it for all downstream queries — detailSchema.resourceId, presence filter, comment thread IDs, and onEdit callback
const pureRecordId = recordId && objectName && recordId.startsWith(`${objectName}-`)
  ? recordId.slice(objectName.length + 1)
  : recordId;
  • DetailView: Add "Record not found" empty state when data is null post-load, with optional back navigation — prevents silent blank page

  • Tests: Fix broken waitFor selectors in RecordDetailEdit.test.tsx, add assertions that findOne receives the stripped ID, add two tests for the record-not-found state

Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug] 详情页刷新/进入无法显示数据,recordId 带前缀导致 findOne 查不到记录</issue_title>
<issue_description>### 现象
https://demo.objectui.org/apps/crm_app/contact/record/contact-1772355903654-1 进入详情页或者刷新,页面不会显示任何数据,也无错误提示。

预期

详情页应能正常显示记录内容。

原因分析

  • URL 里的 recordIdcontact-1772355903654-1,包含对象名前缀
  • RecordDetailView 直接将此 id 作为 resourceId 传递给 DetailView
  • DetailView 调用 dataSource.findOne("contact", "contact-1772355903654-1"),后端实际存储的是去前缀的 id(如 "1772355903654-1"),查不到返回 null,页面就空白了

关键代码

RecordDetailView.tsx:

const detailSchema: DetailViewSchema = {
  type: 'detail-view',
  objectName: objectDef.name,
  resourceId: recordId, // 此处未剥离前缀
  ...
}

DetailView.tsx 会直接用 resourceId 查找:

dataSource.findOne(schema.objectName, schema.resourceId)

建议修复

  • RecordDetailView 组件提��剥离前缀,只传递纯 id 给 detailSchema.resourceId 和 presence、评论 fetch 等所有相关数据查询点
  • DetailView 找不到记录(result==null)应显示 "Record not found" 或错误提示,避免空白页面

影响范围

  • 所有详情页的初始加载和刷新
  • 任何依赖 recordId 查询的功能

补充

/assign @hotlong </issue_description>

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


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 1, 2026

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

Project Deployment Actions Updated (UTC)
objectui Ready Ready Preview, Comment Mar 1, 2026 9:35am
objectui-demo Ready Ready Preview, Comment Mar 1, 2026 9:35am
objectui-storybook Ready Ready Preview, Comment Mar 1, 2026 9:35am

Request Review

…ow "Record not found" in DetailView

- RecordDetailView: compute pureRecordId once and use for resourceId, presence, and comment queries
- DetailView: show "Record not found" message with Go back button when data is null after loading
- Update tests to verify findOne called with stripped ID and test Record not found state

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix issue with recordId prefix causing blank detail page fix: strip objectName prefix from recordId in detail page, show "Record not found" on null Mar 1, 2026
@hotlong
Copy link
Copy Markdown
Contributor

hotlong commented Mar 1, 2026

@copilot 仔细评估是否已经完成了任务中要求的所有开发?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 1, 2026

@copilot 仔细评估是否已经完成了任务中要求的所有开发?

All issue requirements have been completed. Here's the full audit:

1. RecordDetailView prefix stripping (✅ all 6 query points):

  • detailSchema.resourceIdpureRecordId (line 258)
  • Presence filter → pureRecordId (line 52)
  • Comment fetch threadId → pureRecordId (line 49)
  • handleAddComment threadId → pureRecordId (line 95)
  • handleAddReply threadId → pureRecordId (line 130)
  • onEdit callback → pureRecordId (line 286)

2. DetailView "Record not found" state (✅):

  • Shows message + "Go back" button when data is null after loading (DetailView.tsx lines 235-250)

3. Tests (✅ 28 passing):

  • RecordDetailEdit.test.tsx: Verifies findOne called with stripped ID + onEdit receives stripped ID + passthrough for non-prefixed IDs
  • DetailView.test.tsx: 2 new tests for "Record not found" state and "Go back" button

The only remaining raw recordId usage (line 183) is intentionally for the loading reset effect — it detects URL navigation changes, not data queries.

@hotlong hotlong marked this pull request as ready for review March 1, 2026 09:49
Copilot AI review requested due to automatic review settings March 1, 2026 09:49
@hotlong hotlong merged commit 942aab8 into main Mar 1, 2026
6 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

Fixes console record detail pages when navigating via URL by normalizing recordId (stripping the objectName- prefix) so backend lookups succeed, and adds a clear empty state when a record loads as null.

Changes:

  • Strip objectName- prefix from URL recordId once in RecordDetailView and reuse pureRecordId across DetailView, presence, comments, and edit callbacks.
  • Add a “Record not found” empty state to DetailView when loaded data is null.
  • Update/add tests covering recordId stripping and the new not-found state.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
packages/plugin-detail/src/DetailView.tsx Adds a “Record not found” empty state after loading when data is missing.
packages/plugin-detail/src/tests/DetailView.test.tsx Adds tests validating the not-found empty state and optional back behavior.
apps/console/src/components/RecordDetailView.tsx Introduces pureRecordId and threads it through detail schema, presence, comments, and onEdit.
apps/console/src/tests/RecordDetailEdit.test.tsx Fixes selectors and asserts findOne is called with stripped/non-stripped IDs.
Comments suppressed due to low confidence (3)

packages/plugin-detail/src/DetailView.tsx:240

  • The "Record not found" branch is triggered by a broad falsy check (!data). This will also render the not-found state when data is still undefined (e.g., misconfigured schema with no resourceId/dataSource), not just when findOne explicitly returns null. Consider checking data === null (and optionally schema.resourceId present) so only a true not-found result shows this state.
  if (!data && !schema.data) {
    return (
      <div className={cn('flex flex-col items-center justify-center py-16 text-center', className)}>
        <p className="text-lg font-semibold">Record not found</p>
        <p className="text-sm text-muted-foreground mt-1">
          The record you are looking for does not exist or may have been deleted.

apps/console/src/components/RecordDetailView.tsx:58

  • dataSource.find is being called with $filter as an interpolated string. In @object-ui/types, QueryParams.$filter is defined as an object/AST, and the ObjectStack adapter converts object filters to an AST; passing a string can be mis-parsed (e.g., treated as a list of characters). Use an object filter like { recordId: pureRecordId } / { threadId } instead of a string expression.
    // Fetch record viewers
    dataSource.find('sys_presence', { $filter: `recordId eq '${pureRecordId}'` })
      .then((res: any) => { if (res.data?.length) setRecordViewers(res.data); })
      .catch(() => {});

    // Fetch persisted comments and map to FeedItem[]
    dataSource.find('sys_comment', { $filter: `threadId eq '${threadId}'`, $orderby: 'createdAt asc' })
      .then((res: any) => {

apps/console/src/components/RecordDetailView.tsx:80

  • The useEffect dependency list includes currentUser, but currentUser is a new object literal each render, which will cause this effect to refetch presence/comments unnecessarily. Prefer depending on stable primitives (e.g., currentUser.id) or memoize currentUser with useMemo.
      })
      .catch(() => {});
  }, [dataSource, objectName, pureRecordId, currentUser]);

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] 详情页刷新/进入无法显示数据,recordId 带前缀导致 findOne 查不到记录

3 participants