chore: refactor workspace count to single route (#4809)

Co-authored-by: Presley Pizzo <presley@coder.com>
This commit is contained in:
Garrett Delfosse
2022-11-10 13:25:46 -05:00
committed by GitHub
co-authored by Presley Pizzo
parent 5fb9c33ecd
commit 766a2ad590
23 changed files with 160 additions and 761 deletions
+2 -10
View File
@@ -298,17 +298,9 @@ export const getURLWithSearchParams = (
export const getWorkspaces = async (
options: TypesGen.WorkspacesRequest,
): Promise<TypesGen.Workspace[]> => {
): Promise<TypesGen.WorkspacesResponse> => {
const url = getURLWithSearchParams("/api/v2/workspaces", options)
const response = await axios.get<TypesGen.Workspace[]>(url)
return response.data
}
export const getWorkspacesCount = async (
options: TypesGen.WorkspaceCountRequest,
): Promise<TypesGen.WorkspaceCountResponse> => {
const url = getURLWithSearchParams("/api/v2/workspaces/count", options)
const response = await axios.get(url)
const response = await axios.get<TypesGen.WorkspacesResponse>(url)
return response.data
}
+6 -10
View File
@@ -883,16 +883,6 @@ export interface WorkspaceBuildsRequest extends Pagination {
readonly Since: string
}
// From codersdk/workspaces.go
export interface WorkspaceCountRequest {
readonly q?: string
}
// From codersdk/workspaces.go
export interface WorkspaceCountResponse {
readonly count: number
}
// From codersdk/workspaces.go
export interface WorkspaceFilter {
readonly q?: string
@@ -935,6 +925,12 @@ export interface WorkspacesRequest extends Pagination {
readonly q?: string
}
// From codersdk/workspaces.go
export interface WorkspacesResponse {
readonly workspaces: Workspace[]
readonly count: number
}
// From codersdk/apikey.go
export type APIKeyScope = "all" | "application_connect"
@@ -21,7 +21,7 @@ describe("WorkspacesPage", () => {
// Given
server.use(
rest.get("/api/v2/workspaces", async (req, res, ctx) => {
return res(ctx.status(200), ctx.json([]))
return res(ctx.status(200), ctx.json({ workspaces: [], count: 0 }))
}),
)
@@ -53,6 +53,6 @@ describe("WorkspacesPage", () => {
},
{ timeout: 2000 },
)
await screen.findByText(MockWorkspace.name)
await screen.findByText(`${MockWorkspace.name}1`)
})
})
+11 -4
View File
@@ -2,6 +2,7 @@ import { FieldError } from "api/errors"
import { everyOneGroup } from "util/groups"
import * as Types from "../api/types"
import * as TypesGen from "../api/typesGenerated"
import { range } from "lodash"
export const MockTemplateDAUResponse: TypesGen.TemplateDAUsResponse = {
entries: [
@@ -523,6 +524,16 @@ export const MockPendingWorkspace: TypesGen.Workspace = {
},
}
// just over one page of workspaces
export const MockWorkspacesResponse: TypesGen.WorkspacesResponse = {
workspaces: range(1, 27).map((id: number) => ({
...MockWorkspace,
id: id.toString(),
name: `${MockWorkspace.name}${id}`,
})),
count: 26,
}
// requests the MockWorkspace
export const MockWorkspaceRequest: TypesGen.CreateWorkspaceRequest = {
name: "test",
@@ -530,10 +541,6 @@ export const MockWorkspaceRequest: TypesGen.CreateWorkspaceRequest = {
template_id: "test-template",
}
export const MockWorkspaceCountResponse: TypesGen.WorkspaceCountResponse = {
count: 26, // just over 1 page
}
export const MockUserAgent: Types.UserAgent = {
browser: "Chrome 99.0.4844",
device: "Other",
+1 -5
View File
@@ -138,11 +138,7 @@ export const handlers = [
// workspaces
rest.get("/api/v2/workspaces", async (req, res, ctx) => {
return res(ctx.status(200), ctx.json([M.MockWorkspace]))
}),
// has to come before the parameterized endpoints
rest.get("/api/v2/workspaces/count", async (req, res, ctx) => {
return res(ctx.status(200), ctx.json(M.MockWorkspaceCountResponse))
return res(ctx.status(200), ctx.json(M.MockWorkspacesResponse))
}),
rest.get("/api/v2/workspaces/:workspaceId", async (req, res, ctx) => {
return res(ctx.status(200), ctx.json(M.MockWorkspace))
@@ -226,7 +226,7 @@ type WorkspacesEvent =
| { type: "UPDATE_FILTER"; query?: string }
export const workspacesMachine =
/** @xstate-layout N4IgpgJg5mDOIC5QHcD2AnA1rADgQwGM4BlAFz1LADoDUBXAO1KplNIEsGoBhepgYgioG1TgDdUmaqwDqGbPiKxejUgG0ADAF1EoHKljsOw3SAAeiAIyWNVAMwA2AJwAOACyWnAJjsuvGty8AGhAAT0QfWxcAVm9ohwcXAHYkp0sXFwBfTJC0LFxCEnJKGj5mVg4uFQEwdHQMKhwAGwoAMwwAWxYwUjl8xThq9W1TfUNjBlMLBDsnaKovaMtfDQ00jLckhxDwhEiqGO9-OxPZk69s3PkCpTIKalpVfgBVAAUAEQBBABUAUQB9ABiAEkADJ-ABKmh0SBAYyM7BMsOmbm8VA00Q0KRcli2di86TcOwiDioDk8DjcMS8Lm8dg0LgclxAeQUhVgdxKrJucCosHI6EqUFeeCgnAoiIY-GhowMCKRoGmAFocU57J4vG58VSMqliQglR4FmsvF5sX5XMloszuQMOcVqLb2d02JwoH02UpBMJRAwJFIXR6ebAZbD4RMpoglfF5gSGWt8ZYdZZ9ekXFQktEXI58dn3B4LjkWdc7ZzHSXnRU3UG7d6RFRxJJpD0a+y1JYYXo5RHkVHGZYqE43AEYgnnNE7PqaUl0dFTU4NA5Ui41m4bRXbg6qE6lC6ha2vbV6uhGi1SO10F1ZBu4KGu+NJZGDdFAmTacscTSnLn9RkFvS-CTKlNmia0ix3Ip7m3G9YCoOgcAgCUuAPMAITAVpYDrX1-WoeDEMoFC0Iwu84W7R9ewNelSQ0JNyQ0Al4hsE59XOKg3GHId0gcHwkgyMCrn6dky2gwTd2QPAjG+VAiPQOAAAsUMwsx+SgvBWkodAAApMVWABKfgIPtKDDO3CTSCkmT5MUkjw3IxUoznGdVksHw7FA1xZicFi1QcRccVpAleIcF911EyCuRgl4Ph+AFXk+ABxX4bLIhVzAc78DjsawHDc7wdW2MIo2WNVeNNTMaTNLLF1Cz1wrAKKvj+f4ADVfghYhgQAeQAOWSh9UumWYM2cWjVixdxJ0Kg1NXmXzEhcjF3Bo7IiwYVAIDgUxDOEx4mAbCAmjAWV+smCj-HTLK50xZxFg0WZgimxwSrcSkkheuY3GiJJCwE2qjJKXbyh6IUhmO+VTvshBuIORJKQJHx4esKcfOOfwEi-OxUhq4MdrKMGe0hpMYcZQIXMTAkXP1JVoZWNyGSTQkMX44swv+8tWb5AUhRFMUGAlVLbIGvtGSoSxYj8LNPretIqaTWwvG-JwcvYrxfJfH6Wb+4STKrZCYPxuy0oNWlYxiNyTi1fx0inUlYnJJwHY8dwJ3ibHSy3Ey8KQ90byI+AwxSiGjaVJJrCoJYGUCF9s3xFjUTJD7VdcdItjFt2hI9mDTMk6T0Nk2AFP1gOTqfJU3IHb7UmxSI3qxFi7AWKuFbSBImacdPN2Mov73B0uhwbmkXYt-EaJcKn5wWRXuN4r6XNAju6oNoWDQdgdB-NuxLdHqmsvTBXZm4lyMgpJkVqAA */
/** @xstate-layout N4IgpgJg5mDOIC5QHcD2AnA1rADgQwGM4BlAFz1LADpZz1SBLAOygAU8pmKHUmBiANoAGALqJQOVLAaNe4kAA9EAWgAcANnVUAzAEYATOoCcAdiFHt+obtUAaEAE9Euo6qo2LR0y-3bV+1QBfQPs0LFxCEnJKKhhSRhYAdQxsfCJYPgheamYAN1RMajjk8LS4YTEkEElpWSZ5JQRlAFYjABYdA1UjXVbmtu1teycENqN9KhNm5tVVbXU5nvHm4NCUiPSyCiKweOYoEtTIjKymHKZ8wtjdw43y3UqJKRkeeqrG5X02rT11XSEAiYBl4TMNEG1+lQhEJ1FZtF4hM0TPpdKsQGEjptojs9kl1mUMmB0OgMFQcAAbCgAMwwAFtrqRbgSKvIai85O8VM11EIdNMNEJtBCBkNHODoVQAtChCZ4eYbNo0Ri7rAtjEAK44CDcPGlSIAJTAVJO2SoeQK1E12soTINRtgLKqbLqDRU+n0RioRn6JhMqiRQjaQn96jBCBszSozX0zW0rSMxnUst0ipC6PxxzV1GQeBkABVUIaqeg4AALW3pPgKWjbKh4KmUdAACma0oAlHxlQSs1Qc-nC0aS7Byxn0o6nrVXq6mtzPULevDdEm2kHQWKEB6Jt045ZoUn-uo2krR1FtnwAKqsAAiAEE8wBRAD6ADV7-riABJADyADlx9VnhdTkmksXRJgTBY-GMYNvTDZRek9TRej9XQDFcP0VjTLtM2xC9rzvJ9WBvABxe9-2dKdgOUWUtGjL5Az8QY-TsdcEyjVCTBsIEvB49Rjz1LEz0vW8H0fAAxD8ABkH31cjAMo0APn6Dpvhlf4E3+GNmjgpdtCoMYYVUAZuQ0JMgjRJhUAgOB5GwwSYhreh9nYTgmG4DkJ3ZN5FJULwOiFMw-SsVRrEFMNvS9Hiouikx+MxU8YjiBIDhPeAnXkjzFF8gYdERfwEy8PwUTDQw9KRZoU2hcZNDafRYqw1KeytHUUoEsAizSzygJ8poAjcKxvmMNpZW5VoSosL0iu6UrLGROKVR7PtSALIshxHNrOoAydMqUmYo00ExTCM-pBhK8woRTWFWh5WYgyPBqNqzVkMu8rKmn+WqdGGmV-GDULRRGLQotUXRfVBsx2kRYJgiAA */
createMachine(
{
tsTypes: {} as import("./workspacesXService.typegen").Typegen1,
@@ -235,10 +235,7 @@ export const workspacesMachine =
events: {} as WorkspacesEvent,
services: {} as {
getWorkspaces: {
data: TypesGen.Workspace[]
}
getWorkspacesCount: {
data: { count: number }
data: TypesGen.WorkspacesResponse
}
updateWorkspaceRefs: {
data: {
@@ -254,98 +251,64 @@ export const workspacesMachine =
UPDATE_VERSION: {
actions: "triggerUpdateVersion",
},
UPDATE_PAGE: {
target: "gettingWorkspaces",
actions: "updateURL",
},
UPDATE_FILTER: {
actions: ["assignFilter", "sendResetPage"],
},
},
type: "parallel",
initial: "startingPagination",
states: {
count: {
initial: "gettingCount",
states: {
idle: {},
gettingCount: {
entry: "clearGetCountError",
invoke: {
src: "getWorkspacesCount",
id: "getWorkspacesCount",
onDone: [
{
target: "idle",
actions: "assignCount",
},
],
onError: [
{
target: "idle",
actions: "assignGetCountError",
},
],
},
},
},
on: {
UPDATE_FILTER: {
target: ".gettingCount",
actions: ["assignFilter", "sendResetPage"],
},
startingPagination: {
entry: "assignPaginationRef",
always: {
target: "gettingWorkspaces",
},
},
workspaces: {
initial: "startingPagination",
states: {
startingPagination: {
entry: "assignPaginationRef",
always: {
target: "gettingWorkspaces",
gettingWorkspaces: {
entry: "clearGetWorkspacesError",
invoke: {
src: "getWorkspaces",
id: "getWorkspaces",
onDone: [
{
target: "waitToRefreshWorkspaces",
cond: "isEmpty",
actions: ["assignWorkspaceRefs", "assignCount"],
},
},
gettingWorkspaces: {
entry: "clearGetWorkspacesError",
invoke: {
src: "getWorkspaces",
id: "getWorkspaces",
onDone: [
{
target: "waitToRefreshWorkspaces",
cond: "isEmpty",
actions: "assignWorkspaceRefs",
},
{
target: "updatingWorkspaceRefs",
},
],
onError: [
{
target: "waitToRefreshWorkspaces",
actions: "assignGetWorkspacesError",
},
],
{
target: "updatingWorkspaceRefs",
actions: "assignCount",
},
},
updatingWorkspaceRefs: {
invoke: {
src: "updateWorkspaceRefs",
id: "updateWorkspaceRefs",
onDone: [
{
target: "waitToRefreshWorkspaces",
actions: "assignUpdatedWorkspaceRefs",
},
],
],
onError: [
{
target: "waitToRefreshWorkspaces",
actions: "assignGetWorkspacesError",
},
},
waitToRefreshWorkspaces: {
after: {
"5000": {
target: "#workspacesState.workspaces.gettingWorkspaces",
actions: [],
internal: false,
},
},
},
],
},
on: {
UPDATE_PAGE: {
target: ".gettingWorkspaces",
actions: "updateURL",
},
updatingWorkspaceRefs: {
invoke: {
src: "updateWorkspaceRefs",
id: "updateWorkspaceRefs",
onDone: [
{
target: "waitToRefreshWorkspaces",
actions: "assignUpdatedWorkspaceRefs",
},
],
},
},
waitToRefreshWorkspaces: {
after: {
"5000": {
target: "gettingWorkspaces",
actions: [],
internal: false,
},
},
},
@@ -358,10 +321,13 @@ export const workspacesMachine =
actions: {
assignWorkspaceRefs: assign({
workspaceRefs: (_, event) =>
event.data.map((data) => {
event.data.workspaces.map((data) => {
return spawn(workspaceItemMachine.withContext({ data }), data.id)
}),
}),
assignCount: assign({
count: (_, event) => event.data.count,
}),
assignPaginationRef: assign({
paginationRef: (context) =>
spawn(
@@ -403,15 +369,6 @@ export const workspacesMachine =
return event.data.refsToKeep.concat(newWorkspaceRefs)
},
}),
assignCount: assign({
count: (_, event) => event.data.count,
}),
assignGetCountError: assign({
getCountError: (_, event) => event.data,
}),
clearGetCountError: assign({
getCountError: (_) => undefined,
}),
},
services: {
getWorkspaces: (context) => {
@@ -429,7 +386,7 @@ export const workspacesMachine =
updateWorkspaceRefs: (context, event) => {
const refsToKeep: WorkspaceItemMachineRef[] = []
context.workspaceRefs?.forEach((ref) => {
const matchingWorkspace = event.data.find(
const matchingWorkspace = event.data.workspaces.find(
(workspace) => ref.id === workspace.id,
)
if (matchingWorkspace) {
@@ -443,7 +400,7 @@ export const workspacesMachine =
}
})
const newWorkspaces = event.data.filter(
const newWorkspaces = event.data.workspaces.filter(
(workspace) =>
!context.workspaceRefs?.find((ref) => ref.id === workspace.id),
)
@@ -453,8 +410,6 @@ export const workspacesMachine =
newWorkspaces,
})
},
getWorkspacesCount: (context) =>
API.getWorkspacesCount({ q: context.filter }),
},
},
)