From cf8442fa4b150a3d61389a7e71c45e1072040a44 Mon Sep 17 00:00:00 2001 From: Presley Date: Wed, 27 Apr 2022 18:18:07 +0000 Subject: [PATCH] Switch to using creation mode in XState still problems in tests --- .../CreateUserPage/CreateUserPage.tsx | 16 +++-- site/src/pages/UsersPage/UsersPage.tsx | 8 ++- site/src/testHelpers/index.tsx | 1 + site/src/xServices/StateContext.tsx | 4 +- site/src/xServices/users/usersXService.ts | 65 +++++++++++-------- 5 files changed, 54 insertions(+), 40 deletions(-) diff --git a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx index da4febd6df..89e3f21e46 100644 --- a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx +++ b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx @@ -1,6 +1,6 @@ import { useActor } from "@xstate/react" import React, { useContext } from "react" -import { useNavigate } from "react-router" +import { Navigate } from "react-router" import { CreateUserRequest } from "../../../api/typesGenerated" import { CreateUserForm } from "../../../components/CreateUserForm/CreateUserForm" import { XServiceContext } from "../../../xServices/StateContext" @@ -13,17 +13,19 @@ export const CreateUserPage = () => { const xServices = useContext(XServiceContext) const [usersState, usersSend] = useActor(xServices.usersXService) const { createUserError, createUserFormErrors } = usersState.context - const navigate = useNavigate() // There is no field for organization id in Community Edition, so handle its field error like a generic error - const genericError = (createUserError || createUserFormErrors?.organization_id) ? Language.unknownError : undefined + const genericError = createUserError || createUserFormErrors?.organization_id ? Language.unknownError : undefined - return ( - usersSend({ type: "CREATE", user })} - onCancel={() => navigate("/users")} + onCancel={() => {usersSend("EXIT_CREATION_MODE")}} isLoading={usersState.hasTag("loading")} error={genericError} /> - ) + } else { + // on cancel or success, redirect + return + } } diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index 699a432234..0efc19be12 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -1,6 +1,6 @@ import { useActor } from "@xstate/react" import React, { useContext, useEffect } from "react" -import { useNavigate } from "react-router" +import { Navigate } from "react-router" import { ErrorSummary } from "../../components/ErrorSummary/ErrorSummary" import { XServiceContext } from "../../xServices/StateContext" import { UsersPageView } from "./UsersPageView" @@ -9,7 +9,6 @@ export const UsersPage: React.FC = () => { const xServices = useContext(XServiceContext) const [usersState, usersSend] = useActor(xServices.usersXService) const { users, pager, getUsersError } = usersState.context - const navigate = useNavigate() /** * Fetch users on component mount @@ -20,13 +19,16 @@ export const UsersPage: React.FC = () => { if (usersState.matches("error")) { return + } else if (usersState.matches("creationMode")) { + console.log("loop") + return } else { return ( { - navigate("/users/create") + usersSend("ENTER_CREATION_MODE") }} /> ) diff --git a/site/src/testHelpers/index.tsx b/site/src/testHelpers/index.tsx index 873c9687dc..527206f5a9 100644 --- a/site/src/testHelpers/index.tsx +++ b/site/src/testHelpers/index.tsx @@ -3,6 +3,7 @@ import { render as wrappedRender, RenderResult } from "@testing-library/react" import { createMemoryHistory } from "history" import React from "react" import { MemoryRouter, Route, Routes, unstable_HistoryRouter as HistoryRouter } from "react-router-dom" +import { AppRouter } from "../AppRouter" import { RequireAuth } from "../components/RequireAuth/RequireAuth" import { dark } from "../theme" import { XServiceProvider } from "../xServices/StateContext" diff --git a/site/src/xServices/StateContext.tsx b/site/src/xServices/StateContext.tsx index 4a9bf20991..aa0fad0dc0 100644 --- a/site/src/xServices/StateContext.tsx +++ b/site/src/xServices/StateContext.tsx @@ -1,6 +1,5 @@ import { useInterpret } from "@xstate/react" import React, { createContext } from "react" -import { useNavigate } from "react-router" import { ActorRefFrom } from "xstate" import { authMachine } from "./auth/authXService" import { buildInfoMachine } from "./buildInfo/buildInfoXService" @@ -23,13 +22,12 @@ interface XServiceContextType { export const XServiceContext = createContext({} as XServiceContextType) export const XServiceProvider: React.FC = ({ children }) => { - const navigate = useNavigate() return ( {children} diff --git a/site/src/xServices/users/usersXService.ts b/site/src/xServices/users/usersXService.ts index 7624250c19..017d955a14 100644 --- a/site/src/xServices/users/usersXService.ts +++ b/site/src/xServices/users/usersXService.ts @@ -1,4 +1,3 @@ -import { NavigateFunction } from "react-router" import { assign, createMachine } from "xstate" import * as API from "../../api" import { ApiError, FieldErrors, isApiError, mapApiErrorToFieldErrors } from "../../api/errors" @@ -16,10 +15,13 @@ export interface UsersContext { getUsersError?: Error | unknown createUserError?: Error | unknown createUserFormErrors?: FieldErrors - navigate?: NavigateFunction } -export type UsersEvent = { type: "GET_USERS" } | { type: "CREATE"; user: TypesGen.CreateUserRequest } +export type UsersEvent = + | { type: "GET_USERS" } + | { type: "ENTER_CREATION_MODE" } + | { type: "EXIT_CREATION_MODE" } + | { type: "CREATE"; user: TypesGen.CreateUserRequest } export const usersMachine = createMachine( { @@ -45,7 +47,7 @@ export const usersMachine = createMachine( idle: { on: { GET_USERS: "gettingUsers", - CREATE: "creatingUser", + ENTER_CREATION_MODE: "creationMode", }, }, gettingUsers: { @@ -67,28 +69,40 @@ export const usersMachine = createMachine( }, tags: "loading", }, - creatingUser: { - invoke: { - src: "createUser", - id: "createUser", - onDone: { - target: "idle", - actions: ["displayCreateUserSuccess", "redirectToUsersPage", "clearCreateUserError"], + creationMode: { + initial: "idle", + states: { + idle: { + on: { + CREATE: "creatingUser", + EXIT_CREATION_MODE: "#usersState.idle" + }, }, - onError: [ - { - target: "idle", - cond: "isFormError", - actions: ["assignCreateUserFormErrors"], + creatingUser: { + invoke: { + src: "createUser", + id: "createUser", + onDone: { + target: "#usersState.idle", + actions: ["displayCreateUserSuccess", "clearCreateUserError"], + }, + onError: [ + { + target: "idle", + cond: "isFormError", + actions: ["assignCreateUserFormErrors"], + }, + { + target: "idle", + actions: ["assignCreateUserError"], + }, + ], }, - { - target: "idle", - actions: ["assignCreateUserError"], - }, - ], + tags: "loading", + }, }, - tags: "loading", }, + error: { on: { GET_USERS: "gettingUsers", @@ -102,7 +116,7 @@ export const usersMachine = createMachine( createUser: (_, event) => API.createUser(event.user), }, guards: { - isFormError: (_, event) => isApiError(event.data) + isFormError: (_, event) => isApiError(event.data), }, actions: { assignUsers: assign({ @@ -121,7 +135,7 @@ export const usersMachine = createMachine( }), assignCreateUserFormErrors: assign({ // the guard ensures it is ApiError - createUserFormErrors: (_, event) => mapApiErrorToFieldErrors((event.data as ApiError).response.data) + createUserFormErrors: (_, event) => mapApiErrorToFieldErrors((event.data as ApiError).response.data), }), clearCreateUserError: assign((context: UsersContext) => ({ ...context, @@ -130,9 +144,6 @@ export const usersMachine = createMachine( displayCreateUserSuccess: () => { displaySuccess(Language.createUserSuccess) }, - redirectToUsersPage: (context) => { - context.navigate && context.navigate("/users") - }, }, }, )