Skip to content

fix: resolve search ranking showing N/A on admin page#256

Open
snomiao wants to merge 7 commits into
mainfrom
fix/admin-search-ranking-na
Open

fix: resolve search ranking showing N/A on admin page#256
snomiao wants to merge 7 commits into
mainfrom
fix/admin-search-ranking-na

Conversation

@snomiao

@snomiao snomiao commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • The /nodes/search API endpoint doesn't return search_ranking in its response, causing all rankings to display as "N/A" on the admin search ranking page
  • Added a NodeSearchRankingCell component that fetches each node's details via GET /nodes/{nodeId} (which returns search_ranking for authenticated admin users) to display actual ranking values
  • Also fixed formatting to match project prettier config (single quotes, no semicolons)

Test plan

  • Log in as admin and navigate to /admin/search-ranking
  • Verify search ranking values now show actual numbers instead of "N/A" for nodes that have rankings set
  • Verify editing a ranking still works correctly via the edit modal
  • Verify pagination and search still work

🤖 Generated with Claude Code

The /nodes/search endpoint doesn't include search_ranking in its response,
causing all rankings to display as "N/A". Added a NodeSearchRankingCell
component that fetches each node's details via GET /nodes/{nodeId} (which
returns search_ranking for authenticated admin users) to display the actual
ranking values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 31, 2026 10:10
@vercel

vercel Bot commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
registry-web Ready Ready Preview, Comment Apr 10, 2026 9:01am

Request Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes the admin “Search Ranking Management” page showing N/A by rendering rankings via per-node detail fetches, working around /nodes/search not returning search_ranking.

Changes:

  • Added NodeSearchRankingCell that calls useGetNode(nodeId) to display node.search_ranking per row.
  • Updated the table to use the new cell instead of node.search_ranking from the search response.
  • Reformatted pages/admin/search-ranking.tsx to match Prettier config (single quotes, no semicolons).
Comments suppressed due to low confidence (2)

pages/admin/search-ranking.tsx:162

  • Node.id is optional in the generated API types, but this row uses it for both the React key and the detail Link URL. If a node ever comes back without an id, this will produce an invalid /nodes/undefined link and a non-unique/unstable key. Consider guarding the row rendering (or link) when node.id is missing and using a guaranteed-stable key fallback.
              <div>
                <Button size="xs" color="blue" onClick={() => handleEditRanking(node)}>
                  <MdEdit className="mr-1" /> {t("Edit")}
                </Button>
              </div>
            </li>
          ))}

          {/* Empty state */}
          {(!data?.nodes || data.nodes.length === 0) && (
            <li className="py-4 text-center text-gray-400">{t("No nodes found")}</li>

pages/admin/search-ranking.tsx:171

  • NodeSearchRankingCell is invoked with nodeId={node.id || ''}. When node.id is absent this silently disables the query (because useGetNode is enabled: !!nodeId) and will always display N/A, which can mask data issues. Prefer handling the missing-id case explicitly (e.g., render N/A without instantiating the query, and avoid using an empty-string id that still creates a /nodes/ query key).
            currentPage={page}
            totalPages={data?.totalPages || 1}
            onPageChange={handlePageChange}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pages/admin/search-ranking.tsx Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 4, 2026 10:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pages/admin/search-ranking.tsx Outdated
Comment on lines +17 to +19
const { data: node, isLoading } = useGetNode(nodeId, {
staleTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

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

useGetNode's second argument is params (querystring), not React Query options. Passing { staleTime, refetchOnWindowFocus } here will be sent as request params and the caching options won't apply. Move these under the 3rd argument as options: { query: { staleTime, refetchOnWindowFocus } } (and keep params as undefined unless needed).

Suggested change
const { data: node, isLoading } = useGetNode(nodeId, {
staleTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,
const { data: node, isLoading } = useGetNode(nodeId, undefined, {
query: {
staleTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,
},

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7e31cd5. Moved staleTime and refetchOnWindowFocus to the 3rd argument under options.query, and passed undefined for params. Also added enabled: !!nodeId to prevent queries with empty strings.

Comment thread pages/admin/search-ranking.tsx Outdated
Comment on lines +17 to +21
const { data: node, isLoading } = useGetNode(nodeId, {
staleTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,
});
if (isLoading) return <Spinner size="xs" />;

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

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

This cell treats any useGetNode failure the same as “no ranking” (it will render N/A whenever the request errors, since node is undefined and isLoading is false). Consider handling isError/error separately (e.g., render an explicit error state or retry affordance) so network/auth issues aren’t silently masked as missing data.

Suggested change
const { data: node, isLoading } = useGetNode(nodeId, {
staleTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,
});
if (isLoading) return <Spinner size="xs" />;
const { data: node, isLoading, isError } = useGetNode(nodeId, {
staleTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,
});
if (isLoading) return <Spinner size="xs" />;
if (isError) return <>Error</>;

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7e31cd5. Added isError handling that shows an explicit "Error" state instead of silently displaying N/A.

Comment on lines 151 to 154
<div className="text-gray-300">{formatDownloadCount(node.downloads || 0)}</div>
<div className="text-gray-300">
{node.search_ranking !== undefined ? node.search_ranking : t("N/A")}
<NodeSearchRankingCell nodeId={node.id || ""} />
</div>

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

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

Rendering NodeSearchRankingCell for each row introduces an N+1 pattern (up to 24 extra GET /nodes/{id} requests per page load/search/pagination). This can significantly slow the admin page and increase API load; consider adding search_ranking to /nodes/search for admin responses, or introducing a batch endpoint / query that fetches rankings for the current page in one request.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Acknowledged the N+1 concern. The ideal fix is to extend /nodes/search to include search_ranking for admin responses on the backend. This approach is a workaround since the frontend can't modify the API response. Added staleTime: 5min and refetchOnWindowFocus: false (now correctly placed in query options per 7e31cd5) to mitigate repeated refetches.

Comment thread pages/admin/search-ranking.tsx Outdated
<div className="text-gray-300">{formatDownloadCount(node.downloads || 0)}</div>
<div className="text-gray-300">
{node.search_ranking !== undefined ? node.search_ranking : t("N/A")}
<NodeSearchRankingCell nodeId={node.id || ""} />

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

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

node.id is optional in the generated Node type; passing node.id || "" means the query will be disabled when id is missing and the cell will silently show N/A. Prefer guarding before rendering (e.g., only render the cell when node.id is truthy) so missing IDs are handled explicitly.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7e31cd5. Now guarding node.id before rendering NodeSearchRankingCell — renders t("N/A") directly when id is missing, avoiding the empty-string query key issue.

snomiao and others added 3 commits April 10, 2026 17:56
Previously only triggered on PRs targeting dev/staging/main, which meant
PRs to feature branches skipped lint, format, and build checks.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move staleTime/refetchOnWindowFocus to 3rd arg (options.query) instead of 2nd arg (params)
- Add isError handling to show explicit error state instead of silent N/A
- Guard node.id before rendering NodeSearchRankingCell to handle missing IDs explicitly
- Add enabled: !!nodeId to prevent queries with empty string

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 10, 2026 09:00
@snomiao snomiao removed the request for review from Copilot April 10, 2026 09:00
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.

2 participants