diff --git a/site/src/api/errors.ts b/site/src/api/errors.ts
index f16f422154848..052dd303f9e97 100644
--- a/site/src/api/errors.ts
+++ b/site/src/api/errors.ts
@@ -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 = {}
diff --git a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.test.tsx b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.test.tsx
index 0aae2f9f35695..907807afe47c4 100644
--- a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.test.tsx
+++ b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.test.tsx
@@ -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",
@@ -46,7 +46,7 @@ describe("Create User Page", () => {
})
render()
await fillForm({})
- const errorMessage = await screen.findByText(Language.unknownError)
+ const errorMessage = await screen.findByText(UserLanguage.createUserError)
expect(errorMessage).toBeDefined()
})
diff --git a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx
index 6b1bd0367ff7c..c5ddc98adcb3e 100644
--- a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx
+++ b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx
@@ -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 (
diff --git a/site/src/xServices/users/usersXService.ts b/site/src/xServices/users/usersXService.ts
index 7566f17ed4623..abbd1d5cf49b6 100644
--- a/site/src/xServices/users/usersXService.ts
+++ b/site/src/xServices/users/usersXService.ts
@@ -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"]
@@ -122,7 +130,7 @@ export const usersMachine = createMachine(
onError: [
{
target: "idle",
- cond: "isFormError",
+ cond: "hasFieldErrors",
actions: ["assignCreateUserFormErrors"],
},
{
@@ -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({
@@ -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