diff --git a/site/src/api/errors.ts b/site/src/api/errors.ts index 80c93dfe6dada..f16f422154848 100644 --- a/site/src/api/errors.ts +++ b/site/src/api/errors.ts @@ -44,3 +44,12 @@ export const mapApiErrorToFieldErrors = (apiErrorResponse: ApiErrorResponse): Fi return result } + +/** + * + * @param error + * @param defaultMessage + * @returns error's message if ApiError or Error, else defaultMessage + */ +export const getErrorMessage = (error: Error | ApiError | unknown, defaultMessage: string): string => + isApiError(error) ? error.response.data.message : error instanceof Error ? error.message : defaultMessage diff --git a/site/src/pages/UsersPage/UsersPage.test.tsx b/site/src/pages/UsersPage/UsersPage.test.tsx index 3e4b300b101af..086990a920d2e 100644 --- a/site/src/pages/UsersPage/UsersPage.test.tsx +++ b/site/src/pages/UsersPage/UsersPage.test.tsx @@ -272,6 +272,26 @@ describe("Users Page", () => { expect(API.updateUserRoles).toBeCalledTimes(1) expect(API.updateUserRoles).toBeCalledWith([...currentRoles, MockAuditorRole.name], MockUser.id) }) + it("shows an error from the backend", async () => { + render( + <> + + + , + ) + + server.use( + rest.put(`/api/v2/users/${MockUser.id}/roles`, (req, res, ctx) => { + return res(ctx.status(401), ctx.json({ message: "message from the backend" })) + }), + ) + + // eslint-disable-next-line @typescript-eslint/no-empty-function + await updateUserRole(() => {}, MockAuditorRole) + + // Check if the error message is displayed + await screen.findByText("message from the backend") + }) }) }) }) diff --git a/site/src/xServices/users/usersXService.ts b/site/src/xServices/users/usersXService.ts index c21219ae6e1be..7566f17ed4623 100644 --- a/site/src/xServices/users/usersXService.ts +++ b/site/src/xServices/users/usersXService.ts @@ -1,6 +1,6 @@ import { assign, createMachine } from "xstate" import * as API from "../../api/api" -import { ApiError, FieldErrors, isApiError, mapApiErrorToFieldErrors } from "../../api/errors" +import { ApiError, FieldErrors, getErrorMessage, isApiError, mapApiErrorToFieldErrors } from "../../api/errors" import * as TypesGen from "../../api/typesGenerated" import { displayError, displaySuccess } from "../../components/GlobalSnackbar/utils" import { generateRandomString } from "../../util/random" @@ -292,17 +292,20 @@ export const usersMachine = createMachine( displaySuspendSuccess: () => { displaySuccess(Language.suspendUserSuccess) }, - displaySuspendedErrorMessage: () => { - displayError(Language.suspendUserError) + displaySuspendedErrorMessage: (context) => { + const message = getErrorMessage(context.suspendUserError, Language.suspendUserError) + displayError(message) }, displayResetPasswordSuccess: () => { displaySuccess(Language.resetUserPasswordSuccess) }, - displayResetPasswordErrorMessage: () => { - displayError(Language.resetUserPasswordError) + displayResetPasswordErrorMessage: (context) => { + const message = getErrorMessage(context.resetUserPasswordError, Language.resetUserPasswordError) + displayError(message) }, - displayUpdateRolesErrorMessage: () => { - displayError(Language.updateUserRolesError) + displayUpdateRolesErrorMessage: (context) => { + const message = getErrorMessage(context.updateUserRolesError, Language.updateUserRolesError) + displayError(message) }, generateRandomPassword: assign({ newUserPassword: (_) => generateRandomString(12),