fix: record detail "not found" in external metadata environments#1032
fix: record detail "not found" in external metadata environments#1032
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…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>
There was a problem hiding this comment.
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 initialfindOnecall rejects (not just when it returnsnull). - Update
ObjectStackAdapter.findOneto gracefully fall back todata.get()when$expandraw 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. |
| if (!isMounted) return; | ||
| if (result) { | ||
| setData(result); | ||
| setLoading(false); | ||
| return; | ||
| } | ||
| // Fallback: try alternate ID format for backward compatibility | ||
| return tryAltId(); | ||
| }); |
There was a problem hiding this comment.
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.
| 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(); | |
| }); |
| }; | ||
|
|
||
| return findOnePromise | ||
| .catch(() => null) // Convert any error to null to trigger alternate ID fallback |
There was a problem hiding this comment.
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.
| .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; | |
| }) |
When deploying to external metadata environments, navigating from list → record detail shows "Record not found" because
findOneerrors bypass the alt-ID fallback, and the$expandcode 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
findOnereturnednull. If it threw (server 500, unsupported API, network error), the fallback was skipped entirely.ObjectStackAdapter degrades gracefully when $expand fails
findOnewith$expandusesrawFindWithPopulatewith$filter: { _id: id }. Some servers don't support this filter+populate API. Previously threw on non-404 errors; now falls through to directdata.get()without expand.Record IDs URL-encoded in navigation URLs
encodeURIComponentadded to all record ID URL construction points across:apps/console/src/components/ObjectView.tsxapps/console/src/hooks/useObjectActions.tspackages/plugin-view/src/ObjectView.tsxpackages/react/src/hooks/useNavigationOverlay.tsOriginal prompt
🔒 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.