From eb9cb9f0016e1a0ada236dcb3522c6bf3111d183 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Mon, 16 Mar 2026 18:54:16 -0700 Subject: [PATCH 1/5] feat: use total_count field from Pagination API response --- src/commands/blueprint/list.tsx | 16 ++++++++++--- src/commands/devbox/list.tsx | 14 ++++++++--- src/commands/gateway-config/list.tsx | 16 ++++++++++--- src/commands/mcp-config/list.tsx | 16 ++++++++++--- src/commands/network-policy/list.tsx | 16 ++++++++++--- src/commands/object/list.tsx | 13 +++++++++-- src/commands/secret/list.tsx | 6 ++++- src/commands/snapshot/list.tsx | 16 ++++++++++--- src/hooks/useCursorPagination.ts | 35 +++++++++++++++++++++------- 9 files changed, 118 insertions(+), 30 deletions(-) diff --git a/src/commands/blueprint/list.tsx b/src/commands/blueprint/list.tsx index 00222c5a..49af3b5c 100644 --- a/src/commands/blueprint/list.tsx +++ b/src/commands/blueprint/list.tsx @@ -113,7 +113,11 @@ const ListBlueprintsUI = ({ // Fetch function for pagination hook const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pageBlueprints: BlueprintListItem[] = []; @@ -127,11 +131,17 @@ const ListBlueprintsUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } + // Only request total_count on first page (expensive for backend) + if (params.includeTotalCount) { + queryParams.include_total_count = true; + } // Fetch ONE page only const page = (await client.blueprints.list( queryParams, - )) as unknown as BlueprintsCursorIDPage; + )) as unknown as BlueprintsCursorIDPage & { + total_count?: number; + }; // Extract data and create defensive copies if (page.blueprints && Array.isArray(page.blueprints)) { @@ -148,7 +158,7 @@ const ListBlueprintsUI = ({ const result = { items: pageBlueprints, hasMore: page.has_more || false, - totalCount: pageBlueprints.length, + totalCount: page.total_count, }; return result; diff --git a/src/commands/devbox/list.tsx b/src/commands/devbox/list.tsx index 6af2a778..d2ed6283 100644 --- a/src/commands/devbox/list.tsx +++ b/src/commands/devbox/list.tsx @@ -78,7 +78,11 @@ const ListDevboxesUI = ({ // Fetch function for pagination hook const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pageDevboxes: Devbox[] = []; @@ -95,11 +99,15 @@ const ListDevboxesUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } + // Only request total_count on first page (expensive for backend) + if (params.includeTotalCount) { + queryParams.include_total_count = true; + } // Fetch ONE page only const page = (await client.devboxes.list( queryParams, - )) as unknown as DevboxesCursorIDPage; + )) as unknown as DevboxesCursorIDPage & { total_count?: number }; // Extract data and create defensive copies using JSON serialization if (page.devboxes && Array.isArray(page.devboxes)) { @@ -111,7 +119,7 @@ const ListDevboxesUI = ({ const result = { items: pageDevboxes, hasMore: page.has_more || false, - totalCount: pageDevboxes.length, + totalCount: page.total_count, }; return result; diff --git a/src/commands/gateway-config/list.tsx b/src/commands/gateway-config/list.tsx index 10a4252c..cb2f63ec 100644 --- a/src/commands/gateway-config/list.tsx +++ b/src/commands/gateway-config/list.tsx @@ -122,7 +122,11 @@ const ListGatewayConfigsUI = ({ // Fetch function for pagination hook const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pageConfigs: GatewayConfigListItem[] = []; @@ -136,11 +140,17 @@ const ListGatewayConfigsUI = ({ if (search.submittedSearchQuery) { queryParams.name = search.submittedSearchQuery; } + // Only request total_count on first page (expensive for backend) + if (params.includeTotalCount) { + queryParams.include_total_count = true; + } // Fetch ONE page only const page = (await client.gatewayConfigs.list( queryParams, - )) as unknown as GatewayConfigsCursorIDPage; + )) as unknown as GatewayConfigsCursorIDPage & { + total_count?: number; + }; // Extract data and create defensive copies if (page.gateway_configs && Array.isArray(page.gateway_configs)) { @@ -163,7 +173,7 @@ const ListGatewayConfigsUI = ({ const result = { items: pageConfigs, hasMore: page.has_more || false, - totalCount: pageConfigs.length, + totalCount: page.total_count, }; return result; diff --git a/src/commands/mcp-config/list.tsx b/src/commands/mcp-config/list.tsx index 6a3ecd90..027f18d1 100644 --- a/src/commands/mcp-config/list.tsx +++ b/src/commands/mcp-config/list.tsx @@ -103,7 +103,11 @@ const ListMcpConfigsUI = ({ const nameWidth = Math.min(80, Math.max(15, remainingWidth)); const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pageConfigs: McpConfigListItem[] = []; @@ -116,10 +120,16 @@ const ListMcpConfigsUI = ({ if (search.submittedSearchQuery) { queryParams.name = search.submittedSearchQuery; } + // Only request total_count on first page (expensive for backend) + if (params.includeTotalCount) { + queryParams.include_total_count = true; + } const page = (await client.mcpConfigs.list( queryParams, - )) as unknown as McpConfigsCursorIDPage; + )) as unknown as McpConfigsCursorIDPage & { + total_count?: number; + }; if (page.mcp_configs && Array.isArray(page.mcp_configs)) { page.mcp_configs.forEach((m: McpConfigListItem) => { @@ -139,7 +149,7 @@ const ListMcpConfigsUI = ({ return { items: pageConfigs, hasMore: page.has_more || false, - totalCount: pageConfigs.length, + totalCount: page.total_count, }; }, [search.submittedSearchQuery], diff --git a/src/commands/network-policy/list.tsx b/src/commands/network-policy/list.tsx index 5b19e808..b14e6823 100644 --- a/src/commands/network-policy/list.tsx +++ b/src/commands/network-policy/list.tsx @@ -135,7 +135,11 @@ const ListNetworkPoliciesUI = ({ // Fetch function for pagination hook const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pagePolicies: NetworkPolicyListItem[] = []; @@ -149,11 +153,17 @@ const ListNetworkPoliciesUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } + // Only request total_count on first page (expensive for backend) + if (params.includeTotalCount) { + queryParams.include_total_count = true; + } // Fetch ONE page only const page = (await client.networkPolicies.list( queryParams, - )) as unknown as NetworkPoliciesCursorIDPage; + )) as unknown as NetworkPoliciesCursorIDPage & { + total_count?: number; + }; // Extract data and create defensive copies if (page.network_policies && Array.isArray(page.network_policies)) { @@ -178,7 +188,7 @@ const ListNetworkPoliciesUI = ({ const result = { items: pagePolicies, hasMore: page.has_more || false, - totalCount: pagePolicies.length, + totalCount: page.total_count, }; return result; diff --git a/src/commands/object/list.tsx b/src/commands/object/list.tsx index d7579290..ba0117ee 100644 --- a/src/commands/object/list.tsx +++ b/src/commands/object/list.tsx @@ -135,7 +135,11 @@ const ListObjectsUI = ({ // Fetch function for pagination hook const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pageObjects: ObjectListItem[] = []; @@ -149,6 +153,10 @@ const ListObjectsUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } + // Only request total_count on first page (expensive for backend) + if (params.includeTotalCount) { + queryParams.include_total_count = true; + } // Fetch ONE page only const result = await client.objects.list(queryParams); @@ -174,12 +182,13 @@ const ListObjectsUI = ({ const pageResult = result as unknown as { objects: unknown[]; has_more?: boolean; + total_count?: number; }; return { items: pageObjects, hasMore: pageResult.has_more || false, - totalCount: pageObjects.length, + totalCount: pageResult.total_count, }; }, [search.submittedSearchQuery], diff --git a/src/commands/secret/list.tsx b/src/commands/secret/list.tsx index 2f721c66..bec3e877 100644 --- a/src/commands/secret/list.tsx +++ b/src/commands/secret/list.tsx @@ -90,7 +90,11 @@ const ListSecretsUI = ({ // Fetch function for pagination hook const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pageSecrets: SecretListItem[] = []; diff --git a/src/commands/snapshot/list.tsx b/src/commands/snapshot/list.tsx index bf357a11..f950b771 100644 --- a/src/commands/snapshot/list.tsx +++ b/src/commands/snapshot/list.tsx @@ -104,7 +104,11 @@ const ListSnapshotsUI = ({ // Fetch function for pagination hook const fetchPage = React.useCallback( - async (params: { limit: number; startingAt?: string }) => { + async (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => { const client = getClient(); const pageSnapshots: SnapshotListItem[] = []; @@ -121,11 +125,17 @@ const ListSnapshotsUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } + // Only request total_count on first page (expensive for backend) + if (params.includeTotalCount) { + queryParams.include_total_count = true; + } // Fetch ONE page only const page = (await client.devboxes.listDiskSnapshots( queryParams, - )) as unknown as DiskSnapshotsCursorIDPage; + )) as unknown as DiskSnapshotsCursorIDPage & { + total_count?: number; + }; // Extract data and create defensive copies if (page.snapshots && Array.isArray(page.snapshots)) { @@ -143,7 +153,7 @@ const ListSnapshotsUI = ({ const result = { items: pageSnapshots, hasMore: page.has_more || false, - totalCount: pageSnapshots.length, + totalCount: page.total_count, }; return result; diff --git a/src/hooks/useCursorPagination.ts b/src/hooks/useCursorPagination.ts index 5aae8c39..b695596a 100644 --- a/src/hooks/useCursorPagination.ts +++ b/src/hooks/useCursorPagination.ts @@ -7,7 +7,11 @@ export interface UsePaginatedListConfig { /** * Fetch function that takes pagination params and returns a page of results */ - fetchPage: (params: { limit: number; startingAt?: string }) => Promise<{ + fetchPage: (params: { + limit: number; + startingAt?: string; + includeTotalCount?: boolean; + }) => Promise<{ items: T[]; hasMore: boolean; totalCount?: number; @@ -101,7 +105,8 @@ export function useCursorPagination( const [currentPage, setCurrentPage] = React.useState(0); const [hasMore, setHasMore] = React.useState(false); const [totalCount, setTotalCount] = React.useState(0); - const maxTotalCountRef = React.useRef(0); + // Track if we have a cached total count from the API (to avoid re-requesting) + const hasCachedTotalCountRef = React.useRef(false); // Cursor history: cursorHistory[N] = last item ID of page N // Used to determine startingAt for page N+1 @@ -171,9 +176,13 @@ export function useCursorPagination( const startingAt = page > 0 ? cursorHistoryRef.current[page - 1] : undefined; + // Only request total_count on first fetch or when we don't have it cached + const includeTotalCount = !hasCachedTotalCountRef.current; + const result = await fetchPageRef.current({ limit: pageSizeRef.current, startingAt, + includeTotalCount, }); if (!isMountedRef.current) return; @@ -191,12 +200,20 @@ export function useCursorPagination( // Update pagination state setHasMore(result.hasMore); - // Compute cumulative total: items seen on all previous pages + current page. - // Use a high-water mark so the count never decreases when navigating back. - const computed = page * pageSizeRef.current + result.items.length; - const newTotal = Math.max(computed, maxTotalCountRef.current); - maxTotalCountRef.current = newTotal; - setTotalCount(newTotal); + + // Use API's totalCount if available (only on first fetch), otherwise keep existing + if ( + result.totalCount !== undefined && + result.totalCount > 0 && + !hasCachedTotalCountRef.current + ) { + setTotalCount(result.totalCount); + hasCachedTotalCountRef.current = true; + } else if (!hasCachedTotalCountRef.current) { + // Fallback: compute from items seen so far (for APIs that don't support total_count) + const computed = page * pageSizeRef.current + result.items.length; + setTotalCount((prev) => Math.max(computed, prev)); + } } catch (err) { if (!isMountedRef.current) return; setError(err as Error); @@ -216,7 +233,7 @@ export function useCursorPagination( React.useEffect(() => { // Clear cursor history when deps change cursorHistoryRef.current = []; - maxTotalCountRef.current = 0; + hasCachedTotalCountRef.current = false; setCurrentPage(0); setItems([]); setHasMore(false); From 7b19628b8a8383858d0990724e573557927482b1 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Fri, 20 Mar 2026 15:37:57 -0700 Subject: [PATCH 2/5] delete + suffix --- src/commands/blueprint/list.tsx | 10 ++++------ src/commands/devbox/list.tsx | 8 +++----- src/commands/gateway-config/list.tsx | 10 ++++------ src/commands/mcp-config/list.tsx | 10 ++++------ src/commands/network-policy/list.tsx | 10 ++++------ src/commands/object/list.tsx | 10 ++++------ src/commands/secret/list.tsx | 8 +++----- src/commands/snapshot/list.tsx | 10 ++++------ 8 files changed, 30 insertions(+), 46 deletions(-) diff --git a/src/commands/blueprint/list.tsx b/src/commands/blueprint/list.tsx index 49af3b5c..3a60fc65 100644 --- a/src/commands/blueprint/list.tsx +++ b/src/commands/blueprint/list.tsx @@ -893,7 +893,7 @@ const ListBlueprintsUI = ({ data={blueprints} keyExtractor={(blueprint: BlueprintListItem) => blueprint.id} selectedIndex={selectedIndex} - title={`blueprints[${hasMore ? `${totalCount}+` : totalCount}]`} + title={`blueprints[${totalCount}]`} columns={blueprintColumns} emptyState={ @@ -907,7 +907,7 @@ const ListBlueprintsUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -925,8 +925,7 @@ const ListBlueprintsUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -936,8 +935,7 @@ const ListBlueprintsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/devbox/list.tsx b/src/commands/devbox/list.tsx index d2ed6283..018d434c 100644 --- a/src/commands/devbox/list.tsx +++ b/src/commands/devbox/list.tsx @@ -731,7 +731,7 @@ const ListDevboxesUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -749,8 +749,7 @@ const ListDevboxesUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -760,8 +759,7 @@ const ListDevboxesUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/gateway-config/list.tsx b/src/commands/gateway-config/list.tsx index cb2f63ec..990d2743 100644 --- a/src/commands/gateway-config/list.tsx +++ b/src/commands/gateway-config/list.tsx @@ -663,7 +663,7 @@ const ListGatewayConfigsUI = ({ data={configs} keyExtractor={(config: GatewayConfigListItem) => config.id} selectedIndex={selectedIndex} - title={`gateway_configs[${hasMore ? `${totalCount}+` : totalCount}]`} + title={`gateway_configs[${totalCount}]`} columns={columns} emptyState={ @@ -678,7 +678,7 @@ const ListGatewayConfigsUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -696,8 +696,7 @@ const ListGatewayConfigsUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -707,8 +706,7 @@ const ListGatewayConfigsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/mcp-config/list.tsx b/src/commands/mcp-config/list.tsx index 027f18d1..4dad5f1f 100644 --- a/src/commands/mcp-config/list.tsx +++ b/src/commands/mcp-config/list.tsx @@ -590,7 +590,7 @@ const ListMcpConfigsUI = ({ data={configs} keyExtractor={(config: McpConfigListItem) => config.id} selectedIndex={selectedIndex} - title={`mcp_configs[${hasMore ? `${totalCount}+` : totalCount}]`} + title={`mcp_configs[${totalCount}]`} columns={columns} emptyState={ @@ -603,7 +603,7 @@ const ListMcpConfigsUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -621,8 +621,7 @@ const ListMcpConfigsUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -632,8 +631,7 @@ const ListMcpConfigsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/network-policy/list.tsx b/src/commands/network-policy/list.tsx index b14e6823..66663fbf 100644 --- a/src/commands/network-policy/list.tsx +++ b/src/commands/network-policy/list.tsx @@ -693,7 +693,7 @@ const ListNetworkPoliciesUI = ({ data={policies} keyExtractor={(policy: NetworkPolicyListItem) => policy.id} selectedIndex={selectedIndex} - title={`network_policies[${hasMore ? `${totalCount}+` : totalCount}]`} + title={`network_policies[${totalCount}]`} columns={columns} emptyState={ @@ -707,7 +707,7 @@ const ListNetworkPoliciesUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -725,8 +725,7 @@ const ListNetworkPoliciesUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -736,8 +735,7 @@ const ListNetworkPoliciesUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/object/list.tsx b/src/commands/object/list.tsx index ba0117ee..c2979a43 100644 --- a/src/commands/object/list.tsx +++ b/src/commands/object/list.tsx @@ -733,7 +733,7 @@ const ListObjectsUI = ({ data={objects} keyExtractor={(obj: ObjectListItem) => obj.id} selectedIndex={selectedIndex} - title={`storage_objects[${hasMore ? `${totalCount}+` : totalCount}]`} + title={`storage_objects[${totalCount}]`} columns={columns} emptyState={ @@ -748,7 +748,7 @@ const ListObjectsUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -766,8 +766,7 @@ const ListObjectsUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -777,8 +776,7 @@ const ListObjectsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/secret/list.tsx b/src/commands/secret/list.tsx index bec3e877..8c009b1b 100644 --- a/src/commands/secret/list.tsx +++ b/src/commands/secret/list.tsx @@ -547,7 +547,7 @@ const ListSecretsUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -565,8 +565,7 @@ const ListSecretsUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -576,8 +575,7 @@ const ListSecretsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/snapshot/list.tsx b/src/commands/snapshot/list.tsx index f950b771..56b96305 100644 --- a/src/commands/snapshot/list.tsx +++ b/src/commands/snapshot/list.tsx @@ -605,7 +605,7 @@ const ListSnapshotsUI = ({ data={snapshots} keyExtractor={(snapshot: SnapshotListItem) => snapshot.id} selectedIndex={selectedIndex} - title={`snapshots[${hasMore ? `${totalCount}+` : totalCount}]`} + title={`snapshots[${totalCount}]`} columns={columns} emptyState={ @@ -620,7 +620,7 @@ const ListSnapshotsUI = ({ {!showPopup && ( - {figures.hamburger} {hasMore ? `${totalCount}+` : totalCount} + {figures.hamburger} {totalCount} {" "} @@ -638,8 +638,7 @@ const ListSnapshotsUI = ({ ) : ( - Page {currentPage + 1} of{" "} - {hasMore ? `${totalPages}+` : totalPages} + Page {currentPage + 1} of {totalPages} )} @@ -649,8 +648,7 @@ const ListSnapshotsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of{" "} - {hasMore ? `${totalCount}+` : totalCount} + Showing {startIndex + 1}-{endIndex} of {totalCount} {search.submittedSearchQuery && ( <> From b67e9eb925c408ed84369713a5937da53bad8e20 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Fri, 20 Mar 2026 15:58:23 -0700 Subject: [PATCH 3/5] fix range bugs --- src/commands/blueprint/list.tsx | 8 ++++++-- src/commands/devbox/list.tsx | 8 ++++++-- src/commands/gateway-config/list.tsx | 8 ++++++-- src/commands/mcp-config/list.tsx | 8 ++++++-- src/commands/network-policy/list.tsx | 8 ++++++-- src/commands/object/list.tsx | 8 ++++++-- src/commands/secret/list.tsx | 8 ++++++-- src/commands/snapshot/list.tsx | 8 ++++++-- 8 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/commands/blueprint/list.tsx b/src/commands/blueprint/list.tsx index 3a60fc65..fabb0f66 100644 --- a/src/commands/blueprint/list.tsx +++ b/src/commands/blueprint/list.tsx @@ -366,7 +366,11 @@ const ListBlueprintsUI = ({ // Calculate pagination info for display const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + blueprints.length; + const endIndex = Math.min(startIndex + blueprints.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; const executeOperation = async ( blueprintOverride?: BlueprintListItem, @@ -935,7 +939,7 @@ const ListBlueprintsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/devbox/list.tsx b/src/commands/devbox/list.tsx index 018d434c..f9132e1d 100644 --- a/src/commands/devbox/list.tsx +++ b/src/commands/devbox/list.tsx @@ -427,7 +427,11 @@ const ListDevboxesUI = ({ // Calculate pagination info for display const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + devboxes.length; + const endIndex = Math.min(startIndex + devboxes.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; // Filter operations based on devbox status const hasTunnel = !!( @@ -759,7 +763,7 @@ const ListDevboxesUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/gateway-config/list.tsx b/src/commands/gateway-config/list.tsx index 990d2743..720e4f80 100644 --- a/src/commands/gateway-config/list.tsx +++ b/src/commands/gateway-config/list.tsx @@ -314,7 +314,11 @@ const ListGatewayConfigsUI = ({ // Calculate pagination info for display const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + configs.length; + const endIndex = Math.min(startIndex + configs.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; const executeOperation = async ( config: GatewayConfigListItem, @@ -706,7 +710,7 @@ const ListGatewayConfigsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/mcp-config/list.tsx b/src/commands/mcp-config/list.tsx index 4dad5f1f..18029ee3 100644 --- a/src/commands/mcp-config/list.tsx +++ b/src/commands/mcp-config/list.tsx @@ -276,7 +276,11 @@ const ListMcpConfigsUI = ({ const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + configs.length; + const endIndex = Math.min(startIndex + configs.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; const executeOperation = async ( config: McpConfigListItem, @@ -631,7 +635,7 @@ const ListMcpConfigsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/network-policy/list.tsx b/src/commands/network-policy/list.tsx index 66663fbf..40dc9b62 100644 --- a/src/commands/network-policy/list.tsx +++ b/src/commands/network-policy/list.tsx @@ -351,7 +351,11 @@ const ListNetworkPoliciesUI = ({ // Calculate pagination info for display const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + policies.length; + const endIndex = Math.min(startIndex + policies.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; const executeOperation = async ( policy: NetworkPolicyListItem, @@ -735,7 +739,7 @@ const ListNetworkPoliciesUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/object/list.tsx b/src/commands/object/list.tsx index c2979a43..3e0be10d 100644 --- a/src/commands/object/list.tsx +++ b/src/commands/object/list.tsx @@ -353,7 +353,11 @@ const ListObjectsUI = ({ // Calculate pagination info for display const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + objects.length; + const endIndex = Math.min(startIndex + objects.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; const executeOperation = async ( obj: ObjectListItem, @@ -776,7 +780,7 @@ const ListObjectsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/secret/list.tsx b/src/commands/secret/list.tsx index 8c009b1b..7602d137 100644 --- a/src/commands/secret/list.tsx +++ b/src/commands/secret/list.tsx @@ -241,7 +241,11 @@ const ListSecretsUI = ({ // Calculate pagination info for display const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + secrets.length; + const endIndex = Math.min(startIndex + secrets.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; const executeOperation = async ( secret: SecretListItem, @@ -575,7 +579,7 @@ const ListSecretsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> diff --git a/src/commands/snapshot/list.tsx b/src/commands/snapshot/list.tsx index 56b96305..1bed9c2a 100644 --- a/src/commands/snapshot/list.tsx +++ b/src/commands/snapshot/list.tsx @@ -278,7 +278,11 @@ const ListSnapshotsUI = ({ // Calculate pagination info for display const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); const startIndex = currentPage * PAGE_SIZE; - const endIndex = startIndex + snapshots.length; + const endIndex = Math.min(startIndex + snapshots.length, totalCount); + const showingRange = + endIndex === startIndex + 1 + ? `${startIndex + 1}` + : `${startIndex + 1}-${endIndex}`; const executeOperation = async ( snapshot: SnapshotListItem, @@ -648,7 +652,7 @@ const ListSnapshotsUI = ({ •{" "} - Showing {startIndex + 1}-{endIndex} of {totalCount} + Showing {showingRange} of {totalCount} {search.submittedSearchQuery && ( <> From 8a0e65ef63c7725c340be51fbaf415594edabbff Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Fri, 20 Mar 2026 16:08:15 -0700 Subject: [PATCH 4/5] fix inconsistency --- src/commands/devbox/list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/devbox/list.tsx b/src/commands/devbox/list.tsx index f9132e1d..b33973a5 100644 --- a/src/commands/devbox/list.tsx +++ b/src/commands/devbox/list.tsx @@ -721,7 +721,7 @@ const ListDevboxesUI = ({ data={devboxes} keyExtractor={(devbox: Devbox) => devbox.id} selectedIndex={selectedIndex} - title="devboxes" + title={`devboxes[${totalCount}]`} columns={tableColumns} emptyState={ From e48e389dd26cdf5e4a34d56d77feab9bf1f6bb48 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Tue, 24 Mar 2026 15:28:31 -0700 Subject: [PATCH 5/5] make it fast --- src/commands/blueprint/list.tsx | 6 ++---- src/commands/devbox/list.tsx | 6 ++---- src/commands/gateway-config/list.tsx | 6 ++---- src/commands/mcp-config/list.tsx | 6 ++---- src/commands/network-policy/list.tsx | 6 ++---- src/commands/object/list.tsx | 6 ++---- src/commands/snapshot/list.tsx | 6 ++---- 7 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/commands/blueprint/list.tsx b/src/commands/blueprint/list.tsx index fabb0f66..68c39847 100644 --- a/src/commands/blueprint/list.tsx +++ b/src/commands/blueprint/list.tsx @@ -124,6 +124,8 @@ const ListBlueprintsUI = ({ // Build query params const queryParams: Record = { limit: params.limit, + // Only request total_count on first page (expensive for backend) + include_total_count: params.includeTotalCount === true, }; if (params.startingAt) { queryParams.starting_after = params.startingAt; @@ -131,10 +133,6 @@ const ListBlueprintsUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } - // Only request total_count on first page (expensive for backend) - if (params.includeTotalCount) { - queryParams.include_total_count = true; - } // Fetch ONE page only const page = (await client.blueprints.list( diff --git a/src/commands/devbox/list.tsx b/src/commands/devbox/list.tsx index b33973a5..4bc1f2ee 100644 --- a/src/commands/devbox/list.tsx +++ b/src/commands/devbox/list.tsx @@ -89,6 +89,8 @@ const ListDevboxesUI = ({ // Build query params const queryParams: Record = { limit: params.limit, + // Only request total_count on first page (expensive for backend) + include_total_count: params.includeTotalCount === true, }; if (params.startingAt) { queryParams.starting_after = params.startingAt; @@ -99,10 +101,6 @@ const ListDevboxesUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } - // Only request total_count on first page (expensive for backend) - if (params.includeTotalCount) { - queryParams.include_total_count = true; - } // Fetch ONE page only const page = (await client.devboxes.list( diff --git a/src/commands/gateway-config/list.tsx b/src/commands/gateway-config/list.tsx index 720e4f80..7529127a 100644 --- a/src/commands/gateway-config/list.tsx +++ b/src/commands/gateway-config/list.tsx @@ -133,6 +133,8 @@ const ListGatewayConfigsUI = ({ // Build query params const queryParams: Record = { limit: params.limit, + // Only request total_count on first page (expensive for backend) + include_total_count: params.includeTotalCount === true, }; if (params.startingAt) { queryParams.starting_after = params.startingAt; @@ -140,10 +142,6 @@ const ListGatewayConfigsUI = ({ if (search.submittedSearchQuery) { queryParams.name = search.submittedSearchQuery; } - // Only request total_count on first page (expensive for backend) - if (params.includeTotalCount) { - queryParams.include_total_count = true; - } // Fetch ONE page only const page = (await client.gatewayConfigs.list( diff --git a/src/commands/mcp-config/list.tsx b/src/commands/mcp-config/list.tsx index 18029ee3..b25895a7 100644 --- a/src/commands/mcp-config/list.tsx +++ b/src/commands/mcp-config/list.tsx @@ -113,6 +113,8 @@ const ListMcpConfigsUI = ({ const queryParams: Record = { limit: params.limit, + // Only request total_count on first page (expensive for backend) + include_total_count: params.includeTotalCount === true, }; if (params.startingAt) { queryParams.starting_after = params.startingAt; @@ -120,10 +122,6 @@ const ListMcpConfigsUI = ({ if (search.submittedSearchQuery) { queryParams.name = search.submittedSearchQuery; } - // Only request total_count on first page (expensive for backend) - if (params.includeTotalCount) { - queryParams.include_total_count = true; - } const page = (await client.mcpConfigs.list( queryParams, diff --git a/src/commands/network-policy/list.tsx b/src/commands/network-policy/list.tsx index 40dc9b62..9e6d9bdf 100644 --- a/src/commands/network-policy/list.tsx +++ b/src/commands/network-policy/list.tsx @@ -146,6 +146,8 @@ const ListNetworkPoliciesUI = ({ // Build query params const queryParams: Record = { limit: params.limit, + // Only request total_count on first page (expensive for backend) + include_total_count: params.includeTotalCount === true, }; if (params.startingAt) { queryParams.starting_after = params.startingAt; @@ -153,10 +155,6 @@ const ListNetworkPoliciesUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } - // Only request total_count on first page (expensive for backend) - if (params.includeTotalCount) { - queryParams.include_total_count = true; - } // Fetch ONE page only const page = (await client.networkPolicies.list( diff --git a/src/commands/object/list.tsx b/src/commands/object/list.tsx index 3e0be10d..6dd47980 100644 --- a/src/commands/object/list.tsx +++ b/src/commands/object/list.tsx @@ -146,6 +146,8 @@ const ListObjectsUI = ({ // Build query params const queryParams: Record = { limit: params.limit, + // Only request total_count on first page (expensive for backend) + include_total_count: params.includeTotalCount === true, }; if (params.startingAt) { queryParams.starting_after = params.startingAt; @@ -153,10 +155,6 @@ const ListObjectsUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } - // Only request total_count on first page (expensive for backend) - if (params.includeTotalCount) { - queryParams.include_total_count = true; - } // Fetch ONE page only const result = await client.objects.list(queryParams); diff --git a/src/commands/snapshot/list.tsx b/src/commands/snapshot/list.tsx index 1bed9c2a..7cdba0f1 100644 --- a/src/commands/snapshot/list.tsx +++ b/src/commands/snapshot/list.tsx @@ -115,6 +115,8 @@ const ListSnapshotsUI = ({ // Build query params const queryParams: Record = { limit: params.limit, + // Only request total_count on first page (expensive for backend) + include_total_count: params.includeTotalCount === true, }; if (params.startingAt) { queryParams.starting_after = params.startingAt; @@ -125,10 +127,6 @@ const ListSnapshotsUI = ({ if (search.submittedSearchQuery) { queryParams.search = search.submittedSearchQuery; } - // Only request total_count on first page (expensive for backend) - if (params.includeTotalCount) { - queryParams.include_total_count = true; - } // Fetch ONE page only const page = (await client.devboxes.listDiskSnapshots(