diff --git a/packages/api/src/builders/builders.repository.ts b/packages/api/src/builders/builders.repository.ts index 609bd3d3..0919a35f 100644 --- a/packages/api/src/builders/builders.repository.ts +++ b/packages/api/src/builders/builders.repository.ts @@ -45,7 +45,7 @@ export function findAll( search: string | undefined, limit: number, offset: number, -): E.Effect<{ data: BuilderDocument[]; total: number }, CollectionNotFoundError | DatabaseError> { +): E.Effect<{ data: BuilderDocument[]; total: number; unmigrated: number }, CollectionNotFoundError | DatabaseError> { const filter: Record = {}; if (search) { const escaped = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); @@ -64,9 +64,13 @@ export function findAll( try: () => collection.countDocuments(filter), catch: (cause) => new DatabaseError({ cause, message: "findAll:count" }), }), + E.tryPromise({ + try: () => collection.countDocuments({ creditsUsd: { $exists: false } }), + catch: (cause) => new DatabaseError({ cause, message: "findAll:unmigrated" }), + }), ]), ), - E.map(([data, total]) => ({ data, total })), + E.map(([data, total, unmigrated]) => ({ data, total, unmigrated })), ); } diff --git a/packages/api/src/credits/credits.controllers.ts b/packages/api/src/credits/credits.controllers.ts index 840feb47..b834d5cd 100644 --- a/packages/api/src/credits/credits.controllers.ts +++ b/packages/api/src/credits/credits.controllers.ts @@ -374,7 +374,7 @@ export function adminListBuilders(options: ControllerOptions): void { return pipe( BuildersRepository.findAll(c.env, search, limit, offset), E.map( - ({ data, total }): AdminListBuildersResponse => ({ + ({ data, total, unmigrated }): AdminListBuildersResponse => ({ data: data.map((b) => ({ did: b.did, name: b.name, @@ -384,7 +384,7 @@ export function adminListBuilders(options: ControllerOptions): void { : b.status) as BuilderStatusDto, storageBytes: b.storageBytes ?? 0, })), - pagination: { total, limit, offset }, + pagination: { total, limit, offset, unmigrated }, }), ), E.map((response) => c.json(response)), diff --git a/packages/types/src/admin.dto.ts b/packages/types/src/admin.dto.ts index f51d7860..cdcf7d89 100644 --- a/packages/types/src/admin.dto.ts +++ b/packages/types/src/admin.dto.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { BuilderStatusDto } from "./credits.dto"; -import { PaginatedResponse } from "./pagination.dto"; +import { SortQuerySchema } from "./pagination.dto"; import { ApiSuccessResponse } from "./responses.dto"; /** @@ -43,10 +43,20 @@ const AdminBuilderDto = z.object({ /** * Paginated list of builders for admin view. + * Extends the standard pagination with an unmigrated count for the migration banner. */ -export const AdminListBuildersResponse = PaginatedResponse(AdminBuilderDto).meta({ - ref: "AdminListBuildersResponse", -}); +export const AdminListBuildersResponse = z + .object({ + data: z.array(AdminBuilderDto), + pagination: z.object({ + total: z.number().int().min(0), + limit: z.number().int().min(1), + offset: z.number().int().min(0), + sort: SortQuerySchema, + unmigrated: z.number().int().min(0), + }), + }) + .meta({ ref: "AdminListBuildersResponse" }); export type AdminListBuildersResponse = z.infer; /**