Skip to content

Commit 5715d38

Browse files
committed
Start adding pagination - type error
1 parent e005aaf commit 5715d38

File tree

4 files changed

+72
-17
lines changed

4 files changed

+72
-17
lines changed

site/src/api/api.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ export const getApiKey = async (): Promise<TypesGen.GenerateAPIKeyResponse> => {
132132
}
133133

134134
export const getUsers = async (
135-
filter?: TypesGen.UsersRequest,
135+
options: TypesGen.UsersRequest,
136136
): Promise<TypesGen.User[]> => {
137-
const url = getURLWithSearchParams("/api/v2/users", filter)
138-
const response = await axios.get<TypesGen.User[]>(url)
137+
const url = buildURL("/api/v2/users", options)
138+
const response = await axios.get<TypesGen.User[]>(url.toString())
139139
return response.data
140140
}
141141

@@ -264,6 +264,21 @@ export const watchWorkspace = (workspaceId: string): EventSource => {
264264
)
265265
}
266266

267+
interface SearchParamOptions extends TypesGen.Pagination {
268+
q?: string
269+
filter?: string
270+
}
271+
272+
const buildURL = (basePath: string, options: SearchParamOptions) => {
273+
const url = new URL(basePath)
274+
const keys = Object.keys(options) as (keyof SearchParamOptions)[]
275+
keys.forEach((key) => {
276+
const value = options[key] ?? ""
277+
url.searchParams.append(key, value.toString())
278+
})
279+
return url
280+
}
281+
267282
export const getURLWithSearchParams = (
268283
basePath: string,
269284
filter?: TypesGen.WorkspaceFilter | TypesGen.UsersRequest,

site/src/pages/UsersPage/UsersPage.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useActor, useMachine } from "@xstate/react"
22
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"
3+
import { getPaginationContext } from "components/PaginationWidget/utils"
34
import { usePermissions } from "hooks/usePermissions"
45
import { FC, ReactNode, useContext, useEffect } from "react"
56
import { Helmet } from "react-helmet-async"
@@ -25,11 +26,16 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
2526
const xServices = useContext(XServiceContext)
2627
const navigate = useNavigate()
2728
const [searchParams, setSearchParams] = useSearchParams()
28-
const filter = searchParams.get("filter") ?? undefined
29+
const filter = searchParams.get("filter") ?? ""
2930
const [usersState, usersSend] = useMachine(usersMachine, {
3031
context: {
3132
filter,
33+
paginationContext: getPaginationContext(searchParams),
3234
},
35+
actions: {
36+
updateURL: (context, event) =>
37+
setSearchParams({ page: event.page, filter: context.filter }),
38+
}
3339
})
3440
const {
3541
users,
@@ -39,6 +45,7 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
3945
userIdToActivate,
4046
userIdToResetPassword,
4147
newUserPassword,
48+
paginationRef
4249
} = usersState.context
4350

4451
const userToBeSuspended = users?.find((u) => u.id === userIdToSuspend)
@@ -56,14 +63,6 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
5663
usersState.matches("gettingUsers") ||
5764
(canEditUsers && rolesState.matches("gettingRoles"))
5865

