Allow view client roles tab without view-realm access (#21142)

* Allow view client->roles tab with view-clients access.
Fixes #21047

* Fix role deleted success message.
This commit is contained in:
Stan Silvert 2023-06-23 07:04:37 -04:00 committed by GitHub
parent 7fe7dfc529
commit 080b6a7981
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 34 deletions

View file

@ -23,7 +23,7 @@ export const ClientRoleRoute: AppRouteObject = {
element: <RealmRoleTabs />, element: <RealmRoleTabs />,
breadcrumb: (t) => t("roles:roleDetails"), breadcrumb: (t) => t("roles:roleDetails"),
handle: { handle: {
access: "view-realm", access: "view-clients",
}, },
} satisfies AppRouteObject; } satisfies AppRouteObject;

View file

@ -11,6 +11,7 @@ import { FilterIcon } from "@patternfly/react-icons";
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAccess } from "../../context/access/Access";
import useLocaleSort from "../../utils/useLocaleSort"; import useLocaleSort from "../../utils/useLocaleSort";
import { ListEmptyState } from "../list-empty-state/ListEmptyState"; import { ListEmptyState } from "../list-empty-state/ListEmptyState";
import { KeycloakDataTable } from "../table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../table-toolbar/KeycloakDataTable";
@ -40,10 +41,14 @@ export const AddRoleMappingModal = ({
onClose, onClose,
}: AddRoleMappingModalProps) => { }: AddRoleMappingModalProps) => {
const { t } = useTranslation(type); const { t } = useTranslation(type);
const { hasAccess } = useAccess();
const canViewRealmRoles = hasAccess("view-realm");
const [searchToggle, setSearchToggle] = useState(false); const [searchToggle, setSearchToggle] = useState(false);
const [filterType, setFilterType] = useState<FilterType>("roles"); const [filterType, setFilterType] = useState<FilterType>(
canViewRealmRoles ? "roles" : "clients"
);
const [selectedRows, setSelectedRows] = useState<Row[]>([]); const [selectedRows, setSelectedRows] = useState<Row[]>([]);
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const refresh = () => setKey(key + 1); const refresh = () => setKey(key + 1);
@ -137,34 +142,36 @@ export const AddRoleMappingModal = ({
searchPlaceholderKey="clients:searchByRoleName" searchPlaceholderKey="clients:searchByRoleName"
isPaginated={!(filterType === "roles" && type !== "roles")} isPaginated={!(filterType === "roles" && type !== "roles")}
searchTypeComponent={ searchTypeComponent={
<ToolbarItem> canViewRealmRoles && (
<Dropdown <ToolbarItem>
onSelect={() => { <Dropdown
setFilterType(filterType === "roles" ? "clients" : "roles"); onSelect={() => {
setSearchToggle(false); setFilterType(filterType === "roles" ? "clients" : "roles");
refresh(); setSearchToggle(false);
}} refresh();
data-testid="filter-type-dropdown" }}
toggle={ data-testid="filter-type-dropdown"
<DropdownToggle toggle={
onToggle={setSearchToggle} <DropdownToggle
icon={<FilterIcon />} onToggle={setSearchToggle}
> icon={<FilterIcon />}
{filterType === "roles" >
? t("common:filterByRoles") {filterType === "roles"
: t("common:filterByClients")} ? t("common:filterByRoles")
</DropdownToggle> : t("common:filterByClients")}
} </DropdownToggle>
isOpen={searchToggle} }
dropdownItems={[ isOpen={searchToggle}
<DropdownItem key="filter-type" data-testid={filterType}> dropdownItems={[
{filterType === "roles" <DropdownItem key="filter-type" data-testid={filterType}>
? t("common:filterByClients") {filterType === "roles"
: t("common:filterByRoles")} ? t("common:filterByClients")
</DropdownItem>, : t("common:filterByRoles")}
]} </DropdownItem>,
/> ]}
</ToolbarItem> />
</ToolbarItem>
)
} }
canSelectAll canSelectAll
isRadio={isRadio} isRadio={isRadio}

View file

@ -33,7 +33,6 @@ const RoleDetailLink = ({
}: RoleDetailLinkProps) => { }: RoleDetailLinkProps) => {
const { t } = useTranslation(messageBundle); const { t } = useTranslation(messageBundle);
const { realm } = useRealm(); const { realm } = useRealm();
return role.name !== defaultRoleName ? ( return role.name !== defaultRoleName ? (
<Link to={toDetail(role.id!)}>{role.name}</Link> <Link to={toDetail(role.id!)}>{role.name}</Link>
) : ( ) : (
@ -107,7 +106,7 @@ export const RolesList = ({
]); ]);
} }
setSelectedRole(undefined); setSelectedRole(undefined);
addAlert(t("roleDeletedSuccess"), AlertVariant.success); addAlert(t("roles:roleDeletedSuccess"), AlertVariant.success);
} catch (error) { } catch (error) {
addError("roles:roleDeleteError", error); addError("roles:roleDeleteError", error);
} }
@ -145,7 +144,10 @@ export const RolesList = ({
title: t("common:delete"), title: t("common:delete"),
onRowClick: (role) => { onRowClick: (role) => {
setSelectedRole(role); setSelectedRole(role);
if (role.name === realm!.defaultRole!.name) { if (
realm!.defaultRole &&
role.name === realm!.defaultRole!.name
) {
addAlert( addAlert(
t("defaultRoleDeleteError"), t("defaultRoleDeleteError"),
AlertVariant.danger AlertVariant.danger

View file

@ -300,7 +300,7 @@ export default function RealmRoleTabs() {
}; };
const isDefaultRole = (name: string | undefined) => const isDefaultRole = (name: string | undefined) =>
realm?.defaultRole!.name === name; realm?.defaultRole && realm.defaultRole!.name === name;
if (!realm) { if (!realm) {
return <KeycloakSpinner />; return <KeycloakSpinner />;