Reduced state held and fixed reset (#4213)

This commit is contained in:
Erik Jan de Wit 2023-01-18 12:58:13 +01:00 committed by GitHub
parent 6277c0bc06
commit 45b2a8da62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 52 deletions

View file

@ -251,7 +251,7 @@ describe("Realm roles test", () => {
keyValue.fillKeyValue({ key: "one", value: "1" }).validateRows(2); keyValue.fillKeyValue({ key: "one", value: "1" }).validateRows(2);
keyValue.save(); keyValue.save();
masthead.checkNotificationMessage("The role has been saved", true); masthead.checkNotificationMessage("The role has been saved", true);
keyValue.validateRows(1); keyValue.validateRows(2);
}); });
it("should add attribute multiple", () => { it("should add attribute multiple", () => {
@ -262,14 +262,14 @@ describe("Realm roles test", () => {
.fillKeyValue({ key: "two", value: "2" }, 1) .fillKeyValue({ key: "two", value: "2" }, 1)
.fillKeyValue({ key: "three", value: "3" }, 2) .fillKeyValue({ key: "three", value: "3" }, 2)
.save() .save()
.validateRows(3); .validateRows(4);
}); });
it("should delete attribute", () => { it("should delete attribute", () => {
listingPage.itemExist(editRoleName).goToItemDetails(editRoleName); listingPage.itemExist(editRoleName).goToItemDetails(editRoleName);
createRealmRolePage.goToAttributesTab(); createRealmRolePage.goToAttributesTab();
keyValue.deleteRow(1).save().validateRows(2); keyValue.deleteRow(1).save().validateRows(3);
}); });
}); });
}); });

View file