59-
// Fetch users on component mount
60-
useEffect(() => {
61-
usersSend({
62-
type: "GET_USERS",
63-
query: filter,
64-
})
65-
}, [filter, usersSend])
66-
6766
// Fetch roles on component mount
6867
useEffect(() => {
6968
// Only fetch the roles if the user has permission for it
@@ -113,9 +112,9 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
113112
canEditUsers={canEditUsers}
114113
filter={usersState.context.filter}
115114
onFilter={(query) => {
116-
searchParams.set("filter", query)
117-
setSearchParams(searchParams)
115+
usersSend({ type: "FILTER", query })
118116
}}
117+
paginationRef={paginationRef}
119118
/>
120119

121120
{userToBeDeleted && (

site/src/pages/UsersPage/UsersPageView.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { PaginationWidget } from "components/PaginationWidget/PaginationWidget"
12
import { FC } from "react"
3+
import { PaginationMachineRef } from "xServices/pagination/paginationXService"
24
import * as TypesGen from "../../api/typesGenerated"
35
import { SearchBarWithFilter } from "../../components/SearchBarWithFilter/SearchBarWithFilter"
46
import { UsersTable } from "../../components/UsersTable/UsersTable"
@@ -26,6 +28,7 @@ export interface UsersPageViewProps {
2628
roles: TypesGen.Role["name"][],
2729
) => void
2830
onFilter: (query: string) => void
31+
paginationRef: PaginationMachineRef
2932
}
3033

3134
export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
@@ -43,6 +46,7 @@ export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
4346
isLoading,
4447
filter,
4548
onFilter,
49+
paginationRef
4650
}) => {
4751
const presetFilters = [
4852
{ query: userFilterQuery.active, name: Language.activeUsersFilterName },
@@ -71,6 +75,8 @@ export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
7175
canEditUsers={canEditUsers}
7276
isLoading={isLoading}
7377
/>
78+
79+
<PaginationWidget paginationRef={paginationRef} />
7480
</>
7581
)
7682
}

site/src/xServices/users/usersXService.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { assign, createMachine } from "xstate"
1+
import { getPaginationData } from "components/PaginationWidget/utils"
2+
import { PaginationContext, paginationMachine, PaginationMachineRef } from "xServices/pagination/paginationXService"
3+
import { assign, createMachine, send, spawn } from "xstate"
24
import * as API from "../../api/api"
35
import { getErrorMessage } from "../../api/errors"
46
import * as TypesGen from "../../api/typesGenerated"
@@ -9,6 +11,8 @@ import {
911
import { queryToFilter } from "../../util/filters"
1012
import { generateRandomString } from "../../util/random"
1113

14+
const usersPaginationId = "usersPagination"
15+
1216
export const Language = {
1317
getUsersError: "Error getting users.",
1418
suspendUserSuccess: "Successfully suspended the user.",
@@ -44,6 +48,8 @@ export interface UsersContext {
4448
// Update user roles
4549
userIdToUpdateRoles?: TypesGen.User["id"]
4650
updateUserRolesError?: Error | unknown
51+
paginationContext: PaginationContext
52+
paginationRef: PaginationMachineRef
4753
}
4854

4955
export type UsersEvent =
@@ -70,6 +76,10 @@ export type UsersEvent =
7076
userId: TypesGen.User["id"]
7177
roles: TypesGen.Role["name"][]
7278
}
79+
// Filter
80+
| { type: "FILTER"; query: string }
81+
// Pagination
82+
| { type: "UPDATE_PAGE"; page: string }
7383

7484
export const usersMachine = createMachine(
7585
{
@@ -103,8 +113,12 @@ export const usersMachine = createMachine(
103113
}
104114
},
105115
},
106-
initial: "gettingUsers",
116+
initial: "startingPagination",
107117
states: {
118+
startingPagination: {
119+
entry: "assignPaginationRef",
120+
always: "gettingUsers"
121+
},
108122
gettingUsers: {
109123
entry: "clearGetUsersError",
110124
invoke: {
@@ -155,6 +169,13 @@ export const usersMachine = createMachine(
155169
target: "updatingUserRoles",
156170
actions: ["assignUserIdToUpdateRoles"],
157171
},
172+
UPDATE_PAGE: {
173+
target: "gettingUsers",
174+
actions: "updateURL"
175+
},
176+
FILTER: {
177+
actions: ["assignFilter", "sendResetPage"]
178+
}
158179
},
159180
},
160181
confirmUserSuspension: {
@@ -282,7 +303,10 @@ export const usersMachine = createMachine(
282303
// Passing API.getUsers directly does not invoke the function properly
283304
// when it is mocked. This happen in the UsersPage tests inside of the
284305
// "shows a success message and refresh the page" test case.
285-
getUsers: (context) => API.getUsers(queryToFilter(context.filter)),
306+
getUsers: (context) => {
307+
const { offset, limit } = getPaginationData(context.paginationRef)
308+
return API.getUsers({ ...queryToFilter(context.filter), offset, limit })
309+
},
286310
suspendUser: (context) => {
287311
if (!context.userIdToSuspend) {
288312
throw new Error("userIdToSuspend is undefined")
@@ -457,6 +481,17 @@ export const usersMachine = createMachine(
457481
})
458482
},
459483
}),
484+
assignPaginationRef: assign({
485+
paginationRef: (context) =>
486+
spawn(
487+
paginationMachine.withContext(context.paginationContext),
488+
usersPaginationId,
489+
),
490+
}),
491+
sendResetPage: send(
492+
{ type: "RESET_PAGE" },
493+
{ to: usersPaginationId },
494+
),
460495
},
461496
},
462497
)

0 commit comments

Comments
 (0)