diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 966c8902c3..7bad235d6b 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1187,9 +1187,9 @@ class ApiMethods { }; getWorkspaces = async ( - options: TypesGen.WorkspacesRequest, + req: TypesGen.WorkspacesRequest, ): Promise => { - const url = getURLWithSearchParams("/api/v2/workspaces", options); + const url = getURLWithSearchParams("/api/v2/workspaces", req); const response = await this.axios.get(url); return response.data; }; diff --git a/site/src/api/queries/workspaces.ts b/site/src/api/queries/workspaces.ts index bcfb07b754..1c3e82a881 100644 --- a/site/src/api/queries/workspaces.ts +++ b/site/src/api/queries/workspaces.ts @@ -139,15 +139,14 @@ async function findMatchWorkspace(q: string): Promise { } } -function workspacesKey(config: WorkspacesRequest = {}) { - const { q, limit } = config; - return ["workspaces", { q, limit }] as const; +function workspacesKey(req: WorkspacesRequest = {}) { + return ["workspaces", req] as const; } -export function workspaces(config: WorkspacesRequest = {}) { +export function workspaces(req: WorkspacesRequest = {}) { return { - queryKey: workspacesKey(config), - queryFn: () => API.getWorkspaces(config), + queryKey: workspacesKey(req), + queryFn: () => API.getWorkspaces(req), } as const satisfies QueryOptions; } diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx index 988e9a5385..b80da553de 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx @@ -305,6 +305,67 @@ describe("WorkspacesPage", () => { MockStoppedWorkspace.latest_build.template_version_id, ); }); + + it("correctly handles pagination by including pagination parameters in query key", async () => { + const totalWorkspaces = 50; + const workspacesPage1 = Array.from({ length: 25 }, (_, i) => ({ + ...MockWorkspace, + id: `page1-workspace-${i}`, + name: `page1-workspace-${i}`, + })); + const workspacesPage2 = Array.from({ length: 25 }, (_, i) => ({ + ...MockWorkspace, + id: `page2-workspace-${i}`, + name: `page2-workspace-${i}`, + })); + + const getWorkspacesSpy = jest.spyOn(API, "getWorkspaces"); + + getWorkspacesSpy.mockImplementation(({ offset }) => { + switch (offset) { + case 0: + return Promise.resolve({ + workspaces: workspacesPage1, + count: totalWorkspaces, + }); + case 25: + return Promise.resolve({ + workspaces: workspacesPage2, + count: totalWorkspaces, + }); + default: + return Promise.reject(new Error("Unexpected offset")); + } + }); + + const user = userEvent.setup(); + renderWithAuth(); + + await waitFor(() => { + expect(screen.getByText("page1-workspace-0")).toBeInTheDocument(); + }); + + expect(getWorkspacesSpy).toHaveBeenLastCalledWith({ + q: "owner:me", + offset: 0, + limit: 25, + }); + + const nextPageButton = screen.getByRole("button", { name: /next page/i }); + await user.click(nextPageButton); + + await waitFor(() => { + expect(screen.getByText("page2-workspace-0")).toBeInTheDocument(); + }); + + expect(getWorkspacesSpy).toHaveBeenLastCalledWith({ + q: "owner:me", + offset: 25, + limit: 25, + }); + + expect(screen.queryByText("page1-workspace-0")).not.toBeInTheDocument(); + }); }); const getWorkspaceCheckbox = (workspace: Workspace) => { diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index 62ed7bfed7..0488fc0730 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -116,7 +116,8 @@ const WorkspacesPage: FC = () => { }); const workspacesQueryOptions = workspaces({ - ...pagination, + limit: pagination.limit, + offset: pagination.offset, q: filterState.filter.query, }); const { data, error, refetch } = useQuery({