@ -5,12 +5,12 @@ import {
PageSection, PageSection,
ValidatedOptions, ValidatedOptions,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import type { SubmitHandler, UseFormMethods } from "react-hook-form"; import { SubmitHandler, useWatch, UseFormMethods } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, To } from "react-router-dom-v5-compat"; import { Link, To } from "react-router-dom-v5-compat";
import { FormAccess } from "../form-access/FormAccess"; import { FormAccess } from "../form-access/FormAccess";
import type { AttributeForm } from "../key-value-form/AttributeForm"; import { AttributeForm } from "../key-value-form/AttributeForm";
import { KeycloakTextArea } from "../keycloak-text-area/KeycloakTextArea"; import { KeycloakTextArea } from "../keycloak-text-area/KeycloakTextArea";
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput";
import { ViewHeader } from "../view-header/ViewHeader"; import { ViewHeader } from "../view-header/ViewHeader";
@ -24,7 +24,7 @@ export type RoleFormProps = {
}; };
export const RoleForm = ({ export const RoleForm = ({
form: { handleSubmit, errors, register, getValues }, form: { register, control, handleSubmit, errors },
onSubmit, onSubmit,
cancelLink, cancelLink,
role, role,
@ -32,6 +32,12 @@ export const RoleForm = ({
}: RoleFormProps) => { }: RoleFormProps) => {
const { t } = useTranslation("roles"); const { t } = useTranslation("roles");
const roleName = useWatch<string | undefined>({
control,
defaultValue: undefined,
name: "name",
});
return ( return (
<> <>
{!editMode && <ViewHeader titleKey={t("createRole")} />} {!editMode && <ViewHeader titleKey={t("createRole")} />}
@ -86,7 +92,7 @@ export const RoleForm = ({
? ValidatedOptions.error ? ValidatedOptions.error
: ValidatedOptions.default : ValidatedOptions.default
} }
isDisabled={getValues().name?.includes("default-roles")} isDisabled={roleName?.includes("default-roles")}
/> />
</FormGroup> </FormGroup>
<ActionGroup> <ActionGroup>

View file

@ -8,9 +8,8 @@ import {
Tab, Tab,
TabTitleText, TabTitleText,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { omit } from "lodash-es";
import { useState } from "react"; import { useState } from "react";
import { SubmitHandler, useForm } from "react-hook-form"; import { SubmitHandler, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocation, useMatch, useNavigate } from "react-router-dom-v5-compat"; import { useLocation, useMatch, useNavigate } from "react-router-dom-v5-compat";
@ -30,6 +29,7 @@ import {
import { import {
arrayToKeyValue, arrayToKeyValue,
keyValueToArray, keyValueToArray,
KeyValueType,
} from "../components/key-value-form/key-value-convert"; } from "../components/key-value-form/key-value-convert";
import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner";
import { PermissionsTab } from "../components/permission-tab/PermissionTab"; import { PermissionsTab } from "../components/permission-tab/PermissionTab";
@ -54,11 +54,10 @@ export default function RealmRoleTabs() {
const form = useForm<AttributeForm>({ const form = useForm<AttributeForm>({
mode: "onChange", mode: "onChange",
}); });
const { setValue, reset } = form; const { control, reset, setValue } = form;
const navigate = useNavigate(); const navigate = useNavigate();
const { adminClient } = useAdminClient(); const { adminClient } = useAdminClient();
const [role, setRole] = useState<AttributeForm>();
const { id, clientId } = useParams<ClientRoleParams>(); const { id, clientId } = useParams<ClientRoleParams>();
const { pathname } = useLocation(); const { pathname } = useLocation();
@ -66,12 +65,11 @@ export default function RealmRoleTabs() {
const { realm: realmName } = useRealm(); const { realm: realmName } = useRealm();
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const [attributes, setAttributes] = useState<KeyValueType[] | undefined>();
const { profileInfo } = useServerInfo(); const { profileInfo } = useServerInfo();
const refresh = () => { const refresh = () => setKey(key + 1);
setKey(key + 1);
};
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
@ -84,6 +82,18 @@ export default function RealmRoleTabs() {
}; };
}; };
const roleName = useWatch<string | undefined>({
control,
defaultValue: undefined,
name: "name",
});
const composites = useWatch<boolean>({
control,
defaultValue: false,
name: "composite",
});
const [realm, setRealm] = useState<RealmRepresentation>(); const [realm, setRealm] = useState<RealmRepresentation>();
useFetch( useFetch(
@ -103,36 +113,20 @@ export default function RealmRoleTabs() {
const convertedRole = convert(role); const convertedRole = convert(role);
reset(convertedRole); reset(convertedRole);
setAttributes(convertedRole.attributes);
setRealm(realm); setRealm(realm);
setRole(convertedRole);
}, },
[key] [key]
); );
const onSubmit: SubmitHandler<AttributeForm> = async (formValues) => { const onSubmit: SubmitHandler<AttributeForm> = async (formValues) => {
try { try {
if (
formValues.attributes &&
formValues.attributes[formValues.attributes.length - 1]?.key === ""
) {
setValue(
"attributes",
formValues.attributes.slice(0, formValues.attributes.length - 1)
);
}
const { attributes, ...rest } = formValues; const { attributes, ...rest } = formValues;
let roleRepresentation: RoleRepresentation = rest; const roleRepresentation: RoleRepresentation = rest;
roleRepresentation.name = roleRepresentation.name?.trim(); roleRepresentation.name = roleRepresentation.name?.trim();
roleRepresentation.attributes = keyValueToArray(attributes);
if (attributes) {
roleRepresentation.attributes = keyValueToArray(attributes);
}
roleRepresentation = {
...omit(role!, "attributes"),
...roleRepresentation,
};
if (!clientId) { if (!clientId) {
await adminClient.roles.updateById({ id }, roleRepresentation); await adminClient.roles.updateById({ id }, roleRepresentation);
} else { } else {
@ -142,7 +136,7 @@ export default function RealmRoleTabs() {
); );
} }
setRole(convert(roleRepresentation)); setAttributes(attributes);
addAlert(t("roleSaveSuccess"), AlertVariant.success); addAlert(t("roleSaveSuccess"), AlertVariant.success);
} catch (error) { } catch (error) {
addError("roles:roleSaveError", error); addError("roles:roleSaveError", error);
@ -201,7 +195,7 @@ export default function RealmRoleTabs() {
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: "roles:roleDeleteConfirm", titleKey: "roles:roleDeleteConfirm",
messageKey: t("roles:roleDeleteConfirmDialog", { messageKey: t("roles:roleDeleteConfirmDialog", {
selectedRoleName: role?.name || t("createRole"), selectedRoleName: roleName || t("createRole"),
}), }),
continueButtonLabel: "common:delete", continueButtonLabel: "common:delete",
continueButtonVariant: ButtonVariant.danger, continueButtonVariant: ButtonVariant.danger,
@ -212,7 +206,7 @@ export default function RealmRoleTabs() {
} else { } else {
await adminClient.clients.delRole({ await adminClient.clients.delRole({
id: clientId, id: clientId,
roleName: role!.name!, roleName: roleName!,
}); });
} }
addAlert(t("roleDeletedSuccess"), AlertVariant.success); addAlert(t("roleDeletedSuccess"), AlertVariant.success);
@ -266,14 +260,14 @@ export default function RealmRoleTabs() {
] = useConfirmDialog({ ] = useConfirmDialog({
titleKey: t("roles:removeAllAssociatedRoles") + "?", titleKey: t("roles:removeAllAssociatedRoles") + "?",
messageKey: t("roles:removeAllAssociatedRolesConfirmDialog", { messageKey: t("roles:removeAllAssociatedRolesConfirmDialog", {
name: role?.name || t("createRole"), name: roleName || t("createRole"),
}), }),
continueButtonLabel: "common:delete", continueButtonLabel: "common:delete",
continueButtonVariant: ButtonVariant.danger, continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => { onConfirm: async () => {
try { try {
const additionalRoles = await adminClient.roles.getCompositeRoles({ const additionalRoles = await adminClient.roles.getCompositeRoles({
id: role!.id!, id,
}); });
await adminClient.roles.delCompositeRoles({ id }, additionalRoles); await adminClient.roles.delCompositeRoles({ id }, additionalRoles);
addAlert( addAlert(
@ -296,7 +290,7 @@ export default function RealmRoleTabs() {
const addComposites = async (composites: RoleRepresentation[]) => { const addComposites = async (composites: RoleRepresentation[]) => {
try { try {
await adminClient.roles.createComposite( await adminClient.roles.createComposite(
{ roleId: role?.id!, realm: realm!.realm }, { roleId: id, realm: realm!.realm },
composites composites
); );
refresh(); refresh();
@ -307,9 +301,10 @@ export default function RealmRoleTabs() {
} }
}; };
const isDefaultRole = (name: string) => realm?.defaultRole!.name === name; const isDefaultRole = (name: string | undefined) =>
realm?.defaultRole!.name === name;
if (!realm || !role) { if (!realm) {
return <KeycloakSpinner />; return <KeycloakSpinner />;
} }
@ -321,17 +316,17 @@ export default function RealmRoleTabs() {
<AddRoleMappingModal <AddRoleMappingModal
id={id} id={id}
type="roles" type="roles"
name={role.name} name={roleName}
onAssign={(rows) => addComposites(rows.map((r) => r.role))} onAssign={(rows) => addComposites(rows.map((r) => r.role))}
onClose={() => setOpen(false)} onClose={() => setOpen(false)}
/> />
)} )}
<ViewHeader <ViewHeader
titleKey={role.name!} titleKey={roleName!}
badges={[ badges={[
{ {
id: "composite-role-badge", id: "composite-role-badge",
text: role.composite ? t("composite") : "", text: composites ? t("composite") : "",
readonly: true, readonly: true,
}, },
]} ]}
@ -354,25 +349,25 @@ export default function RealmRoleTabs() {
? toClient({ realm: realmName, clientId, tab: "roles" }) ? toClient({ realm: realmName, clientId, tab: "roles" })
: toRealmRoles({ realm: realmName }) : toRealmRoles({ realm: realmName })
} }
editMode={true} editMode
/> />
</Tab> </Tab>
{role.composite && ( {composites && (
<Tab <Tab
data-testid="associatedRolesTab" data-testid="associatedRolesTab"
title={<TabTitleText>{t("associatedRolesText")}</TabTitleText>} title={<TabTitleText>{t("associatedRolesText")}</TabTitleText>}
{...associatedRolesTab} {...associatedRolesTab}
> >
<RoleMapping <RoleMapping
name={role.name!} name={roleName!}
id={role.id!} id={id}
type="roles" type="roles"
isManager isManager
save={(rows) => addComposites(rows.map((r) => r.role))} save={(rows) => addComposites(rows.map((r) => r.role))}
/> />
</Tab> </Tab>
)} )}
{!isDefaultRole(role.name!) && ( {!isDefaultRole(roleName) && (
<Tab <Tab
data-testid="attributesTab" data-testid="attributesTab"
className="kc-attributes-tab" className="kc-attributes-tab"
@ -382,11 +377,13 @@ export default function RealmRoleTabs() {
<AttributesForm <AttributesForm
form={form} form={form}
save={onSubmit} save={onSubmit}
reset={() => reset(role)} reset={() =>
setValue("attributes", attributes, { shouldDirty: false })
}
/> />
</Tab> </Tab>
)} )}
{!isDefaultRole(role.name!) && ( {!isDefaultRole(roleName) && (
<Tab <Tab
title={<TabTitleText>{t("usersInRole")}</TabTitleText>} title={<TabTitleText>{t("usersInRole")}</TabTitleText>}
{...usersInRoleTab} {...usersInRoleTab}
@ -401,7 +398,7 @@ export default function RealmRoleTabs() {
title={<TabTitleText>{t("common:permissions")}</TabTitleText>} title={<TabTitleText>{t("common:permissions")}</TabTitleText>}
{...permissionsTab} {...permissionsTab}
> >
<PermissionsTab id={role.id} type="roles" /> <PermissionsTab id={id} type="roles" />
</Tab> </Tab>
)} )}
</RoutableTabs> </RoutableTabs>