Skip to content

Commit

Permalink
use ui-shared on admin same error handling
Browse files Browse the repository at this point in the history
also introduce optional renderer for added component
  • Loading branch information
edewit committed Oct 17, 2023
1 parent e6d0281 commit 836262d
Show file tree
Hide file tree
Showing 26 changed files with 3,018 additions and 620 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ public class ErrorRepresentation {
public ErrorRepresentation() {
}

public ErrorRepresentation(String errorMessage) {
this.errorMessage = errorMessage;
}

public ErrorRepresentation(String field, String errorMessage, Object[] params) {
super();
this.field = field;
Expand Down
63 changes: 35 additions & 28 deletions js/apps/account-ui/src/personal-info/PersonalInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ import {
Form,
Spinner,
} from "@patternfly/react-core";
import { ExternalLinkSquareAltIcon } from "@patternfly/react-icons";
import { useKeycloak } from "keycloak-masthead";
import { useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { UserProfileFields, useAlerts } from "ui-shared";
import {
UserProfileFields,
setUserProfileServerError,
useAlerts,
} from "ui-shared";
import {
getPersonalInfo,
getSupportedLocales,
Expand All @@ -25,20 +30,6 @@ import { environment } from "../environment";
import { TFuncKey } from "../i18n";
import { usePromise } from "../utils/usePromise";

type FieldError = {
field: string;
errorMessage: string;
params: string[];
};

const ROOT_ATTRIBUTES = ["username", "firstName", "lastName", "email"];
export const isBundleKey = (key?: string) => key?.includes("${");
export const unWrap = (key: string) => key.substring(2, key.length - 1);
export const isRootAttribute = (attr?: string) =>
attr && ROOT_ATTRIBUTES.includes(attr);
export const fieldName = (name: string) =>
`${isRootAttribute(name) ? "" : "attributes."}${name}`;

const PersonalInfo = () => {
const { t } = useTranslation();
const keycloak = useKeycloak();
Expand Down Expand Up @@ -70,26 +61,24 @@ const PersonalInfo = () => {
} catch (error) {
addError(t("accountUpdatedError").toString());

(error as FieldError[]).forEach((e) => {
const params = Object.assign(
{},
e.params.map((p) => t((isBundleKey(p) ? unWrap(p) : p) as TFuncKey)),
);
setError(fieldName(e.field) as keyof UserRepresentation, {
message: t(e.errorMessage as TFuncKey, {
...params,
defaultValue: e.field,
}),
type: "server",
});
});
setUserProfileServerError(
error,
setError,
(key: TFuncKey, param?: object) => t(key, { ...param }),
);
}
};

if (!userProfileMetadata) {
return <Spinner />;
}

const {
updateEmailFeatureEnabled,
updateEmailActionEnabled,
isRegistrationEmailAsUsername,
isEditUserNameAllowed,
} = environment.features;
return (
<Page title={t("personalInfo")} description={t("personalInfoDescription")}>
<Form isHorizontal onSubmit={handleSubmit(onSubmit)}>
Expand All @@ -98,6 +87,24 @@ const PersonalInfo = () => {
metaData={userProfileMetadata}
supportedLocales={supportedLocales}
t={(key: TFuncKey) => t(key)}
renderer={(attribute) =>
attribute.name === "email" &&
updateEmailFeatureEnabled &&
updateEmailActionEnabled &&
(!isRegistrationEmailAsUsername || isEditUserNameAllowed) ? (
<Button
id="update-email-btn"
variant="link"
onClick={() =>
keycloak?.keycloak.login({ action: "UPDATE_EMAIL" })
}
icon={<ExternalLinkSquareAltIcon />}
iconPosition="right"
>
{t("updateEmail")}
</Button>
) : undefined
}
/>
</FormProvider>
<ActionGroup>
Expand Down
2,868 changes: 2,868 additions & 0 deletions js/apps/admin-ui/public/locales/en/message.properties

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion js/apps/admin-ui/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1662,6 +1662,7 @@
"supportedLocales": "Supported locales",
"defaultLocale": "Default locale",
"selectLocales": "Select locales",
"selectALocale": "Select a locale",
"searchForMessageBundle": "Search for message bundle",
"addMessageBundle": "Add message bundle",
"addMessageBundleSuccess": "Success! The message bundle has been added.",
Expand Down Expand Up @@ -3287,5 +3288,24 @@
"scopeTypeHelp": "Client scopes, which will be added as default scopes to each created client",
"clientDescriptionHelp": "Specifies description of the client. For example 'My Client for TimeSheets'. Supports keys for localized values as well. For example: ${my_client_description}",
"clientsClientTypeHelp": "'OpenID Connect' allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server.'SAML' enables web-based authentication and authorization scenarios including cross-domain single sign-on (SSO) and uses security tokens containing assertions to pass information.",
"clientsClientScopesHelp": "The scopes associated with this resource."
"clientsClientScopesHelp": "The scopes associated with this resource.",
"error-empty": "Please specify value of '{{0}}'.",
"error-invalid-blank": "Please specify value of '{{0}}'.",
"error-invalid-date": "'{{0}}' is invalid date.",
"error-invalid-email": "Invalid email address.",
"error-invalid-length-too-long": "'{{0}}' must have maximal length of {{2}}.",
"error-invalid-length-too-short": "'{{0}}' must have minimal length of {{1}}.",
"error-invalid-length": "'{{0}}' must have a length between {{1}} and {{2}}.",
"error-invalid-number": "'{{0}}' is invalid number.",
"error-invalid-uri-fragment": "'{{0}}' is invalid URL fragment.",
"error-invalid-uri-scheme": "'{{0}}' has invalid URL scheme.",
"error-invalid-uri": "'{{0}}' is invalid URL.",
"error-invalid-value": "'{{0}}' has invalid value.",
"error-number-out-of-range-too-big": "'{{0}}' must have maximal value of {{2}}.",
"error-number-out-of-range-too-small": "'{{0}}' must have minimal value of {{1}}.",
"error-number-out-of-range": "'{{0}}' must be a number between {{1}} and {{2}}.",
"error-pattern-no-match": "'{{0}}' doesn't match required format.",
"error-person-name-invalid-character": "'{{0}}' contains invalid character.",
"error-user-attribute-required": "Please specify '{{0}}'.",
"error-username-invalid-character": "'{{0}}' contains invalid character."
}
9 changes: 4 additions & 5 deletions js/apps/admin-ui/src/user/CreateUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ import { useRealm } from "../context/realm-context/RealmContext";
import { useFetch } from "../utils/useFetch";
import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled";
import { UserForm } from "./UserForm";
import {
isUserProfileError,
userProfileErrorToString,
} from "./UserProfileFields";
import { isUserProfileError, setUserProfileServerError } from "ui-shared";
import { UserFormFields, toUserRepresentation } from "./form-state";
import { toUser } from "./routes/User";

Expand Down Expand Up @@ -74,7 +71,9 @@ export default function CreateUser() {
);
} catch (error) {
if (isUserProfileError(error)) {
addError(userProfileErrorToString(error), error);
setUserProfileServerError(error, form.setError, (key, param) =>
t(key as string, { ...param }),
);
} else {
addError("userCreateError", error);
}
Expand Down
12 changes: 6 additions & 6 deletions js/apps/admin-ui/src/user/EditUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";

import { isUserProfileError, setUserProfileServerError } from "ui-shared";
import { adminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
Expand All @@ -35,10 +35,6 @@ import { UserCredentials } from "./UserCredentials";
import { BruteForced, UserForm } from "./UserForm";
import { UserGroups } from "./UserGroups";
import { UserIdentityProviderLinks } from "./UserIdentityProviderLinks";
import {
isUserProfileError,
userProfileErrorToString,
} from "./UserProfileFields";
import { UserRoleMapping } from "./UserRoleMapping";
import { UserSessions } from "./UserSessions";
import {
Expand Down Expand Up @@ -129,7 +125,11 @@ export default function EditUser() {
refresh();
} catch (error) {
if (isUserProfileError(error)) {
addError(userProfileErrorToString(error), error);
setUserProfileServerError(
error.responseData.errors,
form.setError,
(key, param) => t(key as string, { ...param }),
);
} else {
addError("userCreateError", error);
}
Expand Down
10 changes: 4 additions & 6 deletions js/apps/admin-ui/src/user/UserForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import { useState } from "react";
import { Controller, UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { HelpItem } from "ui-shared";

import { HelpItem, UserProfileFields } from "ui-shared";
import { adminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts";
import { FormAccess } from "../components/form/FormAccess";
Expand All @@ -27,7 +26,6 @@ import { useAccess } from "../context/access/Access";
import { emailRegexPattern } from "../util";
import useFormatDate from "../utils/useFormatDate";
import { FederatedUserLink } from "./FederatedUserLink";
import { UserProfileFields } from "./UserProfileFields";
import { UserFormFields, toUserFormFields } from "./form-state";
import { toUsers } from "./routes/Users";
import { RequiredActionMultiSelect } from "./user-credentials/RequiredActionMultiSelect";
Expand Down Expand Up @@ -188,9 +186,9 @@ export const UserForm = ({
)}
{userProfileMetadata ? (
<UserProfileFields
form={form}
userProfileMetadata={userProfileMetadata}
hideReadOnly={!user}
metaData={user?.userProfileMetadata}
supportedLocales={realm.supportedLocales || []}
t={(key) => t(key as string)}
/>
) : (
<>
Expand Down
Loading

0 comments on commit 836262d

Please sign in to comment.