added user role mapping tab to user details (#1075)
* added user role mapping tab to user details * fix imports to admin client * Update src/user/UserRoleMapping.tsx Co-authored-by: Jon Koops <jonkoops@gmail.com> * Update src/user/UserRoleMapping.tsx Co-authored-by: Jon Koops <jonkoops@gmail.com> * added await * fixed merge error Co-authored-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
parent
f87463d036
commit
e187314b1f
7 changed files with 115 additions and 7 deletions
|
@ -1,6 +1,5 @@
|
|||
export default {
|
||||
groups: {
|
||||
groups: "Groups",
|
||||
groupDetails: "Group details",
|
||||
childGroups: "Child groups",
|
||||
createGroup: "Create group",
|
||||
|
|
|
@ -61,7 +61,7 @@ export const UsersInRoleTab = () => {
|
|||
variant="link"
|
||||
onClick={() => history.push(`/${realm}/groups`)}
|
||||
>
|
||||
{t("groups")}
|
||||
{t("common:groups")}
|
||||
</Button>
|
||||
{t("or")}
|
||||
<Button
|
||||
|
@ -98,7 +98,7 @@ export const UsersInRoleTab = () => {
|
|||
variant="link"
|
||||
onClick={() => history.push(`/${realm}/groups`)}
|
||||
>
|
||||
{t("groups")}
|
||||
{t("common:groups")}
|
||||
</Button>
|
||||
{t("or")}
|
||||
<Button
|
||||
|
|
|
@ -72,7 +72,6 @@ export default {
|
|||
"Only the users with this role directly assigned will appear under this tab. If you need to find users assigned to this role, go to",
|
||||
noUsersEmptyStateDescriptionContinued:
|
||||
"to find them. Users that already have this role as an effective role cannot be added here.",
|
||||
groups: "Groups",
|
||||
or: "or",
|
||||
users: "Users",
|
||||
userName: "Username",
|
||||
|
|
|
@ -310,7 +310,7 @@ export const KeysTabInner = ({ components, refresh }: KeysTabInnerProps) => {
|
|||
</ToolbarGroup>
|
||||
</Toolbar>
|
||||
<DataList
|
||||
aria-label={t("groups")}
|
||||
aria-label={t("common:groups")}
|
||||
onDragFinish={onDragFinish}
|
||||
onDragStart={onDragStart}
|
||||
onDragMove={onDragMove}
|
||||
|
|
101
src/user/UserRoleMapping.tsx
Normal file
101
src/user/UserRoleMapping.tsx
Normal file
|
@ -0,0 +1,101 @@
|
|||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AlertVariant } from "@patternfly/react-core";
|
||||
|
||||
import type { RoleMappingPayload } from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import {
|
||||
mapRoles,
|
||||
RoleMapping,
|
||||
Row,
|
||||
} from "../components/role-mapping/RoleMapping";
|
||||
|
||||
type UserRoleMappingProps = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const UserRoleMapping = ({ id, name }: UserRoleMappingProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
const adminClient = useAdminClient();
|
||||
const { addAlert, addError } = useAlerts();
|
||||
|
||||
const [hide, setHide] = useState(false);
|
||||
|
||||
const loader = async () => {
|
||||
const [assignedRoles, effectiveRoles] = await Promise.all([
|
||||
adminClient.users
|
||||
.listRealmRoleMappings({ id })
|
||||
.then((roles) => roles.map((role) => ({ role }))),
|
||||
adminClient.users
|
||||
.listCompositeRealmRoleMappings({ id })
|
||||
.then((roles) => roles.map((role) => ({ role }))),
|
||||
]);
|
||||
|
||||
const clients = await adminClient.clients.find();
|
||||
const clientRoles = (
|
||||
await Promise.all(
|
||||
clients.map(async (client) => {
|
||||
const [clientAssignedRoles, clientEffectiveRoles] = await Promise.all(
|
||||
[
|
||||
adminClient.users
|
||||
.listClientRoleMappings({
|
||||
id,
|
||||
clientUniqueId: client.id!,
|
||||
})
|
||||
.then((roles) => roles.map((role) => ({ role, client }))),
|
||||
adminClient.users
|
||||
.listCompositeClientRoleMappings({
|
||||
id,
|
||||
clientUniqueId: client.id!,
|
||||
})
|
||||
.then((roles) => roles.map((role) => ({ role, client }))),
|
||||
]
|
||||
);
|
||||
return mapRoles(clientAssignedRoles, clientEffectiveRoles, hide);
|
||||
})
|
||||
)
|
||||
).flat();
|
||||
|
||||
return [...mapRoles(assignedRoles, effectiveRoles, hide), ...clientRoles];
|
||||
};
|
||||
|
||||
const assignRoles = async (rows: Row[]) => {
|
||||
try {
|
||||
const realmRoles = rows
|
||||
.filter((row) => row.client === undefined)
|
||||
.map((row) => row.role as RoleMappingPayload)
|
||||
.flat();
|
||||
await adminClient.users.addRealmRoleMappings({
|
||||
id,
|
||||
roles: realmRoles,
|
||||
});
|
||||
await Promise.all(
|
||||
rows
|
||||
.filter((row) => row.client !== undefined)
|
||||
.map((row) =>
|
||||
adminClient.users.addClientRoleMappings({
|
||||
id,
|
||||
clientUniqueId: row.client!.id!,
|
||||
roles: [row.role as RoleMappingPayload],
|
||||
})
|
||||
)
|
||||
);
|
||||
addAlert(t("roleMappingUpdatedSuccess"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addError("clients:roleMappingUpdatedError", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<RoleMapping
|
||||
name={name}
|
||||
id={id}
|
||||
type="service-account"
|
||||
loader={loader}
|
||||
save={assignRoles}
|
||||
onHideRolesToggle={() => setHide(!hide)}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -25,6 +25,7 @@ import { UserIdentityProviderLinks } from "./UserIdentityProviderLinks";
|
|||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||
import { toUser } from "./routes/User";
|
||||
import { toUsers } from "./routes/Users";
|
||||
import { UserRoleMapping } from "./UserRoleMapping";
|
||||
|
||||
export const UsersTabs = () => {
|
||||
const { t } = useTranslation("users");
|
||||
|
@ -89,7 +90,7 @@ export const UsersTabs = () => {
|
|||
history.push(toUser({ id: createdUser.id, realm, tab: "settings" }));
|
||||
}
|
||||
} catch (error) {
|
||||
addError("users:userCreateError", error);
|
||||
addError("userCreateError", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -135,7 +136,7 @@ export const UsersTabs = () => {
|
|||
<ImpersonateConfirm />
|
||||
<DeleteConfirm />
|
||||
<ViewHeader
|
||||
titleKey={user?.username || t("users:createUser")}
|
||||
titleKey={user?.username || t("createUser")}
|
||||
divider={!id}
|
||||
dropdownItems={[
|
||||
<DropdownItem
|
||||
|
@ -183,6 +184,13 @@ export const UsersTabs = () => {
|
|||
>
|
||||
<UserConsents />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="role-mapping"
|
||||
data-testid="role-mapping-tab"
|
||||
title={<TabTitleText>{t("roleMapping")}</TabTitleText>}
|
||||
>
|
||||
<UserRoleMapping id={id} name={user.username!} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="identity-provider-links"
|
||||
data-testid="identity-provider-links-tab"
|
||||
|
|
|
@ -106,6 +106,7 @@ export default {
|
|||
"Are you sure you want to revoke all granted client scopes for {{clientId}}?",
|
||||
deleteGrantsSuccess: "Grants successfully revoked.",
|
||||
deleteGrantsError: "Error deleting grants.",
|
||||
roleMapping: "Role mapping",
|
||||
unlockAllUsers: "Unlock all users",
|
||||
unlockUsersConfirm:
|
||||
"All the users that are temporarily locked will be unlocked.",
|
||||
|
|
Loading…
Reference in a new issue