Skip to content

Commit 4e84f30

Browse files
authored
feat: use total_count field from Pagination API response (#175)
## Description <!-- Provide a brief description of your changes --> **Note:** PR titles should follow [Conventional Commits](https://www.conventionalcommits.org/) format (e.g., `feat(devbox): add support for custom env vars` or `fix(snapshot): resolve pagination issue`) as they are used for automatic release notes generation. ## Type of Change <!-- Mark the relevant option with an 'x' --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test updates ## Related Issues <!-- Link to related issues using #issue-number --> Closes # ## Changes Made <!-- Describe the changes in detail --> ## Testing <!-- Describe how you tested your changes --> - [ ] I have tested locally - [ ] I have added/updated tests - [ ] All existing tests pass ## Checklist - [ ] My code follows the code style of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have updated the documentation accordingly - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published ## Screenshots (if applicable) <!-- Add screenshots to help explain your changes --> ## Additional Notes <!-- Any additional information that reviewers should know -->
1 parent 8f4145a commit 4e84f30

9 files changed

Lines changed: 175 additions & 85 deletions

File tree

src/commands/blueprint/list.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,19 @@ const ListBlueprintsUI = ({
113113

114114
// Fetch function for pagination hook
115115
const fetchPage = React.useCallback(
116-
async (params: { limit: number; startingAt?: string }) => {
116+
async (params: {
117+
limit: number;
118+
startingAt?: string;
119+
includeTotalCount?: boolean;
120+
}) => {
117121
const client = getClient();
118122
const pageBlueprints: BlueprintListItem[] = [];
119123

120124
// Build query params
121125
const queryParams: Record<string, unknown> = {
122126
limit: params.limit,
127+
// Only request total_count on first page (expensive for backend)
128+
include_total_count: params.includeTotalCount === true,
123129
};
124130
if (params.startingAt) {
125131
queryParams.starting_after = params.startingAt;
@@ -131,7 +137,9 @@ const ListBlueprintsUI = ({
131137
// Fetch ONE page only
132138
const page = (await client.blueprints.list(
133139
queryParams,
134-
)) as unknown as BlueprintsCursorIDPage<BlueprintListItem>;
140+
)) as unknown as BlueprintsCursorIDPage<BlueprintListItem> & {
141+
total_count?: number;
142+
};
135143

136144
// Extract data and create defensive copies
137145
if (page.blueprints && Array.isArray(page.blueprints)) {
@@ -148,7 +156,7 @@ const ListBlueprintsUI = ({
148156
const result = {
149157
items: pageBlueprints,
150158
hasMore: page.has_more || false,
151-
totalCount: pageBlueprints.length,
159+
totalCount: page.total_count,
152160
};
153161

154162
return result;
@@ -356,7 +364,11 @@ const ListBlueprintsUI = ({
356364
// Calculate pagination info for display
357365
const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE));
358366
const startIndex = currentPage * PAGE_SIZE;
359-
const endIndex = startIndex + blueprints.length;
367+
const endIndex = Math.min(startIndex + blueprints.length, totalCount);
368+
const showingRange =
369+
endIndex === startIndex + 1
370+
? `${startIndex + 1}`
371+
: `${startIndex + 1}-${endIndex}`;
360372

361373
const executeOperation = async (
362374
blueprintOverride?: BlueprintListItem,
@@ -883,7 +895,7 @@ const ListBlueprintsUI = ({
883895
data={blueprints}
884896
keyExtractor={(blueprint: BlueprintListItem) => blueprint.id}
885897
selectedIndex={selectedIndex}
886-
title={`blueprints[${hasMore ? `${totalCount}+` : totalCount}]`}
898+
title={`blueprints[${totalCount}]`}
887899
columns={blueprintColumns}
888900
emptyState={
889901
<Text color={colors.textDim}>
@@ -897,7 +909,7 @@ const ListBlueprintsUI = ({
897909
{!showPopup && (
898910
<Box marginTop={1} paddingX={1}>
899911
<Text color={colors.primary} bold>
900-
{figures.hamburger} {hasMore ? `${totalCount}+` : totalCount}
912+
{figures.hamburger} {totalCount}
901913
</Text>
902914
<Text color={colors.textDim} dimColor>
903915
{" "}
@@ -915,8 +927,7 @@ const ListBlueprintsUI = ({
915927
</Text>
916928
) : (
917929
<Text color={colors.textDim} dimColor>
918-
Page {currentPage + 1} of{" "}
919-
{hasMore ? `${totalPages}+` : totalPages}
930+
Page {currentPage + 1} of {totalPages}
920931
</Text>
921932
)}
922933
</>
@@ -926,8 +937,7 @@ const ListBlueprintsUI = ({
926937
{" "}
927938
</Text>
928939
<Text color={colors.textDim} dimColor>
929-
Showing {startIndex + 1}-{endIndex} of{" "}
930-
{hasMore ? `${totalCount}+` : totalCount}
940+
Showing {showingRange} of {totalCount}
931941
</Text>
932942
{search.submittedSearchQuery && (
933943
<>

src/commands/devbox/list.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,19 @@ const ListDevboxesUI = ({
7878

7979
// Fetch function for pagination hook
8080
const fetchPage = React.useCallback(
81-
async (params: { limit: number; startingAt?: string }) => {
81+
async (params: {
82+
limit: number;
83+
startingAt?: string;
84+
includeTotalCount?: boolean;
85+
}) => {
8286
const client = getClient();
8387
const pageDevboxes: Devbox[] = [];
8488

8589
// Build query params
8690
const queryParams: Record<string, unknown> = {
8791
limit: params.limit,
92+
// Only request total_count on first page (expensive for backend)
93+
include_total_count: params.includeTotalCount === true,
8894
};
8995
if (params.startingAt) {
9096
queryParams.starting_after = params.startingAt;
@@ -99,7 +105,7 @@ const ListDevboxesUI = ({
99105
// Fetch ONE page only
100106
const page = (await client.devboxes.list(
101107
queryParams,
102-
)) as unknown as DevboxesCursorIDPage<Devbox>;
108+
)) as unknown as DevboxesCursorIDPage<Devbox> & { total_count?: number };
103109

104110
// Extract data and create defensive copies using JSON serialization
105111
if (page.devboxes && Array.isArray(page.devboxes)) {
@@ -111,7 +117,7 @@ const ListDevboxesUI = ({
111117
const result = {
112118
items: pageDevboxes,
113119
hasMore: page.has_more || false,
114-
totalCount: pageDevboxes.length,
120+
totalCount: page.total_count,
115121
};
116122

117123
return result;
@@ -419,7 +425,11 @@ const ListDevboxesUI = ({
419425
// Calculate pagination info for display
420426
const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE));
421427
const startIndex = currentPage * PAGE_SIZE;
422-
const endIndex = startIndex + devboxes.length;
428+
const endIndex = Math.min(startIndex + devboxes.length, totalCount);
429+
const showingRange =
430+
endIndex === startIndex + 1
431+
? `${startIndex + 1}`
432+
: `${startIndex + 1}-${endIndex}`;
423433

424434
// Filter operations based on devbox status
425435
const hasTunnel = !!(
@@ -709,7 +719,7 @@ const ListDevboxesUI = ({
709719
data={devboxes}
710720
keyExtractor={(devbox: Devbox) => devbox.id}
711721
selectedIndex={selectedIndex}
712-
title="devboxes"
722+
title={`devboxes[${totalCount}]`}
713723
columns={tableColumns}
714724
emptyState={
715725
<Text color={colors.textDim}>
@@ -723,7 +733,7 @@ const ListDevboxesUI = ({
723733
{!showPopup && (
724734
<Box marginTop={1} paddingX={1}>
725735
<Text color={colors.primary} bold>
726-
{figures.hamburger} {hasMore ? `${totalCount}+` : totalCount}
736+
{figures.hamburger} {totalCount}
727737
</Text>
728738
<Text color={colors.textDim} dimColor>
729739
{" "}
@@ -741,8 +751,7 @@ const ListDevboxesUI = ({
741751
</Text>
742752
) : (
743753
<Text color={colors.textDim} dimColor>
744-
Page {currentPage + 1} of{" "}
745-
{hasMore ? `${totalPages}+` : totalPages}
754+
Page {currentPage + 1} of {totalPages}
746755
</Text>
747756
)}
748757
</>
@@ -752,8 +761,7 @@ const ListDevboxesUI = ({
752761
{" "}
753762
</Text>
754763
<Text color={colors.textDim} dimColor>
755-
Showing {startIndex + 1}-{endIndex} of{" "}
756-
{hasMore ? `${totalCount}+` : totalCount}
764+
Showing {showingRange} of {totalCount}
757765
</Text>
758766
{search.submittedSearchQuery && (
759767
<>

src/commands/gateway-config/list.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,19 @@ const ListGatewayConfigsUI = ({
122122

123123
// Fetch function for pagination hook
124124
const fetchPage = React.useCallback(
125-
async (params: { limit: number; startingAt?: string }) => {
125+
async (params: {
126+
limit: number;
127+
startingAt?: string;
128+
includeTotalCount?: boolean;
129+
}) => {
126130
const client = getClient();
127131
const pageConfigs: GatewayConfigListItem[] = [];
128132

129133
// Build query params
130134
const queryParams: Record<string, unknown> = {
131135
limit: params.limit,
136+
// Only request total_count on first page (expensive for backend)
137+
include_total_count: params.includeTotalCount === true,
132138
};
133139
if (params.startingAt) {
134140
queryParams.starting_after = params.startingAt;
@@ -140,7 +146,9 @@ const ListGatewayConfigsUI = ({
140146
// Fetch ONE page only
141147
const page = (await client.gatewayConfigs.list(
142148
queryParams,
143-
)) as unknown as GatewayConfigsCursorIDPage<GatewayConfigListItem>;
149+
)) as unknown as GatewayConfigsCursorIDPage<GatewayConfigListItem> & {
150+
total_count?: number;
151+
};
144152

145153
// Extract data and create defensive copies
146154
if (page.gateway_configs && Array.isArray(page.gateway_configs)) {
@@ -163,7 +171,7 @@ const ListGatewayConfigsUI = ({
163171
const result = {
164172
items: pageConfigs,
165173
hasMore: page.has_more || false,
166-
totalCount: pageConfigs.length,
174+
totalCount: page.total_count,
167175
};
168176

169177
return result;
@@ -304,7 +312,11 @@ const ListGatewayConfigsUI = ({
304312
// Calculate pagination info for display
305313
const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE));
306314
const startIndex = currentPage * PAGE_SIZE;
307-
const endIndex = startIndex + configs.length;
315+
const endIndex = Math.min(startIndex + configs.length, totalCount);
316+
const showingRange =
317+
endIndex === startIndex + 1
318+
? `${startIndex + 1}`
319+
: `${startIndex + 1}-${endIndex}`;
308320

309321
const executeOperation = async (
310322
config: GatewayConfigListItem,
@@ -653,7 +665,7 @@ const ListGatewayConfigsUI = ({
653665
data={configs}
654666
keyExtractor={(config: GatewayConfigListItem) => config.id}
655667
selectedIndex={selectedIndex}
656-
title={`gateway_configs[${hasMore ? `${totalCount}+` : totalCount}]`}
668+
title={`gateway_configs[${totalCount}]`}
657669
columns={columns}
658670
emptyState={
659671
<Text color={colors.textDim}>
@@ -668,7 +680,7 @@ const ListGatewayConfigsUI = ({
668680
{!showPopup && (
669681
<Box marginTop={1} paddingX={1}>
670682
<Text color={colors.primary} bold>
671-
{figures.hamburger} {hasMore ? `${totalCount}+` : totalCount}
683+
{figures.hamburger} {totalCount}
672684
</Text>
673685
<Text color={colors.textDim} dimColor>
674686
{" "}
@@ -686,8 +698,7 @@ const ListGatewayConfigsUI = ({
686698
</Text>
687699
) : (
688700
<Text color={colors.textDim} dimColor>
689-
Page {currentPage + 1} of{" "}
690-
{hasMore ? `${totalPages}+` : totalPages}
701+
Page {currentPage + 1} of {totalPages}
691702
</Text>
692703
)}
693704
</>
@@ -697,8 +708,7 @@ const ListGatewayConfigsUI = ({
697708
{" "}
698709
</Text>
699710
<Text color={colors.textDim} dimColor>
700-
Showing {startIndex + 1}-{endIndex} of{" "}
701-
{hasMore ? `${totalCount}+` : totalCount}
711+
Showing {showingRange} of {totalCount}
702712
</Text>
703713
{search.submittedSearchQuery && (
704714
<>

src/commands/mcp-config/list.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,18 @@ const ListMcpConfigsUI = ({
103103
const nameWidth = Math.min(80, Math.max(15, remainingWidth));
104104

105105
const fetchPage = React.useCallback(
106-
async (params: { limit: number; startingAt?: string }) => {
106+
async (params: {
107+
limit: number;
108+
startingAt?: string;
109+
includeTotalCount?: boolean;
110+
}) => {
107111
const client = getClient();
108112
const pageConfigs: McpConfigListItem[] = [];
109113

110114
const queryParams: Record<string, unknown> = {
111115
limit: params.limit,
116+
// Only request total_count on first page (expensive for backend)
117+
include_total_count: params.includeTotalCount === true,
112118
};
113119
if (params.startingAt) {
114120
queryParams.starting_after = params.startingAt;
@@ -119,7 +125,9 @@ const ListMcpConfigsUI = ({
119125

120126
const page = (await client.mcpConfigs.list(
121127
queryParams,
122-
)) as unknown as McpConfigsCursorIDPage<McpConfigListItem>;
128+
)) as unknown as McpConfigsCursorIDPage<McpConfigListItem> & {
129+
total_count?: number;
130+
};
123131

124132
if (page.mcp_configs && Array.isArray(page.mcp_configs)) {
125133
page.mcp_configs.forEach((m: McpConfigListItem) => {
@@ -139,7 +147,7 @@ const ListMcpConfigsUI = ({
139147
return {
140148
items: pageConfigs,
141149
hasMore: page.has_more || false,
142-
totalCount: pageConfigs.length,
150+
totalCount: page.total_count,
143151
};
144152
},
145153
[search.submittedSearchQuery],
@@ -266,7 +274,11 @@ const ListMcpConfigsUI = ({
266274

267275
const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE));
268276
const startIndex = currentPage * PAGE_SIZE;
269-
const endIndex = startIndex + configs.length;
277+
const endIndex = Math.min(startIndex + configs.length, totalCount);
278+
const showingRange =
279+
endIndex === startIndex + 1
280+
? `${startIndex + 1}`
281+
: `${startIndex + 1}-${endIndex}`;
270282

271283
const executeOperation = async (
272284
config: McpConfigListItem,
@@ -580,7 +592,7 @@ const ListMcpConfigsUI = ({
580592
data={configs}
581593
keyExtractor={(config: McpConfigListItem) => config.id}
582594
selectedIndex={selectedIndex}
583-
title={`mcp_configs[${hasMore ? `${totalCount}+` : totalCount}]`}
595+
title={`mcp_configs[${totalCount}]`}
584596
columns={columns}
585597
emptyState={
586598
<Text color={colors.textDim}>
@@ -593,7 +605,7 @@ const ListMcpConfigsUI = ({
593605
{!showPopup && (
594606
<Box marginTop={1} paddingX={1}>
595607
<Text color={colors.primary} bold>
596-
{figures.hamburger} {hasMore ? `${totalCount}+` : totalCount}
608+
{figures.hamburger} {totalCount}
597609
</Text>
598610
<Text color={colors.textDim} dimColor>
599611
{" "}
@@ -611,8 +623,7 @@ const ListMcpConfigsUI = ({
611623
</Text>
612624
) : (
613625
<Text color={colors.textDim} dimColor>
614-
Page {currentPage + 1} of{" "}
615-
{hasMore ? `${totalPages}+` : totalPages}
626+
Page {currentPage + 1} of {totalPages}
616627
</Text>
617628
)}
618629
</>
@@ -622,8 +633,7 @@ const ListMcpConfigsUI = ({
622633
{" "}
623634
</Text>
624635
<Text color={colors.textDim} dimColor>
625-
Showing {startIndex + 1}-{endIndex} of{" "}
626-
{hasMore ? `${totalCount}+` : totalCount}
636+
Showing {showingRange} of {totalCount}
627637
</Text>
628638
{search.submittedSearchQuery && (
629639
<>

0 commit comments

Comments
 (0)