Skip to content

fix: record detail "not found" in external metadata environments#1032

Merged
hotlong merged 4 commits intomainfrom
copilot/fix-record-detail-not-found
Mar 4, 2026
Merged

fix: record detail "not found" in external metadata environments#1032
hotlong merged 4 commits intomainfrom
copilot/fix-record-detail-not-found

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 4, 2026

When deploying to external metadata environments, navigating from list → record detail shows "Record not found" because findOne errors bypass the alt-ID fallback, and the $expand code path hard-fails on servers that don't support filter+populate.

DetailView fallback catches errors, not just nulls

The alt-ID fallback (strip/add objectName prefix) only ran when findOne returned null. If it threw (server 500, unsupported API, network error), the fallback was skipped entirely.

// Before: .then() never runs if promise rejects
return findOnePromise.then((result) => { ... fallback ... });

// After: convert error → null so fallback always runs
return findOnePromise
  .catch(() => null)
  .then((result) => { ... fallback ... });

ObjectStackAdapter degrades gracefully when $expand fails

findOne with $expand uses rawFindWithPopulate with $filter: { _id: id }. Some servers don't support this filter+populate API. Previously threw on non-404 errors; now falls through to direct data.get() without expand.

Record IDs URL-encoded in navigation URLs

encodeURIComponent added to all record ID URL construction points across:

  • apps/console/src/components/ObjectView.tsx
  • apps/console/src/hooks/useObjectActions.ts
  • packages/plugin-view/src/ObjectView.tsx
  • packages/react/src/hooks/useNavigationOverlay.ts
Original prompt

本项目作为元数据驱动的平台部署到其他元数据环境后,从列表进入记录详情页提示记录没找到。会不会是对ID做了什么特殊处理?https://demo.hotcrm.com/console/apps/crm/contact/record/contact-1772620343833-4


🔒 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 4, 2026

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

Project Deployment Actions Updated (UTC)
objectui Canceled Canceled Mar 4, 2026 11:08am
objectui-demo Ready Ready Preview, Comment Mar 4, 2026 11:08am
objectui-storybook Ready Ready Preview, Comment Mar 4, 2026 11:08am

Request Review

…de $expand in ObjectStackAdapter

When deployed to external metadata environments, findOne may throw (not
just return null) for the initial ID format. The DetailView fallback now
catches errors and retries with an alternate ID (prefix stripped or added).

ObjectStackAdapter.findOne also falls through to direct GET when the
$expand/populate raw request fails, instead of throwing.

Navigation URLs now use encodeURIComponent for record IDs to handle
IDs containing special characters.

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
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 record not found issue in details page fix: record detail "not found" in external metadata environments Mar 4, 2026
@hotlong hotlong marked this pull request as ready for review March 4, 2026 11:11
Copilot AI review requested due to automatic review settings March 4, 2026 11:11
@hotlong hotlong merged commit 97e5535 into main Mar 4, 2026
8 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 a regression where navigating list → record detail can incorrectly show “Record not found” in external metadata environments, by making record fetching more resilient and ensuring record IDs are safely represented in URLs.

Changes:

  • Make DetailView’s alternate-ID fallback run even when the initial findOne call rejects (not just when it returns null).
  • Update ObjectStackAdapter.findOne to gracefully fall back to data.get() when $expand raw requests fail with non-404 errors.
  • URL-encode record IDs (encodeURIComponent) at all navigation URL construction points to prevent routing issues with special characters.

Reviewed changes

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

Show a summary per file
File Description
packages/react/src/hooks/useNavigationOverlay.ts URL-encode record IDs when building new-window navigation URLs.
packages/plugin-view/src/ObjectView.tsx URL-encode record IDs for plugin-view new-window navigation.
packages/plugin-detail/src/DetailView.tsx Ensure alt-ID fallback runs on initial findOne errors by converting reject → null.
packages/plugin-detail/src/tests/DetailView.test.tsx Add coverage for alt-ID fallback behavior when the first findOne throws.
packages/data-objectstack/src/index.ts Degrade gracefully from $expand raw request failures to direct data.get() for findOne.
packages/data-objectstack/src/expand.test.ts Add test to assert $expand non-404 failure falls through to data.get().
apps/console/src/hooks/useObjectActions.ts URL-encode record IDs in console navigation-to-record helper.
apps/console/src/components/ObjectView.tsx URL-encode record IDs for console navigation/new-tab record detail URLs.
ROADMAP.md Document the bugfix root cause, solution, and related test coverage.

Comment on lines +158 to 166
if (!isMounted) return;
if (result) {
setData(result);
setLoading(false);
return;
}
// Fallback: try alternate ID format for backward compatibility
return tryAltId();
});
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

Indentation inside the .then((result) => { ... }) block is off (the block body is not indented relative to the opening brace). This is likely to cause formatter churn; please run the formatter / align indentation to the surrounding style.

Suggested change
if (!isMounted) return;
if (result) {
setData(result);
setLoading(false);
return;
}
// Fallback: try alternate ID format for backward compatibility
return tryAltId();
});
if (!isMounted) return;
if (result) {
setData(result);
setLoading(false);
return;
}
// Fallback: try alternate ID format for backward compatibility
return tryAltId();
});

Copilot uses AI. Check for mistakes.
};

return findOnePromise
.catch(() => null) // Convert any error to null to trigger alternate ID fallback
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

findOnePromise.catch(() => null) swallows all errors (including auth/network) and prevents them from reaching the outer .catch that logs Failed to fetch detail data. Consider capturing/logging the original error (or only converting specific errors like 404/400) so unexpected failures remain observable while still allowing the alt-ID fallback to run.

Suggested change
.catch(() => null) // Convert any error to null to trigger alternate ID fallback
.catch((err) => {
const status = (err as any)?.status ?? (err as any)?.statusCode;
// Only treat explicit "not found" errors as null to trigger alternate ID fallback.
if (status === 404) {
return null;
}
// Rethrow all other errors so they are logged by the outer catch.
throw err;
})

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.

3 participants