Skip to content

Commit f054205

Browse files
authored
feat: add support for --since when listing sandboxes (#68)
1 parent 83cc549 commit f054205

File tree

2 files changed

+77
-12
lines changed

2 files changed

+77
-12
lines changed

src/bin/commands/sandbox/index.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ export const sandboxCommand: CommandModule = {
5454
describe: "Number of items per page",
5555
type: "number",
5656
})
57+
.option("since", {
58+
describe: "Filter by creation date",
59+
type: "string",
60+
})
5761
.option("order-by", {
5862
describe: "Order results by field",
5963
choices: ["inserted_at", "updated_at"],
@@ -66,12 +70,19 @@ export const sandboxCommand: CommandModule = {
6670
})
6771
.option("limit", {
6872
alias: "l",
69-
describe: `Maximum number of sandboxes to list (default: ${DEFAULT_LIMIT})`,
73+
describe: `Maximum number of sandboxes to list (default: ${DEFAULT_LIMIT}, no limit when --since is used)`,
7074
type: "number",
71-
default: DEFAULT_LIMIT,
7275
});
7376
},
7477
handler: async (argv) => {
78+
// Only set the default limit if --since is not provided
79+
const limit =
80+
argv.limit !== undefined
81+
? argv.limit
82+
: argv.since
83+
? undefined
84+
: DEFAULT_LIMIT;
85+
7586
await listSandboxes(
7687
argv.output as string | undefined,
7788
{
@@ -89,9 +100,10 @@ export const sandboxCommand: CommandModule = {
89100
pageSize: argv["page-size"],
90101
}
91102
: undefined,
103+
since: argv.since,
92104
},
93105
argv["headers"] as boolean,
94-
argv.limit as number | undefined
106+
limit as number | undefined
95107
);
96108
},
97109
})

src/bin/commands/sandbox/list.ts

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@ function formatAge(date: Date): string {
4343

4444
export async function listSandboxes(
4545
outputFields?: string,
46-
listOpts: SandboxListOpts & { pagination?: PaginationOpts } = {},
46+
listOpts: SandboxListOpts & {
47+
pagination?: PaginationOpts;
48+
since?: string;
49+
} = {},
4750
showHeaders = true,
48-
limit = 100
51+
limit?: number
4952
) {
5053
const sdk = new CodeSandbox();
5154
const spinner = ora("Fetching sandboxes...").start();
@@ -56,6 +59,25 @@ export async function listSandboxes(
5659
let currentPage = 1;
5760
const pageSize = 50; // API's maximum page size
5861

62+
// Default limit to 100 if not specified, unless since is provided
63+
if (limit === undefined) {
64+
limit = listOpts.since ? Infinity : 100;
65+
}
66+
67+
// If since is provided, ensure we're ordering by inserted_at desc
68+
if (listOpts.since) {
69+
listOpts.orderBy = "inserted_at";
70+
listOpts.direction = "desc";
71+
}
72+
73+
// Parse the since date if provided
74+
const sinceDate = listOpts.since ? new Date(listOpts.since) : null;
75+
if (sinceDate && isNaN(sinceDate.getTime())) {
76+
throw new Error(
77+
`Invalid date format for 'since': ${listOpts.since}. Use ISO format (e.g., '2023-01-01T00:00:00Z').`
78+
);
79+
}
80+
5981
while (true) {
6082
const {
6183
sandboxes,
@@ -74,17 +96,44 @@ export async function listSandboxes(
7496
}
7597

7698
totalCount = total;
77-
const newSandboxes = sandboxes.filter(
99+
100+
// Filter sandboxes by the since date if provided
101+
const filteredSandboxes = sinceDate
102+
? sandboxes.filter(
103+
(sandbox) => new Date(sandbox.createdAt) >= sinceDate
104+
)
105+
: sandboxes;
106+
107+
// If we're using since and ordering by inserted_at desc, we can stop fetching
108+
// once we encounter a sandbox older than the since date
109+
if (
110+
sinceDate &&
111+
listOpts.orderBy === "inserted_at" &&
112+
listOpts.direction === "desc" &&
113+
sandboxes.some((sandbox) => new Date(sandbox.createdAt) < sinceDate)
114+
) {
115+
// Add only the filtered sandboxes that match our criteria
116+
const newSandboxes = filteredSandboxes.filter(
117+
(sandbox) =>
118+
!allSandboxes.some((existing) => existing.id === sandbox.id)
119+
);
120+
allSandboxes = [...allSandboxes, ...newSandboxes];
121+
break;
122+
}
123+
124+
const newSandboxes = filteredSandboxes.filter(
78125
(sandbox) =>
79126
!allSandboxes.some((existing) => existing.id === sandbox.id)
80127
);
81128
allSandboxes = [...allSandboxes, ...newSandboxes];
82129

83130
spinner.text = `Fetching sandboxes... (${allSandboxes.length}${
84-
limit ? `/${Math.min(limit, totalCount)}` : `/${totalCount}`
131+
limit !== Infinity
132+
? `/${Math.min(limit, totalCount)}`
133+
: `/${totalCount}`
85134
})`;
86135

87-
// Stop if we've reached the total count
136+
// Stop if we've reached the total count or the limit
88137
if (allSandboxes.length >= limit || pagination.nextPage == null) {
89138
break;
90139
}
@@ -93,7 +142,7 @@ export async function listSandboxes(
93142
}
94143

95144
// Apply limit after fetching all sandboxes
96-
if (limit) {
145+
if (limit !== Infinity) {
97146
allSandboxes = allSandboxes.slice(0, limit);
98147
}
99148

@@ -125,7 +174,9 @@ export async function listSandboxes(
125174

126175
// eslint-disable-next-line no-console
127176
console.error(
128-
`\nShowing ${allSandboxes.length} of ${totalCount} sandboxes`
177+
listOpts.since
178+
? `\nShowing ${allSandboxes.length} sandboxes created since ${listOpts.since}`
179+
: `\nShowing ${allSandboxes.length} of ${totalCount} sandboxes`
129180
);
130181

131182
return;
@@ -175,10 +226,12 @@ export async function listSandboxes(
175226
// eslint-disable-next-line no-console
176227
console.log(table.toString());
177228

178-
if (limit && totalCount > allSandboxes.length) {
229+
if (limit !== Infinity && totalCount > allSandboxes.length) {
179230
// eslint-disable-next-line no-console
180231
console.error(
181-
`\nShowing ${allSandboxes.length} of ${totalCount} sandboxes`
232+
listOpts.since
233+
? `\nShowing ${allSandboxes.length} sandboxes created since ${listOpts.since}`
234+
: `\nShowing ${allSandboxes.length} of ${totalCount} sandboxes`
182235
);
183236
}
184237
} catch (error) {

0 commit comments

Comments
 (0)