mirror of
https://github.com/keycloak/keycloak.git
synced 2026-05-28 04:13:22 -04:00
moved filter to dropdown (#36711)
* moved filter to dropdown fixes: #36635 Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixing tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed more tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * PR review comments Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> --------- Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
parent
f475646b87
commit
bbbd0ff986
21 changed files with 228 additions and 213 deletions
|
|
@ -505,7 +505,7 @@ eventTypes.CLIENT_LOGIN.name=Client login
|
|||
mapper.nameid.format.tooltip=This mapper is applied only if the NameID format of the incoming AuthnRequest is equal to this value.
|
||||
hideOnLoginPageHelp=If hidden, login with this provider is possible only if requested explicitly, for example using the 'kc_idp_hint' parameter.
|
||||
eventTypes.UPDATE_PROFILE.description=Update profile
|
||||
assignRolesTo=Assign roles to {{client}}
|
||||
assignRolesTo=Assign {{type}} roles to {{client}}
|
||||
orderChangeError=Could not change display order of identity providers {{error}}
|
||||
policyProvider.client-scope=Define conditions for your permissions where a set of one or more client scopes is permitted to access an object.
|
||||
secretExpiresOn=Secret expires on {{time}}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ import { Controller, useFormContext } from "react-hook-form";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { useAdminClient } from "../../../admin-client";
|
||||
import { DefaultSwitchControl } from "../../../components/SwitchControl";
|
||||
import { AddRoleMappingModal } from "../../../components/role-mapping/AddRoleMappingModal";
|
||||
import {
|
||||
AddRoleButton,
|
||||
AddRoleMappingModal,
|
||||
FilterType,
|
||||
} from "../../../components/role-mapping/AddRoleMappingModal";
|
||||
import { Row, ServiceRole } from "../../../components/role-mapping/RoleMapping";
|
||||
import type { RequiredIdValue } from "./ClientScope";
|
||||
|
||||
|
|
@ -22,6 +26,8 @@ export const Role = () => {
|
|||
const values = getValues("roles");
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [filterType, setFilterType] = useState<FilterType>("clients");
|
||||
|
||||
const [selectedRoles, setSelectedRoles] = useState<Row[]>([]);
|
||||
|
||||
useFetch(
|
||||
|
|
@ -67,6 +73,7 @@ export const Role = () => {
|
|||
id="role"
|
||||
type="roles"
|
||||
title={t("assignRole")}
|
||||
filterType={filterType}
|
||||
onAssign={(rows) => {
|
||||
field.onChange([
|
||||
...(field.value || []),
|
||||
|
|
@ -80,15 +87,14 @@ export const Role = () => {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
<AddRoleButton
|
||||
data-testid="select-role-button"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
onFilerTypeChange={(type) => {
|
||||
setFilterType(type);
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("addRoles")}
|
||||
</Button>
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import { FormErrorText, HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
Button,
|
||||
Chip,
|
||||
FormGroup,
|
||||
Split,
|
||||
SplitItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { Chip, FormGroup, Split, SplitItem } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import { AddRoleMappingModal } from "../role-mapping/AddRoleMappingModal";
|
||||
import {
|
||||
AddRoleButton,
|
||||
AddRoleMappingModal,
|
||||
FilterType,
|
||||
} from "../role-mapping/AddRoleMappingModal";
|
||||
import { Row, ServiceRole } from "../role-mapping/RoleMapping";
|
||||
import type { ComponentProps } from "./components";
|
||||
|
||||
|
|
@ -33,6 +32,8 @@ export const RoleComponent = ({
|
|||
const { t } = useTranslation();
|
||||
|
||||
const [openModal, toggleModal] = useToggle();
|
||||
const [filterType, setFilterType] = useState<FilterType>("clients");
|
||||
|
||||
const {
|
||||
control,
|
||||
formState: { errors },
|
||||
|
|
@ -57,6 +58,7 @@ export const RoleComponent = ({
|
|||
<AddRoleMappingModal
|
||||
id="id"
|
||||
type="roles"
|
||||
filterType={filterType}
|
||||
name={name}
|
||||
onAssign={(rows) => field.onChange(parseRow(rows[0]))}
|
||||
onClose={toggleModal}
|
||||
|
|
@ -75,14 +77,16 @@ export const RoleComponent = ({
|
|||
</SplitItem>
|
||||
)}
|
||||
<SplitItem>
|
||||
<Button
|
||||
onClick={toggleModal}
|
||||
<AddRoleButton
|
||||
label="selectRole.label"
|
||||
onFilerTypeChange={(type) => {
|
||||
setFilterType(type);
|
||||
toggleModal();
|
||||
}}
|
||||
variant="secondary"
|
||||
data-testid="add-roles"
|
||||
disabled={isDisabled}
|
||||
>
|
||||
{t("selectRole.label")}
|
||||
</Button>
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@ import {
|
|||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
DropdownProps,
|
||||
MenuToggle,
|
||||
Modal,
|
||||
ModalVariant,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { FilterIcon } from "@patternfly/react-icons";
|
||||
import { cellWidth, TableText } from "@patternfly/react-table";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
@ -21,13 +20,15 @@ import { useAdminClient } from "../../admin-client";
|
|||
import { useAccess } from "../../context/access/Access";
|
||||
import { translationFormatter } from "../../utils/translationFormatter";
|
||||
import useLocaleSort from "../../utils/useLocaleSort";
|
||||
import { ResourcesKey, Row, ServiceRole } from "./RoleMapping";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import { ResourcesKey, Row } from "./RoleMapping";
|
||||
import { getAvailableRoles } from "./queries";
|
||||
import { getAvailableClientRoles } from "./resource";
|
||||
|
||||
type AddRoleMappingModalProps = {
|
||||
id: string;
|
||||
type: ResourcesKey;
|
||||
filterType: FilterType;
|
||||
name?: string;
|
||||
isRadio?: boolean;
|
||||
onAssign: (rows: Row[]) => void;
|
||||
|
|
@ -36,7 +37,7 @@ type AddRoleMappingModalProps = {
|
|||
actionLabel?: string;
|
||||
};
|
||||
|
||||
type FilterType = "roles" | "clients";
|
||||
export type FilterType = "roles" | "clients";
|
||||
|
||||
const RoleDescription = ({ role }: { role: RoleRepresentation }) => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -47,11 +48,78 @@ const RoleDescription = ({ role }: { role: RoleRepresentation }) => {
|
|||
);
|
||||
};
|
||||
|
||||
type AddRoleButtonProps = Omit<
|
||||
DropdownProps,
|
||||
"children" | "toggle" | "isOpen" | "onOpenChange"
|
||||
> & {
|
||||
label?: string;
|
||||
variant?: "default" | "plain" | "primary" | "plainText" | "secondary";
|
||||
isDisabled?: boolean;
|
||||
onFilerTypeChange: (type: FilterType) => void;
|
||||
};
|
||||
|
||||
export const AddRoleButton = ({
|
||||
label,
|
||||
variant,
|
||||
isDisabled,
|
||||
onFilerTypeChange,
|
||||
...rest
|
||||
}: AddRoleButtonProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [open, toggle] = useToggle();
|
||||
|
||||
const { hasAccess } = useAccess();
|
||||
const canViewRealmRoles = hasAccess("view-realm") || hasAccess("query-users");
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
onOpenChange={toggle}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={toggle}
|
||||
variant={variant || "primary"}
|
||||
isDisabled={isDisabled}
|
||||
data-testid="add-role-mapping-button"
|
||||
>
|
||||
{t(label || "assignRole")}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={open}
|
||||
{...rest}
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
data-testid="client-role"
|
||||
component="button"
|
||||
onClick={() => {
|
||||
onFilerTypeChange("clients");
|
||||
}}
|
||||
>
|
||||
{t("clientRoles")}
|
||||
</DropdownItem>
|
||||
{canViewRealmRoles && (
|
||||
<DropdownItem
|
||||
data-testid="roles-role"
|
||||
component="button"
|
||||
onClick={() => {
|
||||
onFilerTypeChange("roles");
|
||||
}}
|
||||
>
|
||||
{t("realmRoles")}
|
||||
</DropdownItem>
|
||||
)}
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
export const AddRoleMappingModal = ({
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
isRadio,
|
||||
filterType,
|
||||
onAssign,
|
||||
onClose,
|
||||
title,
|
||||
|
|
@ -60,15 +128,7 @@ export const AddRoleMappingModal = ({
|
|||
const { adminClient } = useAdminClient();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { hasAccess } = useAccess();
|
||||
const canViewRealmRoles = hasAccess("view-realm") || hasAccess("query-users");
|
||||
|
||||
const [searchToggle, setSearchToggle] = useState(false);
|
||||
|
||||
const [filterType, setFilterType] = useState<FilterType>("clients");
|
||||
const [selectedRows, setSelectedRows] = useState<Row[]>([]);
|
||||
const [key, setKey] = useState(0);
|
||||
const refresh = () => setKey(key + 1);
|
||||
|
||||
const localeSort = useLocaleSort();
|
||||
const compareRow = ({ role: { name } }: Row) => name?.toUpperCase();
|
||||
|
|
@ -120,10 +180,37 @@ export const AddRoleMappingModal = ({
|
|||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "role.name",
|
||||
displayKey: "name",
|
||||
transforms: [cellWidth(30)],
|
||||
},
|
||||
{
|
||||
name: "client.clientId",
|
||||
displayKey: "clientId",
|
||||
},
|
||||
{
|
||||
name: "role.description",
|
||||
displayKey: "description",
|
||||
cellRenderer: RoleDescription,
|
||||
},
|
||||
];
|
||||
|
||||
if (filterType === "roles") {
|
||||
columns.splice(1, 1);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
variant={ModalVariant.large}
|
||||
title={title || t("assignRolesTo", { client: name })}
|
||||
title={
|
||||
title ||
|
||||
t("assignRolesTo", {
|
||||
type: filterType === "roles" ? t("realm") : t("client"),
|
||||
client: name,
|
||||
})
|
||||
}
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
actions={[
|
||||
|
|
@ -150,74 +237,20 @@ export const AddRoleMappingModal = ({
|
|||
]}
|
||||
>
|
||||
<KeycloakDataTable
|
||||
key={key}
|
||||
onSelect={(rows) => setSelectedRows([...rows])}
|
||||
searchPlaceholderKey="searchByRoleName"
|
||||
isPaginated={!(filterType === "roles" && type !== "roles")}
|
||||
searchTypeComponent={
|
||||
canViewRealmRoles && (
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
onOpenChange={(isOpen) => setSearchToggle(isOpen)}
|
||||
onSelect={() => {
|
||||
setFilterType(filterType === "roles" ? "clients" : "roles");
|
||||
setSearchToggle(false);
|
||||
refresh();
|
||||
}}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="filter-type-dropdown"
|
||||
ref={ref}
|
||||
onClick={() => setSearchToggle(!searchToggle)}
|
||||
icon={<FilterIcon />}
|
||||
>
|
||||
{filterType === "roles"
|
||||
? t("filterByRoles")
|
||||
: t("filterByClients")}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={searchToggle}
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem key="filter-type" data-testid={filterType}>
|
||||
{filterType === "roles"
|
||||
? t("filterByClients")
|
||||
: t("filterByRoles")}
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
)
|
||||
searchPlaceholderKey={
|
||||
filterType === "roles" ? "searchByRoleName" : "search"
|
||||
}
|
||||
isPaginated={!(filterType === "roles" && type !== "roles")}
|
||||
canSelectAll
|
||||
isRadio={isRadio}
|
||||
loader={filterType === "roles" ? loader : clientRolesLoader}
|
||||
ariaLabelKey="associatedRolesText"
|
||||
columns={[
|
||||
{
|
||||
name: "name",
|
||||
cellRenderer: ServiceRole,
|
||||
transforms: [cellWidth(30)],
|
||||
},
|
||||
{
|
||||
name: "role.description",
|
||||
displayKey: "description",
|
||||
cellRenderer: RoleDescription,
|
||||
},
|
||||
]}
|
||||
columns={columns}
|
||||
emptyState={
|
||||
<ListEmptyState
|
||||
message={t("noRoles")}
|
||||
instructions={t("noRealmRolesToAssign")}
|
||||
secondaryActions={[
|
||||
{
|
||||
text: t("filterByRoles"),
|
||||
onClick: () => {
|
||||
setFilterType("roles");
|
||||
refresh();
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ import { translationFormatter } from "../../utils/translationFormatter";
|
|||
import { useConfirmDialog } from "../confirm-dialog/ConfirmDialog";
|
||||
import { ListEmptyState } from "@keycloak/keycloak-ui-shared";
|
||||
import { Action, KeycloakDataTable } from "@keycloak/keycloak-ui-shared";
|
||||
import { AddRoleMappingModal } from "./AddRoleMappingModal";
|
||||
import {
|
||||
AddRoleButton,
|
||||
AddRoleMappingModal,
|
||||
FilterType,
|
||||
} from "./AddRoleMappingModal";
|
||||
import { deleteMapping, getEffectiveRoles, getMapping } from "./queries";
|
||||
import { getEffectiveClientRoles } from "./resource";
|
||||
|
||||
|
|
@ -99,6 +103,7 @@ export const RoleMapping = ({
|
|||
|
||||
const [hide, setHide] = useState(true);
|
||||
const [showAssign, setShowAssign] = useState(false);
|
||||
const [filterType, setFilterType] = useState<FilterType>("clients");
|
||||
const [selected, setSelected] = useState<Row[]>([]);
|
||||
|
||||
const assignRoles = async (rows: Row[]) => {
|
||||
|
|
@ -179,6 +184,7 @@ export const RoleMapping = ({
|
|||
<AddRoleMappingModal
|
||||
id={id}
|
||||
type={type}
|
||||
filterType={filterType}
|
||||
name={name}
|
||||
onAssign={assignRoles}
|
||||
onClose={() => setShowAssign(false)}
|
||||
|
|
@ -213,12 +219,12 @@ export const RoleMapping = ({
|
|||
{isManager && (
|
||||
<>
|
||||
<ToolbarItem>
|
||||
<Button
|
||||
data-testid="assignRole"
|
||||
onClick={() => setShowAssign(true)}
|
||||
>
|
||||
{t("assignRole")}
|
||||
</Button>
|
||||
<AddRoleButton
|
||||
onFilerTypeChange={(type) => {
|
||||
setFilterType(type);
|
||||
setShowAssign(true);
|
||||
}}
|
||||
/>
|
||||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Button
|
||||
|
|
@ -270,8 +276,6 @@ export const RoleMapping = ({
|
|||
<ListEmptyState
|
||||
message={t(`noRoles-${type}`)}
|
||||
instructions={t(`noRolesInstructions-${type}`)}
|
||||
primaryActionText={t("assignRole")}
|
||||
onPrimaryAction={() => setShowAssign(true)}
|
||||
secondaryActions={[
|
||||
{
|
||||
text: t("showInheritedRoles"),
|
||||
|
|
@ -281,7 +285,14 @@ export const RoleMapping = ({
|
|||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
>
|
||||
<AddRoleButton
|
||||
onFilerTypeChange={(type) => {
|
||||
setFilterType(type);
|
||||
setShowAssign(true);
|
||||
}}
|
||||
/>
|
||||
</ListEmptyState>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
import { useState } from "react";
|
||||
import { Button, FormGroup } from "@patternfly/react-core";
|
||||
import { MinusCircleIcon } from "@patternfly/react-icons";
|
||||
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import {
|
||||
FormErrorText,
|
||||
HelpItem,
|
||||
useFetch,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { AddRoleMappingModal } from "../../components/role-mapping/AddRoleMappingModal";
|
||||
import { Button, FormGroup } from "@patternfly/react-core";
|
||||
import { MinusCircleIcon } from "@patternfly/react-icons";
|
||||
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
|
||||
import { useState } from "react";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import {
|
||||
AddRoleButton,
|
||||
AddRoleMappingModal,
|
||||
FilterType,
|
||||
} from "../../components/role-mapping/AddRoleMappingModal";
|
||||
import { Row, ServiceRole } from "../../components/role-mapping/RoleMapping";
|
||||
|
||||
type RoleSelectorProps = {
|
||||
|
|
@ -29,6 +33,7 @@ export const RoleSelect = ({ name, isRadio = false }: RoleSelectorProps) => {
|
|||
const values = getValues(name) || [];
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [selectedRoles, setSelectedRoles] = useState<Row[]>([]);
|
||||
const [filterType, setFilterType] = useState<FilterType>("clients");
|
||||
|
||||
useFetch(
|
||||
async () => {
|
||||
|
|
@ -82,15 +87,18 @@ export const RoleSelect = ({ name, isRadio = false }: RoleSelectorProps) => {
|
|||
setIsModalOpen(false);
|
||||
}}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
filterType={filterType}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
<AddRoleButton
|
||||
label={isRadio ? t("selectRole") : t("addRoles")}
|
||||
data-testid="select-role-button"
|
||||
variant="secondary"
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
>
|
||||
{isRadio ? t("selectRole") : t("addRoles")}
|
||||
</Button>
|
||||
onFilerTypeChange={(type) => {
|
||||
setFilterType(type);
|
||||
setIsModalOpen(true);
|
||||
}}
|
||||
/>
|
||||
{selectedRoles.length > 0 && (
|
||||
<Table variant="compact">
|
||||
<Thead>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||
import { useAlerts, useFetch } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
KeycloakSpinner,
|
||||
useAlerts,
|
||||
useFetch,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
AlertVariant,
|
||||
ButtonVariant,
|
||||
|
|
@ -35,10 +39,8 @@ import {
|
|||
arrayToKeyValue,
|
||||
keyValueToArray,
|
||||
} from "../components/key-value-form/key-value-convert";
|
||||
import { KeycloakSpinner } from "@keycloak/keycloak-ui-shared";
|
||||
import { PermissionsTab } from "../components/permission-tab/PermissionTab";
|
||||
import { RoleForm } from "../components/role-form/RoleForm";
|
||||
import { AddRoleMappingModal } from "../components/role-mapping/AddRoleMappingModal";
|
||||
import { RoleMapping } from "../components/role-mapping/RoleMapping";
|
||||
import {
|
||||
RoutableTabs,
|
||||
|
|
@ -47,12 +49,12 @@ import {
|
|||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||
import { useAccess } from "../context/access/Access";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { AdminEvents } from "../events/AdminEvents";
|
||||
import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled";
|
||||
import { useParams } from "../utils/useParams";
|
||||
import { UsersInRoleTab } from "./UsersInRoleTab";
|
||||
import { RealmRoleRoute, RealmRoleTab, toRealmRole } from "./routes/RealmRole";
|
||||
import { toRealmRoles } from "./routes/RealmRoles";
|
||||
import { AdminEvents } from "../events/AdminEvents";
|
||||
|
||||
export default function RealmRoleTabs() {
|
||||
const { adminClient } = useAdminClient();
|
||||
|
|
@ -82,7 +84,6 @@ export default function RealmRoleTabs() {
|
|||
|
||||
const [canManageClientRole, setCanManageClientRole] = useState(false);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const convert = (role: RoleRepresentation) => {
|
||||
const { attributes, ...rest } = role;
|
||||
return {
|
||||
|
|
@ -246,15 +247,6 @@ export default function RealmRoleTabs() {
|
|||
return (
|
||||
<>
|
||||
<DeleteConfirm />
|
||||
{open && (
|
||||
<AddRoleMappingModal
|
||||
id={id}
|
||||
type="roles"
|
||||
name={roleName}
|
||||
onAssign={(rows) => addComposites(rows.map((r) => r.role))}
|
||||
onClose={() => setOpen(false)}
|
||||
/>
|
||||
)}
|
||||
<ViewHeader
|
||||
titleKey={roleName!}
|
||||
badges={[
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { login } from "../utils/login";
|
|||
import { assertNotificationMessage } from "../utils/masthead";
|
||||
import { assertModalTitle, confirmModal } from "../utils/modal";
|
||||
import {
|
||||
changeRoleTypeFilter,
|
||||
pickRoleType,
|
||||
clickHideInheritedRoles,
|
||||
clickUnassign,
|
||||
confirmModalAssign,
|
||||
|
|
@ -20,7 +20,7 @@ import {
|
|||
getTableData,
|
||||
searchItem,
|
||||
} from "../utils/table";
|
||||
import { assignRole, goToScopeTab } from "./scope";
|
||||
import { goToScopeTab } from "./scope";
|
||||
|
||||
test.describe("Scope tab test", () => {
|
||||
const scopeName = `client-scope-mapper-${uuidv4()}`;
|
||||
|
|
@ -47,8 +47,7 @@ test.describe("Scope tab test", () => {
|
|||
test("Assign and unassign role", async ({ page }) => {
|
||||
const role = "admin";
|
||||
|
||||
await assignRole(page);
|
||||
await changeRoleTypeFilter(page, "roles");
|
||||
await pickRoleType(page, "roles");
|
||||
await pickRole(page, role, true);
|
||||
await confirmModalAssign(page);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,3 @@ import { Page } from "@playwright/test";
|
|||
export async function goToScopeTab(page: Page) {
|
||||
await page.getByTestId("scopeTab").click();
|
||||
}
|
||||
|
||||
export async function assignRole(page: Page) {
|
||||
await page.getByTestId("no-roles-for-this-client-scope-empty-action").click();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ test.describe("Roles tab test", () => {
|
|||
await goToAssociatedRolesTab(page);
|
||||
|
||||
// Add associated realm role
|
||||
await page.getByTestId("no-roles-in-this-realm-empty-action").click();
|
||||
await addAssociatedRoles(page, createRealmRoleName);
|
||||
await assertNotificationMessage(page, "Associated roles have been added");
|
||||
|
||||
|
|
@ -188,8 +187,7 @@ test.describe("Roles tab test", () => {
|
|||
await goToAssociatedRolesTab(page);
|
||||
|
||||
// Add associated client roles
|
||||
await page.getByTestId("no-roles-in-this-realm-empty-action").click();
|
||||
await addAssociatedRoles(page, "accountmanage-account", "client");
|
||||
await addAssociatedRoles(page, "manage-account", "client");
|
||||
await assertNotificationMessage(page, "Associated roles have been added");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { expect, Page } from "@playwright/test";
|
||||
import {
|
||||
changeRoleTypeFilter,
|
||||
pickRoleType,
|
||||
confirmModalAssign,
|
||||
pickRole,
|
||||
RoleType,
|
||||
|
|
@ -45,7 +45,7 @@ export async function addAssociatedRoles(
|
|||
roleName: string,
|
||||
roleType: RoleType = "roles",
|
||||
) {
|
||||
await changeRoleTypeFilter(page, roleType);
|
||||
await pickRoleType(page, roleType);
|
||||
await pickRole(page, roleName, true);
|
||||
await confirmModalAssign(page);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ import { v4 as uuid } from "uuid";
|
|||
import adminClient from "../utils/AdminClient";
|
||||
import { login } from "../utils/login";
|
||||
import { assertNotificationMessage } from "../utils/masthead";
|
||||
import { confirmModal } from "../utils/modal";
|
||||
import {
|
||||
changeRoleTypeFilter,
|
||||
pickRoleType,
|
||||
clickHideInheritedRoles,
|
||||
clickUnassign,
|
||||
confirmModalAssign,
|
||||
|
|
@ -16,8 +17,7 @@ import {
|
|||
assertRowExists,
|
||||
clickTableRowItem,
|
||||
} from "../utils/table";
|
||||
import { assignRole, goToRoleMappingTab } from "./role";
|
||||
import { confirmModal } from "../utils/modal";
|
||||
import { goToRoleMappingTab } from "./role";
|
||||
|
||||
test.describe("Role mappings", () => {
|
||||
const predefinedGroup = "group1";
|
||||
|
|
@ -53,8 +53,7 @@ test.describe("Role mappings", () => {
|
|||
});
|
||||
|
||||
test("Assign roles from empty state", async ({ page }) => {
|
||||
await assignRole(page);
|
||||
await changeRoleTypeFilter(page, "roles");
|
||||
await pickRoleType(page, "roles");
|
||||
await pickRole(page, "default-roles-master", true);
|
||||
await confirmModalAssign(page);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,3 @@ import { Page } from "@playwright/test";
|
|||
export async function goToRoleMappingTab(page: Page) {
|
||||
await page.getByTestId("role-mapping-tab").click();
|
||||
}
|
||||
|
||||
export async function assignRole(page: Page) {
|
||||
await page.getByTestId("no-roles-for-this-group-empty-action").click();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { login } from "../utils/login";
|
|||
import { assertNotificationMessage } from "../utils/masthead";
|
||||
import { confirmModal } from "../utils/modal";
|
||||
import {
|
||||
changeRoleTypeFilter,
|
||||
pickRoleType,
|
||||
clickUnassign,
|
||||
confirmModalAssign,
|
||||
pickRole,
|
||||
|
|
@ -35,8 +35,6 @@ import {
|
|||
} from "../utils/table";
|
||||
import {
|
||||
assertUnassignDisabled,
|
||||
assignRole,
|
||||
clickAddRoleButton,
|
||||
clickCreateRoleButton,
|
||||
goToAssociatedRolesTab,
|
||||
} from "./main";
|
||||
|
|
@ -132,25 +130,22 @@ test.describe("Realm roles test", () => {
|
|||
await goToAssociatedRolesTab(page);
|
||||
|
||||
// Add associated realm role from search bar
|
||||
await clickAddRoleButton(page, true);
|
||||
await changeRoleTypeFilter(page, "roles");
|
||||
await pickRoleType(page, "roles");
|
||||
await pickRole(page, "offline_access", true);
|
||||
await confirmModalAssign(page);
|
||||
await assertNotificationMessage(page, "Associated roles have been added");
|
||||
|
||||
// Add associated client role from search bar
|
||||
await clickAddRoleButton(page);
|
||||
await pickRole(page, "accountmanage-account", true);
|
||||
await pickRoleType(page, "client");
|
||||
await pickRole(page, "manage-account", true);
|
||||
await confirmModalAssign(page);
|
||||
await assertNotificationMessage(page, "Associated roles have been added");
|
||||
|
||||
// Add associated client role
|
||||
await clickAddRoleButton(page);
|
||||
await pickRole(page, "accountmanage-consent", true);
|
||||
await pickRoleType(page, "client");
|
||||
await pickRole(page, "manage-consent", true);
|
||||
await confirmModalAssign(page);
|
||||
await assertNotificationMessage(page, "Associated roles have been added");
|
||||
|
||||
await clickAddRoleButton(page);
|
||||
});
|
||||
|
||||
test("should search existing associated role by name and go to it", async ({
|
||||
|
|
@ -207,8 +202,8 @@ test.describe("Realm roles test", () => {
|
|||
await clickTableRowItem(page, itemId);
|
||||
await goToAssociatedRolesTab(page);
|
||||
|
||||
await assignRole(page);
|
||||
await pickRole(page, "accountview-profile", true);
|
||||
await pickRoleType(page, "client");
|
||||
await pickRole(page, "view-profile", true);
|
||||
await confirmModalAssign(page);
|
||||
|
||||
await assertUnassignDisabled(page);
|
||||
|
|
@ -222,8 +217,8 @@ test.describe("Realm roles test", () => {
|
|||
await clickTableRowItem(page, itemId);
|
||||
await goToAssociatedRolesTab(page);
|
||||
|
||||
await assignRole(page);
|
||||
await pickRole(page, "accountview-profile", true);
|
||||
await pickRoleType(page, "client");
|
||||
await pickRole(page, "view-profile", true);
|
||||
await confirmModalAssign(page);
|
||||
|
||||
await clickRowKebabItem(page, "account view-profile", "Unassign");
|
||||
|
|
@ -239,8 +234,8 @@ test.describe("Realm roles test", () => {
|
|||
await clickTableRowItem(page, itemId);
|
||||
await goToAssociatedRolesTab(page);
|
||||
|
||||
await assignRole(page);
|
||||
await pickRole(page, "accountview-profile", true);
|
||||
await pickRoleType(page, "client");
|
||||
await pickRole(page, "view-profile", true);
|
||||
await confirmModalAssign(page);
|
||||
|
||||
await page.locator('input[name="check-all"]').check();
|
||||
|
|
|
|||
|
|
@ -8,15 +8,6 @@ export async function goToAssociatedRolesTab(page: Page) {
|
|||
await page.getByTestId("associatedRolesTab").click();
|
||||
}
|
||||
|
||||
export async function clickAddRoleButton(page: Page, empty: boolean = false) {
|
||||
const id = empty ? "no-roles-in-this-realm-empty-action" : "assignRole";
|
||||
await page.getByTestId(id).click();
|
||||
}
|
||||
|
||||
export async function assignRole(page: Page) {
|
||||
await page.getByTestId("no-roles-in-this-realm-empty-action").click();
|
||||
}
|
||||
|
||||
export async function assertUnassignDisabled(page: Page) {
|
||||
await expect(page.getByTestId("unAssignRole")).toBeDisabled();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,16 @@ import { v4 as uuid } from "uuid";
|
|||
import adminClient from "../utils/AdminClient";
|
||||
import { login } from "../utils/login";
|
||||
import { assertAxeViolations } from "../utils/masthead";
|
||||
import { pickRoleType } from "../utils/roles";
|
||||
import { goToRealm, goToRealmSettings } from "../utils/sidebar";
|
||||
import { goToRealmEventsTab } from "./events";
|
||||
import { goToAddProviders, goToKeys } from "./keys";
|
||||
import { goToLoginTab } from "./login";
|
||||
import { goToLocalizationTab, goToRealmOverridesSubTab } from "./localization";
|
||||
import {
|
||||
goToClientPoliciesList,
|
||||
goToClientPoliciesTab,
|
||||
} from "./client-policies";
|
||||
import { goToRealmEventsTab } from "./events";
|
||||
import { goToAddProviders, goToKeys } from "./keys";
|
||||
import { goToLocalizationTab, goToRealmOverridesSubTab } from "./localization";
|
||||
import { goToLoginTab } from "./login";
|
||||
|
||||
test.describe("Accessibility tests for realm settings", () => {
|
||||
const realmName = `realm-settings-accessibility-${uuid()}`;
|
||||
|
|
@ -186,7 +187,7 @@ test.describe("Accessibility tests for realm settings", () => {
|
|||
page,
|
||||
}) => {
|
||||
await page.getByTestId("rs-userRegistration-tab").click();
|
||||
await page.getByTestId("assignRole").click();
|
||||
await pickRoleType(page, "client");
|
||||
await assertAxeViolations(page);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,15 +4,10 @@ import adminClient from "../utils/AdminClient";
|
|||
import { login } from "../utils/login";
|
||||
import { assertNotificationMessage } from "../utils/masthead";
|
||||
import { confirmModal } from "../utils/modal";
|
||||
import {
|
||||
changeRoleTypeFilter,
|
||||
confirmModalAssign,
|
||||
pickRole,
|
||||
} from "../utils/roles";
|
||||
import { pickRoleType, confirmModalAssign, pickRole } from "../utils/roles";
|
||||
import { goToRealm, goToRealmSettings } from "../utils/sidebar";
|
||||
import { assertRowExists, clickRowKebabItem, searchItem } from "../utils/table";
|
||||
import {
|
||||
clickAssignRole,
|
||||
goToDefaultGroupTab,
|
||||
goToUserRegistrationTab,
|
||||
} from "./user-registration";
|
||||
|
|
@ -41,8 +36,7 @@ test.describe("Realm settings - User registration tab", () => {
|
|||
test(`Add / remove ${roleName} role`, async ({ page }) => {
|
||||
const roleType = "roles";
|
||||
|
||||
await clickAssignRole(page);
|
||||
await changeRoleTypeFilter(page, roleType);
|
||||
await pickRoleType(page, roleType);
|
||||
await pickRole(page, roleName, true);
|
||||
await confirmModalAssign(page);
|
||||
await assertNotificationMessage(page, "Associated roles have been added");
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@ export async function goToUserRegistrationTab(page: Page) {
|
|||
await page.getByTestId("rs-userRegistration-tab").click();
|
||||
}
|
||||
|
||||
export async function clickAssignRole(page: Page) {
|
||||
await page.getByTestId("assignRole").click();
|
||||
}
|
||||
|
||||
export async function goToDefaultGroupTab(page: Page) {
|
||||
await page.getByTestId("default-groups-tab").click();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
import ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
|
||||
import { Page } from "@playwright/test";
|
||||
import {
|
||||
changeRoleTypeFilter,
|
||||
confirmModalAssign,
|
||||
pickRole,
|
||||
} from "../utils/roles";
|
||||
import { pickRoleType, confirmModalAssign, pickRole } from "../utils/roles";
|
||||
|
||||
export async function goToMapperTab(page: Page) {
|
||||
await page.getByTestId("ldap-mappers-tab").click();
|
||||
|
|
@ -43,8 +39,7 @@ export async function fillHardwareAttributeMapper(
|
|||
.fill(data.config?.["ldap.attribute.value"][0] || "");
|
||||
|
||||
if (data.config?.role) {
|
||||
await page.getByTestId("add-roles").click();
|
||||
await changeRoleTypeFilter(page, "roles");
|
||||
await pickRoleType(page, "roles");
|
||||
await pickRole(page, data.config.role[0], true);
|
||||
await confirmModalAssign(page);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,22 +4,16 @@ import { clickSelectRow } from "./table";
|
|||
export type RoleType = "client" | "roles";
|
||||
const rolePickTableName = "Role list";
|
||||
|
||||
export async function changeRoleTypeFilter(page: Page, roleType: RoleType) {
|
||||
const currentFilter = await page
|
||||
.getByTestId("filter-type-dropdown")
|
||||
.innerText();
|
||||
if (currentFilter.includes(roleType)) {
|
||||
return;
|
||||
}
|
||||
export async function pickRoleType(page: Page, roleType: RoleType) {
|
||||
await page.getByTestId("add-role-mapping-button").click();
|
||||
|
||||
let filter;
|
||||
if (roleType === "client") {
|
||||
filter = "Filter by clients";
|
||||
filter = "Client roles";
|
||||
} else {
|
||||
filter = "Filter by realm roles";
|
||||
filter = "Realm roles";
|
||||
}
|
||||
|
||||
await page.getByTestId("filter-type-dropdown").click();
|
||||
await page.getByRole("menuitem", { name: filter, exact: true }).click();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
import { ComponentClass, MouseEventHandler, ReactNode } from "react";
|
||||
import {
|
||||
ComponentClass,
|
||||
MouseEventHandler,
|
||||
PropsWithChildren,
|
||||
ReactNode,
|
||||
} from "react";
|
||||
import {
|
||||
EmptyState,
|
||||
EmptyStateIcon,
|
||||
|
|
@ -40,7 +45,8 @@ export const ListEmptyState = ({
|
|||
secondaryActions,
|
||||
icon,
|
||||
isDisabled = false,
|
||||
}: ListEmptyStateProps) => {
|
||||
children,
|
||||
}: PropsWithChildren<ListEmptyStateProps>) => {
|
||||
return (
|
||||
<EmptyState data-testid="empty-state" variant="lg">
|
||||
{hasIcon && isSearchVariant ? (
|
||||
|
|
@ -63,6 +69,7 @@ export const ListEmptyState = ({
|
|||
{primaryActionText}
|
||||
</Button>
|
||||
)}
|
||||
{children}
|
||||
{secondaryActions && (
|
||||
<EmptyStateActions>
|
||||
{secondaryActions.map((action) => (
|
||||
|
|
|
|||
Loading…
Reference in a new issue