Skip to content

Commit bb400a4

Browse files
authored
fix: Show error message from backend on create existing user (#1964)
* Show error message from backend on create existing user * Format
1 parent 46ffb67 commit bb400a4

File tree

4 files changed

+28
-12
lines changed

4 files changed

+28
-12
lines changed

site/src/api/errors.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ export const isApiError = (err: any): err is ApiError => {
3333
return false
3434
}
3535

36+
/**
37+
* ApiErrors contain useful error messages in their response body. They contain an overall message
38+
* and may also contain errors for specific form fields.
39+
* @param error ApiError
40+
* @returns true if the ApiError contains error messages for specific form fields.
41+
*/
42+
export const hasApiFieldErrors = (error: ApiError): boolean => Array.isArray(error.response.data.errors)
43+
3644
export const mapApiErrorToFieldErrors = (apiErrorResponse: ApiErrorResponse): FieldErrors => {
3745
const result: FieldErrors = {}
3846

site/src/pages/UsersPage/CreateUserPage/CreateUserPage.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Language as FooterLanguage } from "../../../components/FormFooter/FormF
77
import { history, render } from "../../../testHelpers/renderHelpers"
88
import { server } from "../../../testHelpers/server"
99
import { Language as UserLanguage } from "../../../xServices/users/usersXService"
10-
import { CreateUserPage, Language } from "./CreateUserPage"
10+
import { CreateUserPage } from "./CreateUserPage"
1111

1212
const fillForm = async ({
1313
username = "someuser",
@@ -46,7 +46,7 @@ describe("Create User Page", () => {
4646
})
4747
render(<CreateUserPage />)
4848
await fillForm({})
49-
const errorMessage = await screen.findByText(Language.unknownError)
49+
const errorMessage = await screen.findByText(UserLanguage.createUserError)
5050
expect(errorMessage).toBeDefined()
5151
})
5252

site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ export const CreateUserPage: React.FC = () => {
1515
const xServices = useContext(XServiceContext)
1616
const myOrgId = useSelector(xServices.authXService, selectOrgId)
1717
const [usersState, usersSend] = useActor(xServices.usersXService)
18-
const { createUserError, createUserFormErrors } = usersState.context
18+
const { createUserErrorMessage, createUserFormErrors } = usersState.context
1919
const navigate = useNavigate()
2020
// There is no field for organization id in Community Edition, so handle its field error like a generic error
2121
const genericError =
22-
createUserError || createUserFormErrors?.organization_id || !myOrgId ? Language.unknownError : undefined
22+
createUserErrorMessage || createUserFormErrors?.organization_id || (!myOrgId ? Language.unknownError : undefined)
2323

2424
return (
2525
<Margins>

site/src/xServices/users/usersXService.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,33 @@
11
import { assign, createMachine } from "xstate"
22
import * as API from "../../api/api"
3-
import { ApiError, FieldErrors, getErrorMessage, isApiError, mapApiErrorToFieldErrors } from "../../api/errors"
3+
import {
4+
ApiError,
5+
FieldErrors,
6+
getErrorMessage,
7+
hasApiFieldErrors,
8+
isApiError,
9+
mapApiErrorToFieldErrors,
10+
} from "../../api/errors"
411
import * as TypesGen from "../../api/typesGenerated"
512
import { displayError, displaySuccess } from "../../components/GlobalSnackbar/utils"
613
import { generateRandomString } from "../../util/random"
714

815
export const Language = {
916
createUserSuccess: "Successfully created user.",
17+
createUserError: "Error on creating the user.",
1018
suspendUserSuccess: "Successfully suspended the user.",
11-
suspendUserError: "Error on suspend the user.",
19+
suspendUserError: "Error on suspending the user.",
1220
resetUserPasswordSuccess: "Successfully updated the user password.",
13-
resetUserPasswordError: "Error on reset the user password.",
21+
resetUserPasswordError: "Error on resetting the user password.",
1422
updateUserRolesSuccess: "Successfully updated the user roles.",
15-
updateUserRolesError: "Error on update the user roles.",
23+
updateUserRolesError: "Error on updating the user roles.",
1624
}
1725

1826
export interface UsersContext {
1927
// Get users
2028
users?: TypesGen.User[]
2129
getUsersError?: Error | unknown
22-
createUserError?: Error | unknown
30+
createUserErrorMessage?: string
2331
createUserFormErrors?: FieldErrors
2432
// Suspend user
2533
userIdToSuspend?: TypesGen.User["id"]
@@ -122,7 +130,7 @@ export const usersMachine = createMachine(
122130
onError: [
123131
{
124132
target: "idle",
125-
cond: "isFormError",
133+
cond: "hasFieldErrors",
126134
actions: ["assignCreateUserFormErrors"],
127135
},
128136
{
@@ -235,7 +243,7 @@ export const usersMachine = createMachine(
235243
},
236244
},
237245
guards: {
238-
isFormError: (_, event) => isApiError(event.data),
246+
hasFieldErrors: (_, event) => isApiError(event.data) && hasApiFieldErrors(event.data),
239247
},
240248
actions: {
241249
assignUsers: assign({
@@ -258,7 +266,7 @@ export const usersMachine = createMachine(
258266
getUsersError: undefined,
259267
})),
260268
assignCreateUserError: assign({
261-
createUserError: (_, event) => event.data,
269+
createUserErrorMessage: (_, event) => getErrorMessage(event.data, Language.createUserError),
262270
}),
263271
assignCreateUserFormErrors: assign({
264272
// the guard ensures it is ApiError

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy