diff --git a/src/clients/authorization/Permissions.tsx b/src/clients/authorization/Permissions.tsx index abe9438d0a..2d75a4de90 100644 --- a/src/clients/authorization/Permissions.tsx +++ b/src/clients/authorization/Permissions.tsx @@ -30,12 +30,13 @@ import { useAlerts } from "../../components/alert/Alerts"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient"; import useToggle from "../../utils/useToggle"; import { useRealm } from "../../context/realm-context/RealmContext"; -import { SearchDropdown } from "./SearchDropdown"; +import { SearchDropdown, SearchForm } from "./SearchDropdown"; import { MoreLabel } from "./MoreLabel"; import { DetailDescription } from "./DetailDescription"; import { EmptyPermissionsState } from "./EmptyPermissionsState"; import { toNewPermission } from "../routes/NewPermission"; import { toPermissionDetails } from "../routes/PermissionDetails"; +import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState"; import "./permissions.css"; @@ -64,6 +65,7 @@ export const AuthorizationPermissions = ({ clientId }: PermissionsProps) => { const [disabledCreate, setDisabledCreate] = useState<{ resources: boolean; scopes: boolean }>(); const [createOpen, toggleCreate] = useToggle(); + const [search, setSearch] = useState({}); const [key, setKey] = useState(0); const refresh = () => setKey(key + 1); @@ -90,6 +92,7 @@ export const AuthorizationPermissions = ({ clientId }: PermissionsProps) => { first, max, id: clientId, + ...search, }); return await Promise.all( @@ -109,7 +112,7 @@ export const AuthorizationPermissions = ({ clientId }: PermissionsProps) => { ); }, setPermissions, - [key] + [key, search] ); useFetch( @@ -166,10 +169,12 @@ export const AuthorizationPermissions = ({ clientId }: PermissionsProps) => { return ; } + const noData = permissions.length === 0; + const searching = Object.keys(search).length !== 0; return ( - {permissions.length > 0 && ( + {(!noData || searching) && ( { toolbarItem={ <> - + { } > - - - - - {t("common:name")} - {t("common:type")} - {t("associatedPolicy")} - {t("common:description")} - - - - {permissions.map((permission, rowIndex) => ( - + {!noData && ( + + - { - const rows = permissions.map((p, index) => - index === rowIndex - ? { ...p, isExpanded: !p.isExpanded } - : p - ); - setPermissions(rows); - }, - }} - /> - - - {permission.name} - - - - { - policyProviders?.find((p) => p.type === permission.type) - ?.name - } - - - - - {permission.description} - { - setSelectedPermission(permission); - toggleDeleteDialog(); - }, + + {t("common:name")} + {t("common:type")} + {t("associatedPolicy")} + {t("common:description")} + + + + {permissions.map((permission, rowIndex) => ( + + + { + const rows = permissions.map((p, index) => + index === rowIndex + ? { ...p, isExpanded: !p.isExpanded } + : p + ); + setPermissions(rows); }, - ], - }} - > - - - - - - {permission.isExpanded && ( - - p.name!} - /> - - )} - - - - - ))} - + }} + /> + + + {permission.name} + + + + { + policyProviders?.find((p) => p.type === permission.type) + ?.name + } + + + + + {permission.description} + { + setSelectedPermission(permission); + toggleDeleteDialog(); + }, + }, + ], + }} + > + + + + + + {permission.isExpanded && ( + + p.name!} + /> + + )} + + + + + ))} + + )} )} - {permissions.length === 0 && ( + {noData && !searching && ( )} + {noData && searching && ( + + )} ); }; diff --git a/src/clients/authorization/SearchDropdown.tsx b/src/clients/authorization/SearchDropdown.tsx index c4b1178f8b..ebe9873b5e 100644 --- a/src/clients/authorization/SearchDropdown.tsx +++ b/src/clients/authorization/SearchDropdown.tsx @@ -2,6 +2,8 @@ import React from "react"; import { useTranslation } from "react-i18next"; import { Controller, useForm } from "react-hook-form"; import { + ActionGroup, + Button, Dropdown, DropdownToggle, Form, @@ -17,17 +19,50 @@ import useToggle from "../../utils/useToggle"; import "./search-dropdown.css"; -type SearchDropdownProps = { - types?: PolicyProviderRepresentation[]; +export type SearchForm = { + name?: string; + resource?: string; + scope?: string; + type?: string; }; -export const SearchDropdown = ({ types }: SearchDropdownProps) => { +type SearchDropdownProps = { + types?: PolicyProviderRepresentation[]; + onSearch: (form: SearchForm) => void; +}; + +export const SearchDropdown = ({ types, onSearch }: SearchDropdownProps) => { const { t } = useTranslation("clients"); - const { register, control } = useForm(); + const { + register, + control, + formState: { isDirty }, + handleSubmit, + } = useForm({ mode: "onChange" }); const [open, toggle] = useToggle(); const [typeOpen, toggleType] = useToggle(); + const submit = (form: SearchForm) => { + toggle(); + onSearch(form); + }; + + const typeOptions = (value: string) => [ + + {t("allTypes")} + , + ...(types || []).map((type) => ( + + {type.name} + + )), + ]; + return ( {
{ data-testid="searchdropdown_name" /> + + + + + + { onChange(value); toggleType(); }} - selections={value.name} + selections={value || t("allTypes")} variant={SelectVariant.single} aria-label={t("common:type")} isOpen={typeOpen} > - {types?.map((type) => ( - - {type.name} - - ))} + {typeOptions(value)} )} /> + + + +
); diff --git a/src/clients/messages.ts b/src/clients/messages.ts index 36ffa0c8de..a807277b93 100644 --- a/src/clients/messages.ts +++ b/src/clients/messages.ts @@ -126,6 +126,9 @@ export default { associatedPermissions: "Associated permission", allowRemoteResourceManagement: "Remote resource management", resources: "Resources", + resource: "Resource", + allTypes: "All types", + scope: "Scope", owner: "Owner", uris: "URIs", scopes: "Scopes",