added permission search (#1890)

This commit is contained in:
Erik Jan de Wit 2022-01-24 15:17:32 +01:00 committed by GitHub
parent 92c73a7fcc
commit c4724b21c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 186 additions and 106 deletions

View file

@ -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<SearchForm>({});
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 <KeycloakSpinner />;
}
const noData = permissions.length === 0;
const searching = Object.keys(search).length !== 0;
return (
<PageSection variant="light" className="pf-u-p-0">
<DeleteConfirm />
{permissions.length > 0 && (
{(!noData || searching) && (
<PaginatingTableToolbar
count={permissions.length}
first={first}
@ -183,7 +188,7 @@ export const AuthorizationPermissions = ({ clientId }: PermissionsProps) => {
toolbarItem={
<>
<ToolbarItem>
<SearchDropdown types={policyProviders} />
<SearchDropdown types={policyProviders} onSearch={setSearch} />
</ToolbarItem>
<ToolbarItem>
<Dropdown
@ -238,6 +243,7 @@ export const AuthorizationPermissions = ({ clientId }: PermissionsProps) => {
</>
}
>
{!noData && (
<TableComposable aria-label={t("resources")} variant="compact">
<Thead>
<Tr>
@ -327,15 +333,23 @@ export const AuthorizationPermissions = ({ clientId }: PermissionsProps) => {
</Tbody>
))}
</TableComposable>
)}
</PaginatingTableToolbar>
)}
{permissions.length === 0 && (
{noData && !searching && (
<EmptyPermissionsState
clientId={clientId}
isResourceEnabled={disabledCreate?.resources}
isScopeEnabled={disabledCreate?.scopes}
/>
)}
{noData && searching && (
<ListEmptyState
isSearchVariant
message={t("common:noSearchResults")}
instructions={t("common:noSearchResultsInstructions")}
/>
)}
</PageSection>
);
};

View file

@ -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<SearchForm>({ mode: "onChange" });
const [open, toggle] = useToggle();
const [typeOpen, toggleType] = useToggle();
const submit = (form: SearchForm) => {
toggle();
onSearch(form);
};
const typeOptions = (value: string) => [
<SelectOption key="empty" value="">
{t("allTypes")}
</SelectOption>,
...(types || []).map((type) => (
<SelectOption
selected={type.type === value}
key={type.type}
value={type.type}
>
{type.name}
</SelectOption>
)),
];
return (
<Dropdown
data-testid="searchdropdown_dorpdown"
@ -45,6 +80,7 @@ export const SearchDropdown = ({ types }: SearchDropdownProps) => {
<Form
isHorizontal
className="keycloak__client_authentication__searchdropdown_form"
onSubmit={handleSubmit(submit)}
>
<FormGroup label={t("common:name")} fieldId="name">
<TextInput
@ -55,6 +91,24 @@ export const SearchDropdown = ({ types }: SearchDropdownProps) => {
data-testid="searchdropdown_name"
/>
</FormGroup>
<FormGroup label={t("resource")} fieldId="resource">
<TextInput
ref={register}
type="text"
id="resource"
name="resource"
data-testid="searchdropdown_resource"
/>
</FormGroup>
<FormGroup label={t("scope")} fieldId="scope">
<TextInput
ref={register}
type="text"
id="scope"
name="scope"
data-testid="searchdropdown_scope"
/>
</FormGroup>
<FormGroup label={t("common:type")} fieldId="type">
<Controller
name="type"
@ -69,24 +123,33 @@ export const SearchDropdown = ({ types }: SearchDropdownProps) => {
onChange(value);
toggleType();
}}
selections={value.name}
selections={value || t("allTypes")}
variant={SelectVariant.single}
aria-label={t("common:type")}
isOpen={typeOpen}
>
{types?.map((type) => (
<SelectOption
selected={type.type === value.type}
key={type.type}
value={type}
>
{type.name}
</SelectOption>
))}
{typeOptions(value)}
</Select>
)}
/>
</FormGroup>
<ActionGroup>
<Button
variant="primary"
type="submit"
data-testid="search-btn"
isDisabled={!isDirty}
>
{t("common:search")}
</Button>
<Button
variant="link"
data-testid="revert-btn"
onClick={() => onSearch({})}
>
{t("common:clear")}
</Button>
</ActionGroup>
</Form>
</Dropdown>
);

View file

@ -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",