Skip to content

Commit

Permalink
fix: Show error message from backend on create existing user (#1964)
Browse files Browse the repository at this point in the history
* Show error message from backend on create existing user

* Format
  • Loading branch information
presleyp committed Jun 1, 2022
1 parent 46ffb67 commit bb400a4
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 12 deletions.
8 changes: 8 additions & 0 deletions site/src/api/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ export const isApiError = (err: any): err is ApiError => {
return false
}

/**
* ApiErrors contain useful error messages in their response body. They contain an overall message
* and may also contain errors for specific form fields.
* @param error ApiError
* @returns true if the ApiError contains error messages for specific form fields.
*/
export const hasApiFieldErrors = (error: ApiError): boolean => Array.isArray(error.response.data.errors)

export const mapApiErrorToFieldErrors = (apiErrorResponse: ApiErrorResponse): FieldErrors => {
const result: FieldErrors = {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Language as FooterLanguage } from "../../../components/FormFooter/FormF
import { history, render } from "../../../testHelpers/renderHelpers"
import { server } from "../../../testHelpers/server"
import { Language as UserLanguage } from "../../../xServices/users/usersXService"
import { CreateUserPage, Language } from "./CreateUserPage"
import { CreateUserPage } from "./CreateUserPage"

const fillForm = async ({
username = "someuser",
Expand Down Expand Up @@ -46,7 +46,7 @@ describe("Create User Page", () => {
})
render(<CreateUserPage />)
await fillForm({})
const errorMessage = await screen.findByText(Language.unknownError)
const errorMessage = await screen.findByText(UserLanguage.createUserError)
expect(errorMessage).toBeDefined()
})

Expand Down
4 changes: 2 additions & 2 deletions site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ export const CreateUserPage: React.FC = () => {
const xServices = useContext(XServiceContext)
const myOrgId = useSelector(xServices.authXService, selectOrgId)
const [usersState, usersSend] = useActor(xServices.usersXService)
const { createUserError, createUserFormErrors } = usersState.context
const { createUserErrorMessage, 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 || !myOrgId ? Language.unknownError : undefined
createUserErrorMessage || createUserFormErrors?.organization_id || (!myOrgId ? Language.unknownError : undefined)

return (
<Margins>
Expand Down
24 changes: 16 additions & 8 deletions site/src/xServices/users/usersXService.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
import { assign, createMachine } from "xstate"
import * as API from "../../api/api"
import { ApiError, FieldErrors, getErrorMessage, isApiError, mapApiErrorToFieldErrors } from "../../api/errors"
import {
ApiError,
FieldErrors,
getErrorMessage,
hasApiFieldErrors,
isApiError,
mapApiErrorToFieldErrors,
} from "../../api/errors"
import * as TypesGen from "../../api/typesGenerated"
import { displayError, displaySuccess } from "../../components/GlobalSnackbar/utils"
import { generateRandomString } from "../../util/random"

export const Language = {
createUserSuccess: "Successfully created user.",
createUserError: "Error on creating the user.",
suspendUserSuccess: "Successfully suspended the user.",
suspendUserError: "Error on suspend the user.",
suspendUserError: "Error on suspending the user.",
resetUserPasswordSuccess: "Successfully updated the user password.",
resetUserPasswordError: "Error on reset the user password.",
resetUserPasswordError: "Error on resetting the user password.",
updateUserRolesSuccess: "Successfully updated the user roles.",
updateUserRolesError: "Error on update the user roles.",
updateUserRolesError: "Error on updating the user roles.",
}

export interface UsersContext {
// Get users
users?: TypesGen.User[]
getUsersError?: Error | unknown
createUserError?: Error | unknown
createUserErrorMessage?: string
createUserFormErrors?: FieldErrors
// Suspend user
userIdToSuspend?: TypesGen.User["id"]
Expand Down Expand Up @@ -122,7 +130,7 @@ export const usersMachine = createMachine(
onError: [
{
target: "idle",
cond: "isFormError",
cond: "hasFieldErrors",
actions: ["assignCreateUserFormErrors"],
},
{
Expand Down Expand Up @@ -235,7 +243,7 @@ export const usersMachine = createMachine(
},
},
guards: {
isFormError: (_, event) => isApiError(event.data),
hasFieldErrors: (_, event) => isApiError(event.data) && hasApiFieldErrors(event.data),
},
actions: {
assignUsers: assign({
Expand All @@ -258,7 +266,7 @@ export const usersMachine = createMachine(
getUsersError: undefined,
})),
assignCreateUserError: assign({
createUserError: (_, event) => event.data,
createUserErrorMessage: (_, event) => getErrorMessage(event.data, Language.createUserError),
}),
assignCreateUserFormErrors: assign({
// the guard ensures it is ApiError
Expand Down

0 comments on commit bb400a4

Please sign in to comment.