Split out role form for realm and client in seperate components (#4141)
This commit is contained in:
parent
84da38789d
commit
b4fef326de
13 changed files with 287 additions and 223 deletions
|
@ -243,13 +243,6 @@ describe("Realm roles test", () => {
|
||||||
createRealmRolePage.checkDescription(updateDescription);
|
createRealmRolePage.checkDescription(updateDescription);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should revert realm role", () => {
|
|
||||||
listingPage.itemExist(editRoleName).goToItemDetails(editRoleName);
|
|
||||||
createRealmRolePage.checkDescription(updateDescription);
|
|
||||||
createRealmRolePage.updateDescription("going to revert").cancel();
|
|
||||||
createRealmRolePage.checkDescription(updateDescription);
|
|
||||||
});
|
|
||||||
|
|
||||||
const keyValue = new KeyValueInput("attributes");
|
const keyValue = new KeyValueInput("attributes");
|
||||||
it("should add attribute", () => {
|
it("should add attribute", () => {
|
||||||
listingPage.itemExist(editRoleName).goToItemDetails(editRoleName);
|
listingPage.itemExist(editRoleName).goToItemDetails(editRoleName);
|
||||||
|
|
|
@ -93,9 +93,8 @@ export default class ProviderPage {
|
||||||
private mappersTab = "ldap-mappers-tab";
|
private mappersTab = "ldap-mappers-tab";
|
||||||
private rolesTab = "rolesTab";
|
private rolesTab = "rolesTab";
|
||||||
private createRoleBtn = "no-roles-for-this-client-empty-action";
|
private createRoleBtn = "no-roles-for-this-client-empty-action";
|
||||||
private realmRolesSaveBtn = "realm-roles-save-button";
|
private roleSaveBtn = "save";
|
||||||
private roleNameField = "#kc-name";
|
private roleNameField = "#kc-name";
|
||||||
private clientIdSelect = "#client\\.id-select-typeahead";
|
|
||||||
|
|
||||||
private groupName = "aa-uf-mappers-group";
|
private groupName = "aa-uf-mappers-group";
|
||||||
private clientName = "aa-uf-mappers-client";
|
private clientName = "aa-uf-mappers-client";
|
||||||
|
@ -313,7 +312,7 @@ export default class ProviderPage {
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.get(this.roleNameField).clear().type(roleName);
|
cy.get(this.roleNameField).clear().type(roleName);
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.findByTestId(this.realmRolesSaveBtn).click();
|
cy.findByTestId(this.roleSaveBtn).click();
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
class CreateRealmRolePage {
|
class CreateRealmRolePage {
|
||||||
private realmRoleNameInput = "#kc-name";
|
private realmRoleNameInput = "#kc-name";
|
||||||
private realmRoleNameError = "#kc-name-helper";
|
private realmRoleNameError = "#kc-name-helper";
|
||||||
private realmRoleDescriptionInput = "#kc-role-description";
|
private realmRoleDescriptionInput = "#kc-description";
|
||||||
private saveBtn = "realm-roles-save-button";
|
private saveBtn = "save";
|
||||||
private cancelBtn = "cancel";
|
private cancelBtn = "cancel";
|
||||||
|
|
||||||
//#region General Settings
|
//#region General Settings
|
||||||
|
|
70
apps/admin-ui/src/clients/roles/CreateClientRole.tsx
Normal file
70
apps/admin-ui/src/clients/roles/CreateClientRole.tsx
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||||
|
import { AlertVariant } from "@patternfly/react-core";
|
||||||
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useNavigate, useParams } from "react-router-dom-v5-compat";
|
||||||
|
|
||||||
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
|
import { AttributeForm } from "../../components/key-value-form/AttributeForm";
|
||||||
|
import { RoleForm } from "../../components/role-form/RoleForm";
|
||||||
|
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||||
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
|
import { toClientRole } from "../../realm-roles/routes/ClientRole";
|
||||||
|
import { toClient } from "../routes/Client";
|
||||||
|
import { NewRoleParams } from "../routes/NewRole";
|
||||||
|
|
||||||
|
export default function CreateClientRole() {
|
||||||
|
const { t } = useTranslation("roles");
|
||||||
|
const form = useForm<AttributeForm>({ mode: "onChange" });
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { clientId } = useParams<NewRoleParams>();
|
||||||
|
const { adminClient } = useAdminClient();
|
||||||
|
const { realm } = useRealm();
|
||||||
|
const { addAlert, addError } = useAlerts();
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<AttributeForm> = async (formValues) => {
|
||||||
|
const role: RoleRepresentation = {
|
||||||
|
...formValues,
|
||||||
|
name: formValues.name?.trim(),
|
||||||
|
attributes: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await adminClient.clients.createRole({
|
||||||
|
id: clientId,
|
||||||
|
...role,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createdRole = await adminClient.clients.findRole({
|
||||||
|
id: clientId!,
|
||||||
|
roleName: role.name!,
|
||||||
|
});
|
||||||
|
|
||||||
|
addAlert(t("roleCreated"), AlertVariant.success);
|
||||||
|
navigate(
|
||||||
|
toClientRole({
|
||||||
|
realm,
|
||||||
|
clientId: clientId!,
|
||||||
|
id: createdRole.id!,
|
||||||
|
tab: "details",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
addError("roles:roleCreateError", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RoleForm
|
||||||
|
form={form}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
cancelLink={toClient({
|
||||||
|
realm,
|
||||||
|
clientId: clientId!,
|
||||||
|
tab: "roles",
|
||||||
|
})}
|
||||||
|
role="manage-clients"
|
||||||
|
editMode={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import {
|
||||||
ResourceDetailsRoute,
|
ResourceDetailsRoute,
|
||||||
ResourceDetailsWithResourceIdRoute,
|
ResourceDetailsWithResourceIdRoute,
|
||||||
} from "./routes/Resource";
|
} from "./routes/Resource";
|
||||||
|
import { NewRoleRoute } from "./routes/NewRole";
|
||||||
import { NewScopeRoute } from "./routes/NewScope";
|
import { NewScopeRoute } from "./routes/NewScope";
|
||||||
import {
|
import {
|
||||||
ScopeDetailsRoute,
|
ScopeDetailsRoute,
|
||||||
|
@ -44,6 +45,7 @@ const routes: RouteDef[] = [
|
||||||
NewResourceRoute,
|
NewResourceRoute,
|
||||||
ResourceDetailsRoute,
|
ResourceDetailsRoute,
|
||||||
ResourceDetailsWithResourceIdRoute,
|
ResourceDetailsWithResourceIdRoute,
|
||||||
|
NewRoleRoute,
|
||||||
NewScopeRoute,
|
NewScopeRoute,
|
||||||
ScopeDetailsRoute,
|
ScopeDetailsRoute,
|
||||||
ScopeDetailsWithScopeIdRoute,
|
ScopeDetailsWithScopeIdRoute,
|
||||||
|
|
17
apps/admin-ui/src/clients/routes/NewRole.ts
Normal file
17
apps/admin-ui/src/clients/routes/NewRole.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { lazy } from "react";
|
||||||
|
import type { Path } from "react-router-dom-v5-compat";
|
||||||
|
import { generatePath } from "react-router-dom-v5-compat";
|
||||||
|
import type { RouteDef } from "../../route-config";
|
||||||
|
|
||||||
|
export type NewRoleParams = { realm: string; clientId: string };
|
||||||
|
|
||||||
|
export const NewRoleRoute: RouteDef = {
|
||||||
|
path: "/:realm/clients/:clientId/roles/new",
|
||||||
|
component: lazy(() => import("../roles/CreateClientRole")),
|
||||||
|
breadcrumb: (t) => t("roles:createRole"),
|
||||||
|
access: "manage-clients",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toCreateRole = (params: NewRoleParams): Partial<Path> => ({
|
||||||
|
pathname: generatePath(NewRoleRoute.path, params),
|
||||||
|
});
|
|
@ -5,32 +5,32 @@ import {
|
||||||
PageSection,
|
PageSection,
|
||||||
ValidatedOptions,
|
ValidatedOptions,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
|
import type { SubmitHandler, UseFormMethods } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import type { UseFormMethods } from "react-hook-form";
|
import { Link, To } from "react-router-dom-v5-compat";
|
||||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
|
||||||
import { FormAccess } from "../components/form-access/FormAccess";
|
|
||||||
import type { AttributeForm } from "../components/key-value-form/AttributeForm";
|
|
||||||
import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput";
|
|
||||||
import { KeycloakTextArea } from "../components/keycloak-text-area/KeycloakTextArea";
|
|
||||||
import { useRealm } from "../context/realm-context/RealmContext";
|
|
||||||
import { useNavigate } from "react-router-dom-v5-compat";
|
|
||||||
|
|
||||||
export type RealmRoleFormProps = {
|
import { FormAccess } from "../form-access/FormAccess";
|
||||||
|
import type { AttributeForm } from "../key-value-form/AttributeForm";
|
||||||
|
import { KeycloakTextArea } from "../keycloak-text-area/KeycloakTextArea";
|
||||||
|
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput";
|
||||||
|
import { ViewHeader } from "../view-header/ViewHeader";
|
||||||
|
|
||||||
|
export type RoleFormProps = {
|
||||||
form: UseFormMethods<AttributeForm>;
|
form: UseFormMethods<AttributeForm>;
|
||||||
save: () => void;
|
onSubmit: SubmitHandler<AttributeForm>;
|
||||||
|
cancelLink: To;
|
||||||
|
role: "manage-realm" | "manage-clients";
|
||||||
editMode: boolean;
|
editMode: boolean;
|
||||||
reset: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RealmRoleForm = ({
|
export const RoleForm = ({
|
||||||
form: { handleSubmit, errors, register, getValues },
|
form: { handleSubmit, errors, register, getValues },
|
||||||
save,
|
onSubmit,
|
||||||
|
cancelLink,
|
||||||
|
role,
|
||||||
editMode,
|
editMode,
|
||||||
reset,
|
}: RoleFormProps) => {
|
||||||
}: RealmRoleFormProps) => {
|
|
||||||
const { t } = useTranslation("roles");
|
const { t } = useTranslation("roles");
|
||||||
const navigate = useNavigate();
|
|
||||||
const { realm: realmName } = useRealm();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -38,26 +38,27 @@ export const RealmRoleForm = ({
|
||||||
<PageSection variant="light">
|
<PageSection variant="light">
|
||||||
<FormAccess
|
<FormAccess
|
||||||
isHorizontal
|
isHorizontal
|
||||||
onSubmit={handleSubmit(save)}
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
role="manage-realm"
|
role={role}
|
||||||
className="pf-u-mt-lg"
|
className="pf-u-mt-lg"
|
||||||
>
|
>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={t("roleName")}
|
label={t("roleName")}
|
||||||
fieldId="kc-name"
|
fieldId="kc-name"
|
||||||
isRequired
|
validated={
|
||||||
validated={errors.name ? "error" : "default"}
|
errors.name ? ValidatedOptions.error : ValidatedOptions.default
|
||||||
|
}
|
||||||
helperTextInvalid={t("common:required")}
|
helperTextInvalid={t("common:required")}
|
||||||
|
isRequired={!editMode}
|
||||||
>
|
>
|
||||||
<KeycloakTextInput
|
<KeycloakTextInput
|
||||||
|
id="kc-name"
|
||||||
|
name="name"
|
||||||
ref={register({
|
ref={register({
|
||||||
required: !editMode,
|
required: !editMode,
|
||||||
validate: (value: string) =>
|
validate: (value: string) =>
|
||||||
!!value.trim() || t("common:required").toString(),
|
!!value.trim() || t("common:required").toString(),
|
||||||
})}
|
})}
|
||||||
type="text"
|
|
||||||
id="kc-name"
|
|
||||||
name="name"
|
|
||||||
isReadOnly={editMode}
|
isReadOnly={editMode}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
@ -72,40 +73,32 @@ export const RealmRoleForm = ({
|
||||||
helperTextInvalid={errors.description?.message}
|
helperTextInvalid={errors.description?.message}
|
||||||
>
|
>
|
||||||
<KeycloakTextArea
|
<KeycloakTextArea
|
||||||
|
id="kc-description"
|
||||||
name="description"
|
name="description"
|
||||||
aria-label="description"
|
|
||||||
isDisabled={getValues().name?.includes("default-roles")}
|
|
||||||
ref={register({
|
ref={register({
|
||||||
maxLength: {
|
maxLength: {
|
||||||
value: 255,
|
value: 255,
|
||||||
message: t("common:maxLength", { length: 255 }),
|
message: t("common:maxLength", { length: 255 }),
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
type="text"
|
|
||||||
validated={
|
validated={
|
||||||
errors.description
|
errors.description
|
||||||
? ValidatedOptions.error
|
? ValidatedOptions.error
|
||||||
: ValidatedOptions.default
|
: ValidatedOptions.default
|
||||||
}
|
}
|
||||||
id="kc-role-description"
|
isDisabled={getValues().name?.includes("default-roles")}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<ActionGroup>
|
<ActionGroup>
|
||||||
<Button
|
<Button data-testid="save" type="submit" variant="primary">
|
||||||
variant="primary"
|
|
||||||
onClick={save}
|
|
||||||
data-testid="realm-roles-save-button"
|
|
||||||
>
|
|
||||||
{t("common:save")}
|
{t("common:save")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
data-testid="cancel"
|
data-testid="cancel"
|
||||||
onClick={() =>
|
|
||||||
editMode ? reset() : navigate(`/${realmName}/roles`)
|
|
||||||
}
|
|
||||||
variant="link"
|
variant="link"
|
||||||
|
component={(props) => <Link {...props} to={cancelLink} />}
|
||||||
>
|
>
|
||||||
{editMode ? t("common:revert") : t("common:cancel")}
|
{t("common:cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
</ActionGroup>
|
</ActionGroup>
|
||||||
</FormAccess>
|
</FormAccess>
|
57
apps/admin-ui/src/realm-roles/CreateRealmRole.tsx
Normal file
57
apps/admin-ui/src/realm-roles/CreateRealmRole.tsx
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||||
|
import { AlertVariant } from "@patternfly/react-core";
|
||||||
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useNavigate } from "react-router-dom-v5-compat";
|
||||||
|
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import { AttributeForm } from "../components/key-value-form/AttributeForm";
|
||||||
|
import { RoleForm } from "../components/role-form/RoleForm";
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
import { toRealmRole } from "./routes/RealmRole";
|
||||||
|
import { toRealmRoles } from "./routes/RealmRoles";
|
||||||
|
|
||||||
|
export default function CreateRealmRole() {
|
||||||
|
const { t } = useTranslation("roles");
|
||||||
|
const form = useForm<AttributeForm>({ mode: "onChange" });
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { adminClient } = useAdminClient();
|
||||||
|
const { realm } = useRealm();
|
||||||
|
const { addAlert, addError } = useAlerts();
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<AttributeForm> = async (formValues) => {
|
||||||
|
const role: RoleRepresentation = {
|
||||||
|
...formValues,
|
||||||
|
name: formValues.name?.trim(),
|
||||||
|
attributes: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await adminClient.roles.create(role);
|
||||||
|
|
||||||
|
const createdRole = await adminClient.roles.findOneByName({
|
||||||
|
name: formValues.name!,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!createdRole) {
|
||||||
|
throw new Error(t("common:notFound"));
|
||||||
|
}
|
||||||
|
|
||||||
|
addAlert(t("roleCreated"), AlertVariant.success);
|
||||||
|
navigate(toRealmRole({ realm, id: createdRole.id!, tab: "details" }));
|
||||||
|
} catch (error) {
|
||||||
|
addError("roles:roleCreateError", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RoleForm
|
||||||
|
form={form}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
cancelLink={toRealmRoles({ realm })}
|
||||||
|
role="manage-realm"
|
||||||
|
editMode={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -10,11 +10,12 @@ import {
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { omit } from "lodash-es";
|
import { omit } from "lodash-es";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useRouteMatch } from "react-router-dom";
|
import { useRouteMatch } from "react-router-dom";
|
||||||
import { useNavigate } from "react-router-dom-v5-compat";
|
import { useNavigate } from "react-router-dom-v5-compat";
|
||||||
|
|
||||||
|
import { toClient } from "../clients/routes/Client";
|
||||||
import { useAlerts } from "../components/alert/Alerts";
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||||
import {
|
import {
|
||||||
|
@ -28,6 +29,7 @@ import {
|
||||||
import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner";
|
import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner";
|
||||||
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
|
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
|
||||||
import { PermissionsTab } from "../components/permission-tab/PermissionTab";
|
import { PermissionsTab } from "../components/permission-tab/PermissionTab";
|
||||||
|
import { RoleForm } from "../components/role-form/RoleForm";
|
||||||
import { AddRoleMappingModal } from "../components/role-mapping/AddRoleMappingModal";
|
import { AddRoleMappingModal } from "../components/role-mapping/AddRoleMappingModal";
|
||||||
import { RoleMapping } from "../components/role-mapping/RoleMapping";
|
import { RoleMapping } from "../components/role-mapping/RoleMapping";
|
||||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||||
|
@ -35,13 +37,13 @@ import { useAdminClient, useFetch } from "../context/auth/AdminClient";
|
||||||
import { useRealm } from "../context/realm-context/RealmContext";
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
import { useParams } from "../utils/useParams";
|
import { useParams } from "../utils/useParams";
|
||||||
import { RealmRoleForm } from "./RealmRoleForm";
|
|
||||||
import {
|
import {
|
||||||
ClientRoleParams,
|
ClientRoleParams,
|
||||||
ClientRoleRoute,
|
ClientRoleRoute,
|
||||||
toClientRole,
|
toClientRole,
|
||||||
} from "./routes/ClientRole";
|
} from "./routes/ClientRole";
|
||||||
import { toRealmRole } from "./routes/RealmRole";
|
import { toRealmRole } from "./routes/RealmRole";
|
||||||
|
import { toRealmRoles } from "./routes/RealmRoles";
|
||||||
import { UsersInRoleTab } from "./UsersInRoleTab";
|
import { UsersInRoleTab } from "./UsersInRoleTab";
|
||||||
|
|
||||||
export default function RealmRoleTabs() {
|
export default function RealmRoleTabs() {
|
||||||
|
@ -49,7 +51,7 @@ export default function RealmRoleTabs() {
|
||||||
const form = useForm<AttributeForm>({
|
const form = useForm<AttributeForm>({
|
||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
const { setValue, getValues, trigger, reset } = form;
|
const { setValue, reset } = form;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { adminClient } = useAdminClient();
|
const { adminClient } = useAdminClient();
|
||||||
|
@ -84,104 +86,67 @@ export default function RealmRoleTabs() {
|
||||||
|
|
||||||
useFetch(
|
useFetch(
|
||||||
async () => {
|
async () => {
|
||||||
const realm = await adminClient.realms.findOne({ realm: realmName });
|
const [realm, role] = await Promise.all([
|
||||||
if (!id) {
|
adminClient.realms.findOne({ realm: realmName }),
|
||||||
return { realm };
|
adminClient.roles.findOneById({ id }),
|
||||||
}
|
]);
|
||||||
const role = await adminClient.roles.findOneById({ id });
|
|
||||||
return { realm, role };
|
return { realm, role };
|
||||||
},
|
},
|
||||||
({ realm, role }) => {
|
({ realm, role }) => {
|
||||||
if (!realm || (!role && id)) {
|
if (!realm || !role) {
|
||||||
throw new Error(t("common:notFound"));
|
throw new Error(t("common:notFound"));
|
||||||
}
|
}
|
||||||
|
|
||||||
setRealm(realm);
|
const convertedRole = convert(role);
|
||||||
|
|
||||||
if (role) {
|
setRealm(realm);
|
||||||
const convertedRole = convert(role);
|
setRole(convertedRole);
|
||||||
setRole(convertedRole);
|
|
||||||
Object.entries(convertedRole).map((entry) => {
|
Object.entries(convertedRole).map((entry) => {
|
||||||
setValue(entry[0], entry[1]);
|
setValue(entry[0], entry[1]);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[key, url]
|
[key, url]
|
||||||
);
|
);
|
||||||
|
|
||||||
const save = async () => {
|
const onSubmit: SubmitHandler<AttributeForm> = async (formValues) => {
|
||||||
try {
|
try {
|
||||||
const values = getValues();
|
|
||||||
if (
|
if (
|
||||||
values.attributes &&
|
formValues.attributes &&
|
||||||
values.attributes[values.attributes.length - 1]?.key === ""
|
formValues.attributes[formValues.attributes.length - 1]?.key === ""
|
||||||
) {
|
) {
|
||||||
setValue(
|
setValue(
|
||||||
"attributes",
|
"attributes",
|
||||||
values.attributes.slice(0, values.attributes.length - 1)
|
formValues.attributes.slice(0, formValues.attributes.length - 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!(await trigger())) {
|
|
||||||
return;
|
const { attributes, ...rest } = formValues;
|
||||||
}
|
|
||||||
const { attributes, ...rest } = values;
|
|
||||||
let roleRepresentation: RoleRepresentation = rest;
|
let roleRepresentation: RoleRepresentation = rest;
|
||||||
|
|
||||||
roleRepresentation.name = roleRepresentation.name?.trim();
|
roleRepresentation.name = roleRepresentation.name?.trim();
|
||||||
|
|
||||||
if (id) {
|
if (attributes) {
|
||||||
if (attributes) {
|
roleRepresentation.attributes = keyValueToArray(attributes);
|
||||||
roleRepresentation.attributes = keyValueToArray(attributes);
|
}
|
||||||
}
|
roleRepresentation = {
|
||||||
roleRepresentation = {
|
...omit(role!, "attributes"),
|
||||||
...omit(role!, "attributes"),
|
...roleRepresentation,
|
||||||
...roleRepresentation,
|
};
|
||||||
};
|
if (!clientId) {
|
||||||
if (!clientId) {
|
await adminClient.roles.updateById({ id }, roleRepresentation);
|
||||||
await adminClient.roles.updateById({ id }, roleRepresentation);
|
|
||||||
} else {
|
|
||||||
await adminClient.clients.updateRole(
|
|
||||||
{ id: clientId, roleName: values.name! },
|
|
||||||
roleRepresentation
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
setRole(convert(roleRepresentation));
|
|
||||||
} else {
|
} else {
|
||||||
let createdRole;
|
await adminClient.clients.updateRole(
|
||||||
if (!clientId) {
|
{ id: clientId, roleName: formValues.name! },
|
||||||
await adminClient.roles.create(roleRepresentation);
|
roleRepresentation
|
||||||
createdRole = await adminClient.roles.findOneByName({
|
|
||||||
name: values.name!,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await adminClient.clients.createRole({
|
|
||||||
id: clientId,
|
|
||||||
name: values.name,
|
|
||||||
});
|
|
||||||
if (values.description) {
|
|
||||||
await adminClient.clients.updateRole(
|
|
||||||
{ id: clientId, roleName: values.name! },
|
|
||||||
roleRepresentation
|
|
||||||
);
|
|
||||||
}
|
|
||||||
createdRole = await adminClient.clients.findRole({
|
|
||||||
id: clientId,
|
|
||||||
roleName: values.name!,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!createdRole) {
|
|
||||||
throw new Error(t("common:notFound"));
|
|
||||||
}
|
|
||||||
|
|
||||||
setRole(convert(createdRole));
|
|
||||||
navigate(
|
|
||||||
url.substr(0, url.lastIndexOf("/") + 1) + createdRole.id + "/details"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
addAlert(t(id ? "roleSaveSuccess" : "roleCreated"), AlertVariant.success);
|
|
||||||
|
setRole(convert(roleRepresentation));
|
||||||
|
addAlert(t("roleSaveSuccess"), AlertVariant.success);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addError(`roles:${id ? "roleSave" : "roleCreate"}Error`, error);
|
addError("roles:roleSaveError", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -199,7 +164,7 @@ export default function RealmRoleTabs() {
|
||||||
} else {
|
} else {
|
||||||
await adminClient.clients.delRole({
|
await adminClient.clients.delRole({
|
||||||
id: clientId,
|
id: clientId,
|
||||||
roleName: role!.name as string,
|
roleName: role!.name!,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addAlert(t("roleDeletedSuccess"), AlertVariant.success);
|
addAlert(t("roleDeletedSuccess"), AlertVariant.success);
|
||||||
|
@ -328,19 +293,9 @@ export default function RealmRoleTabs() {
|
||||||
|
|
||||||
const isDefaultRole = (name: string) => realm?.defaultRole!.name === name;
|
const isDefaultRole = (name: string) => realm?.defaultRole!.name === name;
|
||||||
|
|
||||||
if (!realm) {
|
if (!realm || !role) {
|
||||||
return <KeycloakSpinner />;
|
return <KeycloakSpinner />;
|
||||||
}
|
}
|
||||||
if (!role) {
|
|
||||||
return (
|
|
||||||
<RealmRoleForm
|
|
||||||
reset={() => reset(role)}
|
|
||||||
form={form}
|
|
||||||
save={save}
|
|
||||||
editMode={false}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -356,7 +311,7 @@ export default function RealmRoleTabs() {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ViewHeader
|
<ViewHeader
|
||||||
titleKey={role.name || t("createRole")}
|
titleKey={role.name!}
|
||||||
badges={[
|
badges={[
|
||||||
{
|
{
|
||||||
id: "composite-role-badge",
|
id: "composite-role-badge",
|
||||||
|
@ -364,73 +319,75 @@ export default function RealmRoleTabs() {
|
||||||
readonly: true,
|
readonly: true,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
subKey={id ? "" : "roles:roleCreateExplain"}
|
|
||||||
actionsDropdownId="roles-actions-dropdown"
|
actionsDropdownId="roles-actions-dropdown"
|
||||||
dropdownItems={dropdownItems}
|
dropdownItems={dropdownItems}
|
||||||
divider={!id}
|
divider={false}
|
||||||
/>
|
/>
|
||||||
<PageSection variant="light" className="pf-u-p-0">
|
<PageSection variant="light" className="pf-u-p-0">
|
||||||
{id && (
|
<KeycloakTabs isBox mountOnEnter>
|
||||||
<KeycloakTabs isBox mountOnEnter>
|
<Tab
|
||||||
|
eventKey="details"
|
||||||
|
title={<TabTitleText>{t("common:details")}</TabTitleText>}
|
||||||
|
>
|
||||||
|
<RoleForm
|
||||||
|
form={form}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
role={clientRoleRouteMatch ? "manage-clients" : "manage-realm"}
|
||||||
|
cancelLink={
|
||||||
|
clientRoleRouteMatch
|
||||||
|
? toClient({ realm: realmName, clientId, tab: "roles" })
|
||||||
|
: toRealmRoles({ realm: realmName })
|
||||||
|
}
|
||||||
|
editMode={true}
|
||||||
|
/>
|
||||||
|
</Tab>
|
||||||
|
{role.composite && (
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="details"
|
eventKey="associated-roles"
|
||||||
title={<TabTitleText>{t("common:details")}</TabTitleText>}
|
className="kc-associated-roles-tab"
|
||||||
|
title={<TabTitleText>{t("associatedRolesText")}</TabTitleText>}
|
||||||
>
|
>
|
||||||
<RealmRoleForm
|
<RoleMapping
|
||||||
reset={() => reset(role)}
|
name={role.name!}
|
||||||
form={form}
|
id={role.id!}
|
||||||
save={save}
|
type="roles"
|
||||||
editMode={true}
|
isManager
|
||||||
|
save={(rows) => addComposites(rows.map((r) => r.role))}
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
{role.composite && (
|
)}
|
||||||
<Tab
|
{!isDefaultRole(role.name!) && (
|
||||||
eventKey="associated-roles"
|
<Tab
|
||||||
className="kc-associated-roles-tab"
|
eventKey="attributes"
|
||||||
title={<TabTitleText>{t("associatedRolesText")}</TabTitleText>}
|
className="kc-attributes-tab"
|
||||||
>
|
title={<TabTitleText>{t("common:attributes")}</TabTitleText>}
|
||||||
<RoleMapping
|
>
|
||||||
name={role.name!}
|
<AttributesForm
|
||||||
id={role.id!}
|
form={form}
|
||||||
type="roles"
|
save={onSubmit}
|
||||||
isManager
|
reset={() => reset(role)}
|
||||||
save={(rows) => addComposites(rows.map((r) => r.role))}
|
/>
|
||||||
/>
|
</Tab>
|
||||||
</Tab>
|
)}
|
||||||
)}
|
{!isDefaultRole(role.name!) && (
|
||||||
{!isDefaultRole(role.name!) && (
|
<Tab
|
||||||
<Tab
|
eventKey="users-in-role"
|
||||||
eventKey="attributes"
|
title={<TabTitleText>{t("usersInRole")}</TabTitleText>}
|
||||||
className="kc-attributes-tab"
|
>
|
||||||
title={<TabTitleText>{t("common:attributes")}</TabTitleText>}
|
<UsersInRoleTab data-cy="users-in-role-tab" />
|
||||||
>
|
</Tab>
|
||||||
<AttributesForm
|
)}
|
||||||
form={form}
|
{!profileInfo?.disabledFeatures?.includes(
|
||||||
save={save}
|
"ADMIN_FINE_GRAINED_AUTHZ"
|
||||||
reset={() => reset(role)}
|
) && (
|
||||||
/>
|
<Tab
|
||||||
</Tab>
|
eventKey="permissions"
|
||||||
)}
|
title={<TabTitleText>{t("common:permissions")}</TabTitleText>}
|
||||||
{!isDefaultRole(role.name!) && (
|
>
|
||||||
<Tab
|
<PermissionsTab id={role.id} type="roles" />
|
||||||
eventKey="users-in-role"
|
</Tab>
|
||||||
title={<TabTitleText>{t("usersInRole")}</TabTitleText>}
|
)}
|
||||||
>
|
</KeycloakTabs>
|
||||||
<UsersInRoleTab data-cy="users-in-role-tab" />
|
|
||||||
</Tab>
|
|
||||||
)}
|
|
||||||
{!profileInfo?.disabledFeatures?.includes(
|
|
||||||
"ADMIN_FINE_GRAINED_AUTHZ"
|
|
||||||
) && (
|
|
||||||
<Tab
|
|
||||||
eventKey="permissions"
|
|
||||||
title={<TabTitleText>{t("common:permissions")}</TabTitleText>}
|
|
||||||
>
|
|
||||||
<PermissionsTab id={role.id} type="roles" />
|
|
||||||
</Tab>
|
|
||||||
)}
|
|
||||||
</KeycloakTabs>
|
|
||||||
)}
|
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -116,7 +116,7 @@ export const RolesList = ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const goToCreate = () => navigate(`${url}/add-role`);
|
const goToCreate = () => navigate(`${url}/new`);
|
||||||
|
|
||||||
if (!realm) {
|
if (!realm) {
|
||||||
return <KeycloakSpinner />;
|
return <KeycloakSpinner />;
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import type { RouteDef } from "../route-config";
|
import type { RouteDef } from "../route-config";
|
||||||
import { AddRoleRoute } from "./routes/AddRole";
|
import { AddRoleRoute } from "./routes/AddRole";
|
||||||
import { AddRoleToClientRoute } from "./routes/AddRoleToClient";
|
|
||||||
import { ClientRoleRoute, ClientRoleRouteWithTab } from "./routes/ClientRole";
|
import { ClientRoleRoute, ClientRoleRouteWithTab } from "./routes/ClientRole";
|
||||||
import { RealmRoleRoute, RealmRoleRouteWithTab } from "./routes/RealmRole";
|
import { RealmRoleRoute, RealmRoleRouteWithTab } from "./routes/RealmRole";
|
||||||
import { RealmRolesRoute } from "./routes/RealmRoles";
|
import { RealmRolesRoute } from "./routes/RealmRoles";
|
||||||
|
|
||||||
const routes: RouteDef[] = [
|
const routes: RouteDef[] = [
|
||||||
AddRoleToClientRoute,
|
|
||||||
ClientRoleRoute,
|
ClientRoleRoute,
|
||||||
ClientRoleRouteWithTab,
|
ClientRoleRouteWithTab,
|
||||||
RealmRolesRoute,
|
RealmRolesRoute,
|
||||||
|
|
|
@ -6,8 +6,8 @@ import type { RouteDef } from "../../route-config";
|
||||||
export type AddRoleParams = { realm: string };
|
export type AddRoleParams = { realm: string };
|
||||||
|
|
||||||
export const AddRoleRoute: RouteDef = {
|
export const AddRoleRoute: RouteDef = {
|
||||||
path: "/:realm/roles/add-role",
|
path: "/:realm/roles/new",
|
||||||
component: lazy(() => import("../RealmRoleTabs")),
|
component: lazy(() => import("../CreateRealmRole")),
|
||||||
breadcrumb: (t) => t("roles:createRole"),
|
breadcrumb: (t) => t("roles:createRole"),
|
||||||
access: "manage-realm",
|
access: "manage-realm",
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { lazy } from "react";
|
|
||||||
import type { Path } from "react-router-dom-v5-compat";
|
|
||||||
import { generatePath } from "react-router-dom-v5-compat";
|
|
||||||
import type { RouteDef } from "../../route-config";
|
|
||||||
|
|
||||||
export type AddRoleToClientParams = {
|
|
||||||
realm: string;
|
|
||||||
clientId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AddRoleToClientRoute: RouteDef = {
|
|
||||||
path: "/:realm/clients/:clientId/roles/add-role",
|
|
||||||
component: lazy(() => import("../RealmRoleTabs")),
|
|
||||||
breadcrumb: (t) => t("roles:createRole"),
|
|
||||||
access: "manage-realm",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const toAddRoleToClient = (
|
|
||||||
params: AddRoleToClientParams
|
|
||||||
): Partial<Path> => ({
|
|
||||||
pathname: generatePath(AddRoleToClientRoute.path, params),
|
|
||||||
});
|
|
Loading…
Reference in a new issue