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

+8
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

+2-2
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

+2-2
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

+16-8
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)