mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: paginating Users page (#4792)
* Extract PageButton * Fix import * Extract utils * Format * Separate pagination - wip * Spawn pagination machine - buggy filter * Make labels optional * Layout, fix send reset bug * Format * Fix refresh data bug * Remove debugging line * Fix url updates setSearchParams overwrites all search params, rather than merging * Update Audit Page * Simplify pagination widget * Fix workspaces story * Fix Audit story * Fix pagination story and pagebutton highlight * Fix pagination tests * Add to utils tests * Format * Add tests * Start adding pagination - type error * Tweak machine * Refactor paginated api calls * Show pagination when count is undefined * fix stories * Fix api helper * Add test * Format * Make widget show all the time to avoid blink
This commit is contained in:
+29
-52
@@ -132,10 +132,10 @@ export const getApiKey = async (): Promise<TypesGen.GenerateAPIKeyResponse> => {
|
||||
}
|
||||
|
||||
export const getUsers = async (
|
||||
filter?: TypesGen.UsersRequest,
|
||||
options: TypesGen.UsersRequest,
|
||||
): Promise<TypesGen.User[]> => {
|
||||
const url = getURLWithSearchParams("/api/v2/users", filter)
|
||||
const response = await axios.get<TypesGen.User[]>(url)
|
||||
const url = getURLWithSearchParams("/api/v2/users", options)
|
||||
const response = await axios.get<TypesGen.User[]>(url.toString())
|
||||
return response.data
|
||||
}
|
||||
|
||||
@@ -264,51 +264,43 @@ export const watchWorkspace = (workspaceId: string): EventSource => {
|
||||
)
|
||||
}
|
||||
|
||||
interface SearchParamOptions extends TypesGen.Pagination {
|
||||
q?: string
|
||||
}
|
||||
|
||||
export const getURLWithSearchParams = (
|
||||
basePath: string,
|
||||
filter?: TypesGen.WorkspaceFilter | TypesGen.UsersRequest,
|
||||
options?: SearchParamOptions,
|
||||
): string => {
|
||||
const searchParams = new URLSearchParams()
|
||||
|
||||
if (filter?.q && filter.q !== "") {
|
||||
searchParams.append("q", filter.q)
|
||||
if (options) {
|
||||
const searchParams = new URLSearchParams()
|
||||
const keys = Object.keys(options) as (keyof SearchParamOptions)[]
|
||||
keys.forEach((key) => {
|
||||
const value = options[key]
|
||||
if (value !== undefined && value !== "") {
|
||||
searchParams.append(key, value.toString())
|
||||
}
|
||||
})
|
||||
const searchString = searchParams.toString()
|
||||
return searchString ? `${basePath}?${searchString}` : basePath
|
||||
} else {
|
||||
return basePath
|
||||
}
|
||||
|
||||
const searchString = searchParams.toString()
|
||||
|
||||
return searchString ? `${basePath}?${searchString}` : basePath
|
||||
}
|
||||
|
||||
export const getWorkspaces = async (
|
||||
options: TypesGen.WorkspacesRequest,
|
||||
): Promise<TypesGen.Workspace[]> => {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (options.limit) {
|
||||
searchParams.set("limit", options.limit.toString())
|
||||
}
|
||||
if (options.offset) {
|
||||
searchParams.set("offset", options.offset.toString())
|
||||
}
|
||||
if (options.q) {
|
||||
searchParams.set("q", options.q)
|
||||
}
|
||||
|
||||
const response = await axios.get<TypesGen.Workspace[]>(
|
||||
`/api/v2/workspaces?${searchParams.toString()}`,
|
||||
)
|
||||
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 searchParams = new URLSearchParams()
|
||||
if (options.q) {
|
||||
searchParams.set("q", options.q)
|
||||
}
|
||||
const response = await axios.get(
|
||||
`/api/v2/workspaces/count?${searchParams.toString()}`,
|
||||
)
|
||||
const url = getURLWithSearchParams("/api/v2/workspaces/count", options)
|
||||
const response = await axios.get(url)
|
||||
return response.data
|
||||
}
|
||||
|
||||
@@ -555,31 +547,16 @@ export const getEntitlements = async (): Promise<TypesGen.Entitlements> => {
|
||||
export const getAuditLogs = async (
|
||||
options: TypesGen.AuditLogsRequest,
|
||||
): Promise<TypesGen.AuditLogResponse> => {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (options.limit) {
|
||||
searchParams.set("limit", options.limit.toString())
|
||||
}
|
||||
if (options.offset) {
|
||||
searchParams.set("offset", options.offset.toString())
|
||||
}
|
||||
if (options.q) {
|
||||
searchParams.set("q", options.q)
|
||||
}
|
||||
|
||||
const response = await axios.get(`/api/v2/audit?${searchParams.toString()}`)
|
||||
const url = getURLWithSearchParams("/api/v2/audit", options)
|
||||
const response = await axios.get(url)
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const getAuditLogsCount = async (
|
||||
options: TypesGen.AuditLogCountRequest = {},
|
||||
): Promise<TypesGen.AuditLogCountResponse> => {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (options.q) {
|
||||
searchParams.set("q", options.q)
|
||||
}
|
||||
const response = await axios.get(
|
||||
`/api/v2/audit/count?${searchParams.toString()}`,
|
||||
)
|
||||
const url = getURLWithSearchParams("/api/v2/audit/count", options)
|
||||
const response = await axios.get(url)
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
||||
@@ -34,15 +34,12 @@ export const PaginationWidget = ({
|
||||
const currentPage = paginationState.context.page
|
||||
const numRecordsPerPage = paginationState.context.limit
|
||||
|
||||
const numPages = numRecords ? Math.ceil(numRecords / numRecordsPerPage) : 0
|
||||
const numPages = numRecords
|
||||
? Math.ceil(numRecords / numRecordsPerPage)
|
||||
: undefined
|
||||
const firstPageActive = currentPage === 1 && numPages !== 0
|
||||
const lastPageActive = currentPage === numPages && numPages !== 0
|
||||
|
||||
// No need to display any pagination if we know the number of pages is 1 or 0
|
||||
if (numPages <= 1 || numRecords === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={containerStyle} className={styles.defaultContainerStyles}>
|
||||
<Button
|
||||
@@ -54,7 +51,7 @@ export const PaginationWidget = ({
|
||||
<KeyboardArrowLeft />
|
||||
<div>{prevLabel}</div>
|
||||
</Button>
|
||||
<Maybe condition={numPages > 0}>
|
||||
<Maybe condition={numPages !== undefined}>
|
||||
<ChooseOne>
|
||||
<Cond condition={isMobile}>
|
||||
<PageButton
|
||||
@@ -64,24 +61,25 @@ export const PaginationWidget = ({
|
||||
/>
|
||||
</Cond>
|
||||
<Cond>
|
||||
{buildPagedList(numPages, currentPage).map((page) =>
|
||||
typeof page !== "number" ? (
|
||||
<PageButton
|
||||
key={`Page${page}`}
|
||||
activePage={currentPage}
|
||||
placeholder="..."
|
||||
disabled
|
||||
/>
|
||||
) : (
|
||||
<PageButton
|
||||
key={`Page${page}`}
|
||||
activePage={currentPage}
|
||||
page={page}
|
||||
numPages={numPages}
|
||||
onPageClick={() => send({ type: "GO_TO_PAGE", page })}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
{numPages &&
|
||||
buildPagedList(numPages, currentPage).map((page) =>
|
||||
typeof page !== "number" ? (
|
||||
<PageButton
|
||||
key={`Page${page}`}
|
||||
activePage={currentPage}
|
||||
placeholder="..."
|
||||
disabled
|
||||
/>
|
||||
) : (
|
||||
<PageButton
|
||||
key={`Page${page}`}
|
||||
activePage={currentPage}
|
||||
page={page}
|
||||
numPages={numPages}
|
||||
onPageClick={() => send({ type: "GO_TO_PAGE", page })}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</Cond>
|
||||
</ChooseOne>
|
||||
</Maybe>
|
||||
|
||||
@@ -238,6 +238,32 @@ describe("UsersPage", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("pagination", () => {
|
||||
it("goes to next and previous page", async () => {
|
||||
renderPage()
|
||||
const user = userEvent.setup()
|
||||
|
||||
const mock = jest
|
||||
.spyOn(API, "getUsers")
|
||||
.mockResolvedValueOnce([MockUser, MockUser2])
|
||||
|
||||
const nextButton = await screen.findByLabelText("Next page")
|
||||
await user.click(nextButton)
|
||||
|
||||
await waitFor(() =>
|
||||
expect(API.getUsers).toBeCalledWith({ offset: 25, limit: 25, q: "" }),
|
||||
)
|
||||
|
||||
mock.mockClear()
|
||||
const previousButton = await screen.findByLabelText("Previous page")
|
||||
await user.click(previousButton)
|
||||
|
||||
await waitFor(() =>
|
||||
expect(API.getUsers).toBeCalledWith({ offset: 0, limit: 25, q: "" }),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("delete user", () => {
|
||||
describe("when it is success", () => {
|
||||
it("shows a success message and refresh the page", async () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useActor, useMachine } from "@xstate/react"
|
||||
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"
|
||||
import { getPaginationContext } from "components/PaginationWidget/utils"
|
||||
import { usePermissions } from "hooks/usePermissions"
|
||||
import { FC, ReactNode, useContext, useEffect } from "react"
|
||||
import { Helmet } from "react-helmet-async"
|
||||
@@ -25,10 +26,15 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
|
||||
const xServices = useContext(XServiceContext)
|
||||
const navigate = useNavigate()
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
const filter = searchParams.get("filter") ?? undefined
|
||||
const filter = searchParams.get("filter") ?? ""
|
||||
const [usersState, usersSend] = useMachine(usersMachine, {
|
||||
context: {
|
||||
filter,
|
||||
paginationContext: getPaginationContext(searchParams),
|
||||
},
|
||||
actions: {
|
||||
updateURL: (context, event) =>
|
||||
setSearchParams({ page: event.page, filter: context.filter }),
|
||||
},
|
||||
})
|
||||
const {
|
||||
@@ -39,6 +45,7 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
|
||||
userIdToActivate,
|
||||
userIdToResetPassword,
|
||||
newUserPassword,
|
||||
paginationRef,
|
||||
} = usersState.context
|
||||
|
||||
const userToBeSuspended = users?.find((u) => u.id === userIdToSuspend)
|
||||
@@ -56,14 +63,6 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
|
||||
usersState.matches("gettingUsers") ||
|
||||
(canEditUsers && rolesState.matches("gettingRoles"))
|
||||
|
||||
// Fetch users on component mount
|
||||
useEffect(() => {
|
||||
usersSend({
|
||||
type: "GET_USERS",
|
||||
query: filter,
|
||||
})
|
||||
}, [filter, usersSend])
|
||||
|
||||
// Fetch roles on component mount
|
||||
useEffect(() => {
|
||||
// Only fetch the roles if the user has permission for it
|
||||
@@ -113,9 +112,9 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => {
|
||||
canEditUsers={canEditUsers}
|
||||
filter={usersState.context.filter}
|
||||
onFilter={(query) => {
|
||||
searchParams.set("filter", query)
|
||||
setSearchParams(searchParams)
|
||||
usersSend({ type: "UPDATE_FILTER", query })
|
||||
}}
|
||||
paginationRef={paginationRef}
|
||||
/>
|
||||
|
||||
{userToBeDeleted && (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ComponentMeta, Story } from "@storybook/react"
|
||||
import { createPaginationRef } from "components/PaginationWidget/utils"
|
||||
import {
|
||||
MockSiteRoles,
|
||||
MockAssignableSiteRoles,
|
||||
MockUser,
|
||||
MockUser2,
|
||||
} from "../../testHelpers/renderHelpers"
|
||||
@@ -9,6 +10,11 @@ import { UsersPageView, UsersPageViewProps } from "./UsersPageView"
|
||||
export default {
|
||||
title: "pages/UsersPageView",
|
||||
component: UsersPageView,
|
||||
argTypes: {
|
||||
paginationRef: {
|
||||
defaultValue: createPaginationRef({ page: 1, limit: 25 }),
|
||||
},
|
||||
},
|
||||
} as ComponentMeta<typeof UsersPageView>
|
||||
|
||||
const Template: Story<UsersPageViewProps> = (args) => (
|
||||
@@ -18,8 +24,7 @@ const Template: Story<UsersPageViewProps> = (args) => (
|
||||
export const Admin = Template.bind({})
|
||||
Admin.args = {
|
||||
users: [MockUser, MockUser2],
|
||||
roles: MockSiteRoles,
|
||||
canCreateUser: true,
|
||||
roles: MockAssignableSiteRoles,
|
||||
canEditUsers: true,
|
||||
}
|
||||
|
||||
@@ -32,7 +37,7 @@ SmallViewport.parameters = {
|
||||
}
|
||||
|
||||
export const Member = Template.bind({})
|
||||
Member.args = { ...Admin.args, canCreateUser: false, canEditUsers: false }
|
||||
Member.args = { ...Admin.args, canEditUsers: false }
|
||||
|
||||
export const Empty = Template.bind({})
|
||||
Empty.args = { ...Admin.args, users: [] }
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { PaginationWidget } from "components/PaginationWidget/PaginationWidget"
|
||||
import { FC } from "react"
|
||||
import { PaginationMachineRef } from "xServices/pagination/paginationXService"
|
||||
import * as TypesGen from "../../api/typesGenerated"
|
||||
import { SearchBarWithFilter } from "../../components/SearchBarWithFilter/SearchBarWithFilter"
|
||||
import { UsersTable } from "../../components/UsersTable/UsersTable"
|
||||
@@ -26,6 +28,7 @@ export interface UsersPageViewProps {
|
||||
roles: TypesGen.Role["name"][],
|
||||
) => void
|
||||
onFilter: (query: string) => void
|
||||
paginationRef: PaginationMachineRef
|
||||
}
|
||||
|
||||
export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
|
||||
@@ -43,6 +46,7 @@ export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
|
||||
isLoading,
|
||||
filter,
|
||||
onFilter,
|
||||
paginationRef,
|
||||
}) => {
|
||||
const presetFilters = [
|
||||
{ query: userFilterQuery.active, name: Language.activeUsersFilterName },
|
||||
@@ -71,6 +75,8 @@ export const UsersPageView: FC<React.PropsWithChildren<UsersPageViewProps>> = ({
|
||||
canEditUsers={canEditUsers}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
|
||||
<PaginationWidget paginationRef={paginationRef} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,8 +48,6 @@ export const MockAuditorRole: TypesGen.Role = {
|
||||
display_name: "Auditor",
|
||||
}
|
||||
|
||||
export const MockSiteRoles = [MockUserAdminRole, MockAuditorRole]
|
||||
|
||||
// assignableRole takes a role and a boolean. The boolean implies if the
|
||||
// actor can assign (add/remove) the role from other users.
|
||||
export function assignableRole(
|
||||
@@ -62,6 +60,12 @@ export function assignableRole(
|
||||
}
|
||||
}
|
||||
|
||||
export const MockSiteRoles = [MockUserAdminRole, MockAuditorRole]
|
||||
export const MockAssignableSiteRoles = [
|
||||
assignableRole(MockUserAdminRole, true),
|
||||
assignableRole(MockAuditorRole, true),
|
||||
]
|
||||
|
||||
export const MockMemberPermissions = {
|
||||
viewAuditLog: false,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { assign, createMachine } from "xstate"
|
||||
import { getPaginationData } from "components/PaginationWidget/utils"
|
||||
import {
|
||||
PaginationContext,
|
||||
paginationMachine,
|
||||
PaginationMachineRef,
|
||||
} from "xServices/pagination/paginationXService"
|
||||
import { assign, createMachine, send, spawn } from "xstate"
|
||||
import * as API from "../../api/api"
|
||||
import { getErrorMessage } from "../../api/errors"
|
||||
import * as TypesGen from "../../api/typesGenerated"
|
||||
@@ -9,6 +15,8 @@ import {
|
||||
import { queryToFilter } from "../../util/filters"
|
||||
import { generateRandomString } from "../../util/random"
|
||||
|
||||
const usersPaginationId = "usersPagination"
|
||||
|
||||
export const Language = {
|
||||
getUsersError: "Error getting users.",
|
||||
suspendUserSuccess: "Successfully suspended the user.",
|
||||
@@ -26,7 +34,7 @@ export const Language = {
|
||||
export interface UsersContext {
|
||||
// Get users
|
||||
users?: TypesGen.User[]
|
||||
filter?: string
|
||||
filter: string
|
||||
getUsersError?: Error | unknown
|
||||
// Suspend user
|
||||
userIdToSuspend?: TypesGen.User["id"]
|
||||
@@ -44,6 +52,8 @@ export interface UsersContext {
|
||||
// Update user roles
|
||||
userIdToUpdateRoles?: TypesGen.User["id"]
|
||||
updateUserRolesError?: Error | unknown
|
||||
paginationContext: PaginationContext
|
||||
paginationRef: PaginationMachineRef
|
||||
}
|
||||
|
||||
export type UsersEvent =
|
||||
@@ -70,393 +80,455 @@ export type UsersEvent =
|
||||
userId: TypesGen.User["id"]
|
||||
roles: TypesGen.Role["name"][]
|
||||
}
|
||||
// Filter
|
||||
| { type: "UPDATE_FILTER"; query: string }
|
||||
// Pagination
|
||||
| { type: "UPDATE_PAGE"; page: string }
|
||||
|
||||
export const usersMachine = createMachine(
|
||||
{
|
||||
id: "usersState",
|
||||
predictableActionArguments: true,
|
||||
tsTypes: {} as import("./usersXService.typegen").Typegen0,
|
||||
schema: {
|
||||
context: {} as UsersContext,
|
||||
events: {} as UsersEvent,
|
||||
services: {} as {
|
||||
getUsers: {
|
||||
data: TypesGen.User[]
|
||||
}
|
||||
createUser: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
suspendUser: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
deleteUser: {
|
||||
data: undefined
|
||||
}
|
||||
activateUser: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
updateUserPassword: {
|
||||
data: undefined
|
||||
}
|
||||
updateUserRoles: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
},
|
||||
},
|
||||
initial: "gettingUsers",
|
||||
states: {
|
||||
gettingUsers: {
|
||||
entry: "clearGetUsersError",
|
||||
invoke: {
|
||||
src: "getUsers",
|
||||
id: "getUsers",
|
||||
onDone: [
|
||||
{
|
||||
target: "#usersState.idle",
|
||||
actions: "assignUsers",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: [
|
||||
"clearUsers",
|
||||
"assignGetUsersError",
|
||||
"displayGetUsersErrorMessage",
|
||||
],
|
||||
target: "#usersState.error",
|
||||
},
|
||||
],
|
||||
},
|
||||
tags: "loading",
|
||||
},
|
||||
idle: {
|
||||
on: {
|
||||
GET_USERS: {
|
||||
actions: "assignFilter",
|
||||
target: "gettingUsers",
|
||||
},
|
||||
SUSPEND_USER: {
|
||||
target: "confirmUserSuspension",
|
||||
actions: ["assignUserIdToSuspend"],
|
||||
},
|
||||
DELETE_USER: {
|
||||
target: "confirmUserDeletion",
|
||||
actions: ["assignUserIdToDelete"],
|
||||
},
|
||||
ACTIVATE_USER: {
|
||||
target: "confirmUserActivation",
|
||||
actions: ["assignUserIdToActivate"],
|
||||
},
|
||||
RESET_USER_PASSWORD: {
|
||||
target: "confirmUserPasswordReset",
|
||||
actions: ["assignUserIdToResetPassword", "generateRandomPassword"],
|
||||
},
|
||||
UPDATE_USER_ROLES: {
|
||||
target: "updatingUserRoles",
|
||||
actions: ["assignUserIdToUpdateRoles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
confirmUserSuspension: {
|
||||
on: {
|
||||
CONFIRM_USER_SUSPENSION: "suspendingUser",
|
||||
CANCEL_USER_SUSPENSION: "idle",
|
||||
},
|
||||
},
|
||||
confirmUserDeletion: {
|
||||
on: {
|
||||
CONFIRM_USER_DELETE: "deletingUser",
|
||||
CANCEL_USER_DELETE: "idle",
|
||||
},
|
||||
},
|
||||
confirmUserActivation: {
|
||||
on: {
|
||||
CONFIRM_USER_ACTIVATION: "activatingUser",
|
||||
CANCEL_USER_ACTIVATION: "idle",
|
||||
},
|
||||
},
|
||||
suspendingUser: {
|
||||
entry: "clearSuspendUserError",
|
||||
invoke: {
|
||||
src: "suspendUser",
|
||||
id: "suspendUser",
|
||||
onDone: {
|
||||
// Update users list
|
||||
target: "gettingUsers",
|
||||
actions: ["displaySuspendSuccess"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: ["assignSuspendUserError", "displaySuspendedErrorMessage"],
|
||||
},
|
||||
},
|
||||
},
|
||||
deletingUser: {
|
||||
entry: "clearDeleteUserError",
|
||||
invoke: {
|
||||
src: "deleteUser",
|
||||
id: "deleteUser",
|
||||
onDone: {
|
||||
target: "gettingUsers",
|
||||
actions: ["displayDeleteSuccess"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: ["assignDeleteUserError", "displayDeleteErrorMessage"],
|
||||
},
|
||||
},
|
||||
},
|
||||
activatingUser: {
|
||||
entry: "clearActivateUserError",
|
||||
invoke: {
|
||||
src: "activateUser",
|
||||
id: "activateUser",
|
||||
onDone: {
|
||||
// Update users list
|
||||
target: "gettingUsers",
|
||||
actions: ["displayActivateSuccess"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignActivateUserError",
|
||||
"displayActivatedErrorMessage",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
confirmUserPasswordReset: {
|
||||
on: {
|
||||
CONFIRM_USER_PASSWORD_RESET: "resettingUserPassword",
|
||||
CANCEL_USER_PASSWORD_RESET: "idle",
|
||||
},
|
||||
},
|
||||
resettingUserPassword: {
|
||||
entry: "clearResetUserPasswordError",
|
||||
invoke: {
|
||||
src: "resetUserPassword",
|
||||
id: "resetUserPassword",
|
||||
onDone: {
|
||||
target: "idle",
|
||||
actions: ["displayResetPasswordSuccess"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignResetUserPasswordError",
|
||||
"displayResetPasswordErrorMessage",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
updatingUserRoles: {
|
||||
entry: "clearUpdateUserRolesError",
|
||||
invoke: {
|
||||
src: "updateUserRoles",
|
||||
id: "updateUserRoles",
|
||||
onDone: {
|
||||
target: "idle",
|
||||
actions: ["updateUserRolesInTheList"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignUpdateRolesError",
|
||||
"displayUpdateRolesErrorMessage",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
error: {
|
||||
on: {
|
||||
GET_USERS: {
|
||||
actions: "assignFilter",
|
||||
target: "gettingUsers",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
services: {
|
||||
// Passing API.getUsers directly does not invoke the function properly
|
||||
// when it is mocked. This happen in the UsersPage tests inside of the
|
||||
// "shows a success message and refresh the page" test case.
|
||||
getUsers: (context) => API.getUsers(queryToFilter(context.filter)),
|
||||
suspendUser: (context) => {
|
||||
if (!context.userIdToSuspend) {
|
||||
throw new Error("userIdToSuspend is undefined")
|
||||
}
|
||||
|
||||
return API.suspendUser(context.userIdToSuspend)
|
||||
},
|
||||
deleteUser: (context) => {
|
||||
if (!context.userIdToDelete) {
|
||||
throw new Error("userIdToDelete is undefined")
|
||||
}
|
||||
return API.deleteUser(context.userIdToDelete)
|
||||
},
|
||||
activateUser: (context) => {
|
||||
if (!context.userIdToActivate) {
|
||||
throw new Error("userIdToActivate is undefined")
|
||||
}
|
||||
|
||||
return API.activateUser(context.userIdToActivate)
|
||||
},
|
||||
resetUserPassword: (context) => {
|
||||
if (!context.userIdToResetPassword) {
|
||||
throw new Error("userIdToResetPassword is undefined")
|
||||
}
|
||||
|
||||
if (!context.newUserPassword) {
|
||||
throw new Error("newUserPassword not generated")
|
||||
}
|
||||
|
||||
return API.updateUserPassword(context.userIdToResetPassword, {
|
||||
password: context.newUserPassword,
|
||||
old_password: "",
|
||||
})
|
||||
},
|
||||
updateUserRoles: (context, event) => {
|
||||
if (!context.userIdToUpdateRoles) {
|
||||
throw new Error("userIdToUpdateRoles is undefined")
|
||||
}
|
||||
|
||||
return API.updateUserRoles(event.roles, context.userIdToUpdateRoles)
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
assignUsers: assign({
|
||||
users: (_, event) => event.data,
|
||||
}),
|
||||
assignFilter: assign({
|
||||
filter: (_, event) => event.query,
|
||||
}),
|
||||
assignGetUsersError: assign({
|
||||
getUsersError: (_, event) => event.data,
|
||||
}),
|
||||
assignUserIdToSuspend: assign({
|
||||
userIdToSuspend: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToDelete: assign({
|
||||
userIdToDelete: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToActivate: assign({
|
||||
userIdToActivate: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToResetPassword: assign({
|
||||
userIdToResetPassword: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToUpdateRoles: assign({
|
||||
userIdToUpdateRoles: (_, event) => event.userId,
|
||||
}),
|
||||
clearGetUsersError: assign((context: UsersContext) => ({
|
||||
...context,
|
||||
getUsersError: undefined,
|
||||
})),
|
||||
assignSuspendUserError: assign({
|
||||
suspendUserError: (_, event) => event.data,
|
||||
}),
|
||||
assignDeleteUserError: assign({
|
||||
deleteUserError: (_, event) => event.data,
|
||||
}),
|
||||
assignActivateUserError: assign({
|
||||
activateUserError: (_, event) => event.data,
|
||||
}),
|
||||
assignResetUserPasswordError: assign({
|
||||
resetUserPasswordError: (_, event) => event.data,
|
||||
}),
|
||||
assignUpdateRolesError: assign({
|
||||
updateUserRolesError: (_, event) => event.data,
|
||||
}),
|
||||
clearUsers: assign((context: UsersContext) => ({
|
||||
...context,
|
||||
users: undefined,
|
||||
})),
|
||||
clearSuspendUserError: assign({
|
||||
suspendUserError: (_) => undefined,
|
||||
}),
|
||||
clearDeleteUserError: assign({
|
||||
deleteUserError: (_) => undefined,
|
||||
}),
|
||||
clearActivateUserError: assign({
|
||||
activateUserError: (_) => undefined,
|
||||
}),
|
||||
clearResetUserPasswordError: assign({
|
||||
resetUserPasswordError: (_) => undefined,
|
||||
}),
|
||||
clearUpdateUserRolesError: assign({
|
||||
updateUserRolesError: (_) => undefined,
|
||||
}),
|
||||
displayGetUsersErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.getUsersError,
|
||||
Language.getUsersError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displaySuspendSuccess: () => {
|
||||
displaySuccess(Language.suspendUserSuccess)
|
||||
},
|
||||
displaySuspendedErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.suspendUserError,
|
||||
Language.suspendUserError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayDeleteSuccess: () => {
|
||||
displaySuccess(Language.deleteUserSuccess)
|
||||
},
|
||||
displayDeleteErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.deleteUserError,
|
||||
Language.deleteUserError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayActivateSuccess: () => {
|
||||
displaySuccess(Language.activateUserSuccess)
|
||||
},
|
||||
displayActivatedErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.activateUserError,
|
||||
Language.activateUserError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayResetPasswordSuccess: () => {
|
||||
displaySuccess(Language.resetUserPasswordSuccess)
|
||||
},
|
||||
displayResetPasswordErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.resetUserPasswordError,
|
||||
Language.resetUserPasswordError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayUpdateRolesErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.updateUserRolesError,
|
||||
Language.updateUserRolesError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
generateRandomPassword: assign({
|
||||
newUserPassword: (_) => generateRandomString(12),
|
||||
}),
|
||||
updateUserRolesInTheList: assign({
|
||||
users: ({ users }, event) => {
|
||||
if (!users) {
|
||||
return users
|
||||
export const usersMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QFdZgE6wMoBcCGOYAdLPujgJYB2UACnlNQRQPZUDEA2gAwC6ioAA4tYFSmwEgAHogCMADiLcA7AFYVAFgCcW5bNkaAbACZDAGhABPOVsNEAzN1XGDhw92PduW+wF9fFqgY2PiERDA4lDQAqmiY7BBsxNQAbiwA1sQRscE8-EggwqLiVJIyCPKyRHryyk4m9lrGzfYW1ggaGqpERvaq9soasqrKfgEgQZi4BFlgkdRQOfEY6CzoRIIANgQAZmsAtuFzS7B5kkVirKUF5QC0ssrGRLV1rs2VyrptiJ3K1cbyHQaUyqSoDVT+QJxEIzIgUCCbMDsLDRLC0ACiADkACIAfVR6IASmcChcSmVEMZOkRDPpgYZ5J4NNx5PZWlY5A8qvZjH15Nx7IZVFp5KoNJCJtDpmF4Yj2Nj0QAZdEAFXR+KwRJJQhElwkN0phi0RAMqncjIZo0Z3wqtSIOgZGg+3HNsglkxhMoRSIAggBhFUASQAaj61RqtXxzrryQaEKZ7Pb7KLBQCTLJ3Kobe5E2adINjE1DE7jO6paFkt72IT0ZqVRHCbjaD6sFgAOoAeUJ2O1hRjVwp8dkxq6A2UFuTyhMWY5CFcdlkhbB8n5vNBZeC0srcuitGxYfVBMbhI7yqwvbJA7jtwBfwF3lG-WHPhtjO4NIZ7lk9Q0fI3UwrOEq13fdw2bABxdEL37fVQDuHk7BUTQnEcAEdGzLoaQtdQ+h8Ywp3-T1tyRECD1xAAxQNFTVYko1JGDrjgxB7m6LQjABfCtBUYduFkV9h2qAZv3w5wuIhcYPS3IgAGM2B2Ch0H2JYsFQQQwCoUQ2HYP0O0xSjCQAWQbXEUTRLEsEDXToOKK8mNtRMCyFXpPjcLQbX0FcTU+EtnFwhlCKk2SqHkxTlNU9TNI4P0fUxP0lWM0yMUxCyrLonUbNg6REFBbpmU+LiHipbhOnc-D3xXUURVpWlioCwCgpCpS4mxMBERKbTdP0oyj1xBVlTVay9UYrKKh8e1vHkbRgRUBobS0fQelFRc9F-Nj5EMOrYQahSmowFq2qubSYrixVjL61UoLSvsMuG8paSeYZ7AzNlDHHN65rcGliv5AVPjNExNrCbbQriH1pMoFJmC0nS9MDQzjP9INQyDVL8nSobBxeD8BnsTops6NzZ0MXHFrZKk2NUfQNok8strknaljBiGoai474p6xGQzDSzMUG2M7OFVjuMXQVeNUSmbTqRNlt-NwnuUR5xRpzdANgcKqAgBYlgSJI4SoNJMhIdWICWPnbJG4ZFxNcX+XHbxhzUOa6i8o1vBFdRaTdZWANhNXYDUjWtbidgVjWDZthwPZFKN-31JNuIzcy8oPPfEYXEm3R8NGPjZ1kRwNCUYU8-w2Xv3EqEVdhCBWrmIOMB1qhkn1jJiGrtqwFNq7LyTuRKeNAxmS0UENEeXjJZGapmRGEfVrTwHW5rqJFmD0P1i2XYDiINu5g7hOu4Ywd9CH6oWVFV4uItdzeONMU6TZWpFxH+eiDwcGKEhpftcSRu9YN4hX+ZoQTuaNroYzjJbRMPgeQujUOob85hZxmlTrSEYLpTAKDNM-AB79mAxBXugVYa8I5R0ONgj+u8MCJ1upyWwk9vwsmTMVAw48C7aAZFyMUU59DP2BrtdA9BYCwAAO5rAgISOAcwOqw3hj1ZsrZOzdlxDWOsVDMZimqPAgwxhKbixFO5HCX1ibaABJTV6ygeH0xBhgARwjRHiLQDgI6sV2aakbHI9sXY8TKNVKouMad7T9FsMTI0Csnr6LtAYUWahFxMnMd7IiRB0ASPmHg6xeBBEiPQBABuTc-6JOSUsGxmSIC+LsnndRecmjqD0KMfC7lxwLlMLofot5RTUwrj7MISSHGfziEU0RIcCFh3XpHTe3Tjh9PSbYrJpSLYPGNCoRwoJ3iihXO5IUTwRS6BqMWAYwJn7IEEBAXBy8MCEhYIiWAOTf4tyIIc45QC4jnMubMu4VoTTFSFG+SpGgPp-CnFA4SzhtDl0lJXMI9yTlLGeXAQZhDw4b2jpCx5ZyLlwFecxL8Dghi6FegoPogp+LGlGHoDwahCxOH8OMKgLBq7wAKJJVWZAl70EYFQFm0YbqDluM4E+nxPgsmLCKXkr5uiFktDob8zJXpKw6QkiIvTgicrAXZW47geiSqGHigEi4ZztBBEQfobIjWeBiVoZ+sowDKv5hbHkzwmiDB5M0NwYpfmzjUAXZwZ9OjfjYk9CxwUGZxBUrHDS5tu7UIQKCRQXEhgjzluUnO7Qj4F0qBgqBeF2lgs6cQXhSx9q10yhGwcJgnhGlpI8IeT5xZzQWk6dQ6h+QPHFmMOVgVLF8KZjgm1xa4zVUnkaZkuMvBDD1YgIxpMeRTUphmZ+fsA6a1Sega15tk4ZkUEXV2TgxTCnkO5YYfwnoKHFVSSccS22AW3oq5d9EuXgIUFUHQvFTCvAMHo2cK4C4eCEn0dwXQHhYLfh-OuN70Y2rXWNbRDribzSNUm8dngTTfkBLyFB8aA2NUKVM4p9i5grp7lG+ahq1AijzsCcl8G5wGPcEYpoS0zHP3GSk05-DsOiPw5GjyC5nBeFZOaDwY65xsI-GoWoDb1pqAOUcqFTy0X0rA6u5inR3xrlsCyOoAohhzSMPaGpr03C8TZPPDj3KGkfKMMswzbEbS3AcgKRcSEnArkGPIKlvggA */
|
||||
createMachine(
|
||||
{
|
||||
tsTypes: {} as import("./usersXService.typegen").Typegen0,
|
||||
schema: {
|
||||
context: {} as UsersContext,
|
||||
events: {} as UsersEvent,
|
||||
services: {} as {
|
||||
getUsers: {
|
||||
data: TypesGen.User[]
|
||||
}
|
||||
|
||||
return users.map((u) => {
|
||||
return u.id === event.data.id ? event.data : u
|
||||
createUser: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
suspendUser: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
deleteUser: {
|
||||
data: undefined
|
||||
}
|
||||
activateUser: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
updateUserPassword: {
|
||||
data: undefined
|
||||
}
|
||||
updateUserRoles: {
|
||||
data: TypesGen.User
|
||||
}
|
||||
},
|
||||
},
|
||||
predictableActionArguments: true,
|
||||
id: "usersState",
|
||||
initial: "startingPagination",
|
||||
states: {
|
||||
startingPagination: {
|
||||
entry: "assignPaginationRef",
|
||||
always: {
|
||||
target: "gettingUsers",
|
||||
},
|
||||
},
|
||||
gettingUsers: {
|
||||
entry: "clearGetUsersError",
|
||||
invoke: {
|
||||
src: "getUsers",
|
||||
id: "getUsers",
|
||||
onDone: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: "assignUsers",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: [
|
||||
"clearUsers",
|
||||
"assignGetUsersError",
|
||||
"displayGetUsersErrorMessage",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
tags: "loading",
|
||||
},
|
||||
idle: {
|
||||
on: {
|
||||
SUSPEND_USER: {
|
||||
target: "confirmUserSuspension",
|
||||
actions: "assignUserIdToSuspend",
|
||||
},
|
||||
DELETE_USER: {
|
||||
target: "confirmUserDeletion",
|
||||
actions: "assignUserIdToDelete",
|
||||
},
|
||||
ACTIVATE_USER: {
|
||||
target: "confirmUserActivation",
|
||||
actions: "assignUserIdToActivate",
|
||||
},
|
||||
RESET_USER_PASSWORD: {
|
||||
target: "confirmUserPasswordReset",
|
||||
actions: [
|
||||
"assignUserIdToResetPassword",
|
||||
"generateRandomPassword",
|
||||
],
|
||||
},
|
||||
UPDATE_USER_ROLES: {
|
||||
target: "updatingUserRoles",
|
||||
actions: "assignUserIdToUpdateRoles",
|
||||
},
|
||||
UPDATE_PAGE: {
|
||||
target: "gettingUsers",
|
||||
actions: "updateURL",
|
||||
},
|
||||
UPDATE_FILTER: {
|
||||
actions: ["assignFilter", "sendResetPage"],
|
||||
},
|
||||
},
|
||||
},
|
||||
confirmUserSuspension: {
|
||||
on: {
|
||||
CONFIRM_USER_SUSPENSION: {
|
||||
target: "suspendingUser",
|
||||
},
|
||||
CANCEL_USER_SUSPENSION: {
|
||||
target: "idle",
|
||||
},
|
||||
},
|
||||
},
|
||||
confirmUserDeletion: {
|
||||
on: {
|
||||
CONFIRM_USER_DELETE: {
|
||||
target: "deletingUser",
|
||||
},
|
||||
CANCEL_USER_DELETE: {
|
||||
target: "idle",
|
||||
},
|
||||
},
|
||||
},
|
||||
confirmUserActivation: {
|
||||
on: {
|
||||
CONFIRM_USER_ACTIVATION: {
|
||||
target: "activatingUser",
|
||||
},
|
||||
CANCEL_USER_ACTIVATION: {
|
||||
target: "idle",
|
||||
},
|
||||
},
|
||||
},
|
||||
suspendingUser: {
|
||||
entry: "clearSuspendUserError",
|
||||
invoke: {
|
||||
src: "suspendUser",
|
||||
id: "suspendUser",
|
||||
onDone: [
|
||||
{
|
||||
target: "gettingUsers",
|
||||
actions: "displaySuspendSuccess",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignSuspendUserError",
|
||||
"displaySuspendedErrorMessage",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
deletingUser: {
|
||||
entry: "clearDeleteUserError",
|
||||
invoke: {
|
||||
src: "deleteUser",
|
||||
id: "deleteUser",
|
||||
onDone: [
|
||||
{
|
||||
target: "gettingUsers",
|
||||
actions: "displayDeleteSuccess",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: ["assignDeleteUserError", "displayDeleteErrorMessage"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
activatingUser: {
|
||||
entry: "clearActivateUserError",
|
||||
invoke: {
|
||||
src: "activateUser",
|
||||
id: "activateUser",
|
||||
onDone: [
|
||||
{
|
||||
target: "gettingUsers",
|
||||
actions: "displayActivateSuccess",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignActivateUserError",
|
||||
"displayActivatedErrorMessage",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
confirmUserPasswordReset: {
|
||||
on: {
|
||||
CONFIRM_USER_PASSWORD_RESET: {
|
||||
target: "resettingUserPassword",
|
||||
},
|
||||
CANCEL_USER_PASSWORD_RESET: {
|
||||
target: "idle",
|
||||
},
|
||||
},
|
||||
},
|
||||
resettingUserPassword: {
|
||||
entry: "clearResetUserPasswordError",
|
||||
invoke: {
|
||||
src: "resetUserPassword",
|
||||
id: "resetUserPassword",
|
||||
onDone: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: "displayResetPasswordSuccess",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignResetUserPasswordError",
|
||||
"displayResetPasswordErrorMessage",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
updatingUserRoles: {
|
||||
entry: "clearUpdateUserRolesError",
|
||||
invoke: {
|
||||
src: "updateUserRoles",
|
||||
id: "updateUserRoles",
|
||||
onDone: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: "updateUserRolesInTheList",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignUpdateRolesError",
|
||||
"displayUpdateRolesErrorMessage",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
services: {
|
||||
// Passing API.getUsers directly does not invoke the function properly
|
||||
// when it is mocked. This happen in the UsersPage tests inside of the
|
||||
// "shows a success message and refresh the page" test case.
|
||||
getUsers: (context) => {
|
||||
const { offset, limit } = getPaginationData(context.paginationRef)
|
||||
return API.getUsers({
|
||||
...queryToFilter(context.filter),
|
||||
offset,
|
||||
limit,
|
||||
})
|
||||
},
|
||||
}),
|
||||
suspendUser: (context) => {
|
||||
if (!context.userIdToSuspend) {
|
||||
throw new Error("userIdToSuspend is undefined")
|
||||
}
|
||||
|
||||
return API.suspendUser(context.userIdToSuspend)
|
||||
},
|
||||
deleteUser: (context) => {
|
||||
if (!context.userIdToDelete) {
|
||||
throw new Error("userIdToDelete is undefined")
|
||||
}
|
||||
return API.deleteUser(context.userIdToDelete)
|
||||
},
|
||||
activateUser: (context) => {
|
||||
if (!context.userIdToActivate) {
|
||||
throw new Error("userIdToActivate is undefined")
|
||||
}
|
||||
|
||||
return API.activateUser(context.userIdToActivate)
|
||||
},
|
||||
resetUserPassword: (context) => {
|
||||
if (!context.userIdToResetPassword) {
|
||||
throw new Error("userIdToResetPassword is undefined")
|
||||
}
|
||||
|
||||
if (!context.newUserPassword) {
|
||||
throw new Error("newUserPassword not generated")
|
||||
}
|
||||
|
||||
return API.updateUserPassword(context.userIdToResetPassword, {
|
||||
password: context.newUserPassword,
|
||||
old_password: "",
|
||||
})
|
||||
},
|
||||
updateUserRoles: (context, event) => {
|
||||
if (!context.userIdToUpdateRoles) {
|
||||
throw new Error("userIdToUpdateRoles is undefined")
|
||||
}
|
||||
|
||||
return API.updateUserRoles(event.roles, context.userIdToUpdateRoles)
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
assignUsers: assign({
|
||||
users: (_, event) => event.data,
|
||||
}),
|
||||
assignFilter: assign({
|
||||
filter: (_, event) => event.query,
|
||||
}),
|
||||
assignGetUsersError: assign({
|
||||
getUsersError: (_, event) => event.data,
|
||||
}),
|
||||
assignUserIdToSuspend: assign({
|
||||
userIdToSuspend: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToDelete: assign({
|
||||
userIdToDelete: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToActivate: assign({
|
||||
userIdToActivate: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToResetPassword: assign({
|
||||
userIdToResetPassword: (_, event) => event.userId,
|
||||
}),
|
||||
assignUserIdToUpdateRoles: assign({
|
||||
userIdToUpdateRoles: (_, event) => event.userId,
|
||||
}),
|
||||
clearGetUsersError: assign((context: UsersContext) => ({
|
||||
...context,
|
||||
getUsersError: undefined,
|
||||
})),
|
||||
assignSuspendUserError: assign({
|
||||
suspendUserError: (_, event) => event.data,
|
||||
}),
|
||||
assignDeleteUserError: assign({
|
||||
deleteUserError: (_, event) => event.data,
|
||||
}),
|
||||
assignActivateUserError: assign({
|
||||
activateUserError: (_, event) => event.data,
|
||||
}),
|
||||
assignResetUserPasswordError: assign({
|
||||
resetUserPasswordError: (_, event) => event.data,
|
||||
}),
|
||||
assignUpdateRolesError: assign({
|
||||
updateUserRolesError: (_, event) => event.data,
|
||||
}),
|
||||
clearUsers: assign((context: UsersContext) => ({
|
||||
...context,
|
||||
users: undefined,
|
||||
})),
|
||||
clearSuspendUserError: assign({
|
||||
suspendUserError: (_) => undefined,
|
||||
}),
|
||||
clearDeleteUserError: assign({
|
||||
deleteUserError: (_) => undefined,
|
||||
}),
|
||||
clearActivateUserError: assign({
|
||||
activateUserError: (_) => undefined,
|
||||
}),
|
||||
clearResetUserPasswordError: assign({
|
||||
resetUserPasswordError: (_) => undefined,
|
||||
}),
|
||||
clearUpdateUserRolesError: assign({
|
||||
updateUserRolesError: (_) => undefined,
|
||||
}),
|
||||
displayGetUsersErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.getUsersError,
|
||||
Language.getUsersError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displaySuspendSuccess: () => {
|
||||
displaySuccess(Language.suspendUserSuccess)
|
||||
},
|
||||
displaySuspendedErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.suspendUserError,
|
||||
Language.suspendUserError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayDeleteSuccess: () => {
|
||||
displaySuccess(Language.deleteUserSuccess)
|
||||
},
|
||||
displayDeleteErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.deleteUserError,
|
||||
Language.deleteUserError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayActivateSuccess: () => {
|
||||
displaySuccess(Language.activateUserSuccess)
|
||||
},
|
||||
displayActivatedErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.activateUserError,
|
||||
Language.activateUserError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayResetPasswordSuccess: () => {
|
||||
displaySuccess(Language.resetUserPasswordSuccess)
|
||||
},
|
||||
displayResetPasswordErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.resetUserPasswordError,
|
||||
Language.resetUserPasswordError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayUpdateRolesErrorMessage: (context) => {
|
||||
const message = getErrorMessage(
|
||||
context.updateUserRolesError,
|
||||
Language.updateUserRolesError,
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
generateRandomPassword: assign({
|
||||
newUserPassword: (_) => generateRandomString(12),
|
||||
}),
|
||||
updateUserRolesInTheList: assign({
|
||||
users: ({ users }, event) => {
|
||||
if (!users) {
|
||||
return users
|
||||
}
|
||||
|
||||
return users.map((u) => {
|
||||
return u.id === event.data.id ? event.data : u
|
||||
})
|
||||
},
|
||||
}),
|
||||
assignPaginationRef: assign({
|
||||
paginationRef: (context) =>
|
||||
spawn(
|
||||
paginationMachine.withContext(context.paginationContext),
|
||||
usersPaginationId,
|
||||
),
|
||||
}),
|
||||
sendResetPage: send({ type: "RESET_PAGE" }, { to: usersPaginationId }),
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user