Fix(clients -> authorization): Evaluate results screen (#2220)
This commit is contained in:
parent
3a25b5e5ec
commit
b64fd23559
1 changed files with 69 additions and 75 deletions
|
@ -1,5 +1,5 @@
|
|||
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
||||
import React, { useState, KeyboardEvent } from "react";
|
||||
import React, { useState, KeyboardEvent, useMemo, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
FormGroup,
|
||||
|
@ -17,6 +17,7 @@ import {
|
|||
Toolbar,
|
||||
ToolbarGroup,
|
||||
ToolbarItem,
|
||||
Divider,
|
||||
} from "@patternfly/react-core";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
|
@ -78,6 +79,26 @@ export type AttributeForm = Omit<
|
|||
|
||||
type Props = ClientSettingsProps & EvaluationResultRepresentation;
|
||||
|
||||
enum ResultsFilter {
|
||||
All = "ALL",
|
||||
StatusDenied = "STATUS_DENIED",
|
||||
StatusPermitted = "STATUS_PERMITTED",
|
||||
}
|
||||
|
||||
function filterResults(
|
||||
results: EvaluationResultRepresentation[],
|
||||
filter: ResultsFilter
|
||||
) {
|
||||
switch (filter) {
|
||||
case ResultsFilter.StatusPermitted:
|
||||
return results.filter(({ status }) => status === "PERMIT");
|
||||
case ResultsFilter.StatusDenied:
|
||||
return results.filter(({ status }) => status === "DENY");
|
||||
default:
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
export const AuthorizationEvaluate = ({ client }: Props) => {
|
||||
const form = useFormContext<EvaluateFormInputs>();
|
||||
const { control, reset, trigger } = form;
|
||||
|
@ -98,10 +119,8 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
EvaluationResultRepresentation[]
|
||||
>([]);
|
||||
const [showEvaluateResults, setShowEvaluateResults] = useState(false);
|
||||
const [searchVal, setSearchVal] = useState("");
|
||||
const [filteredResources, setFilteredResources] = useState<
|
||||
EvaluationResultRepresentation[]
|
||||
>([]);
|
||||
const searchQueryRef = useRef("");
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [filterDropdownOpen, setFilterDropdownOpen] = useState(false);
|
||||
const [key, setKey] = useState(0);
|
||||
|
||||
|
@ -109,18 +128,20 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
setKey(key + 1);
|
||||
};
|
||||
|
||||
const FilterType = {
|
||||
allResults: t("allResults"),
|
||||
resultPermit: t("resultPermit"),
|
||||
resultDeny: t("resultDeny"),
|
||||
};
|
||||
|
||||
const [filterType, setFilterType] = useState(FilterType.allResults);
|
||||
const [filter, setFilter] = useState(ResultsFilter.All);
|
||||
|
||||
const [clients, setClients] = useState<ClientRepresentation[]>([]);
|
||||
const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>([]);
|
||||
const [users, setUsers] = useState<UserRepresentation[]>([]);
|
||||
|
||||
const filteredResources = useMemo(
|
||||
() =>
|
||||
filterResults(evaluateResults, filter).filter(
|
||||
({ resource }) => resource?.name?.includes(searchQuery) ?? false
|
||||
),
|
||||
[evaluateResults, filter, searchQuery]
|
||||
);
|
||||
|
||||
useFetch(
|
||||
() =>
|
||||
Promise.all([
|
||||
|
@ -137,7 +158,7 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
);
|
||||
|
||||
useFetch(
|
||||
async () =>
|
||||
() =>
|
||||
Promise.all([
|
||||
adminClient.clients.listResources({
|
||||
id: client.id!,
|
||||
|
@ -150,7 +171,7 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
setResources(resources);
|
||||
setScopes(scopes);
|
||||
},
|
||||
[key, filterType]
|
||||
[key, filter]
|
||||
);
|
||||
|
||||
const evaluate = async () => {
|
||||
|
@ -184,51 +205,23 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
return evaluateResults;
|
||||
};
|
||||
|
||||
const onSearch = () => {
|
||||
if (searchVal !== "") {
|
||||
setSearchVal(searchVal);
|
||||
const filtered = evaluateResults.filter((resource) =>
|
||||
resource.resource?.name?.includes(searchVal)
|
||||
);
|
||||
setFilteredResources(filtered);
|
||||
} else {
|
||||
setSearchVal("");
|
||||
setFilteredResources(evaluateResults);
|
||||
}
|
||||
const confirmSearchQuery = () => {
|
||||
setSearchQuery(searchQueryRef.current);
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
onSearch();
|
||||
confirmSearchQuery();
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (value: string) => {
|
||||
setSearchVal(value);
|
||||
searchQueryRef.current = value;
|
||||
};
|
||||
|
||||
const noEvaluatedData = evaluateResults.length === 0;
|
||||
const noFilteredData = filteredResources.length === 0;
|
||||
|
||||
const options = [
|
||||
<SelectOption
|
||||
key={1}
|
||||
data-testid="all-results-option"
|
||||
value={FilterType.allResults}
|
||||
isPlaceholder
|
||||
/>,
|
||||
<SelectOption
|
||||
data-testid="result-permit-option"
|
||||
key={2}
|
||||
value={FilterType.resultPermit}
|
||||
/>,
|
||||
<SelectOption
|
||||
data-testid="result-deny-option"
|
||||
key={3}
|
||||
value={FilterType.resultDeny}
|
||||
/>,
|
||||
];
|
||||
|
||||
return showEvaluateResults ? (
|
||||
<PageSection>
|
||||
<Toolbar>
|
||||
|
@ -247,7 +240,7 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
<Button
|
||||
variant={ButtonVariant.control}
|
||||
aria-label={t("common:search")}
|
||||
onClick={() => onSearch()}
|
||||
onClick={() => confirmSearchQuery()}
|
||||
>
|
||||
<SearchIcon />
|
||||
</Button>
|
||||
|
@ -262,34 +255,36 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
variant={SelectVariant.single}
|
||||
onToggle={() => setFilterDropdownOpen(!filterDropdownOpen)}
|
||||
onSelect={(_, value) => {
|
||||
if (value === FilterType.allResults) {
|
||||
setFilterType(FilterType.allResults);
|
||||
} else if (value === FilterType.resultPermit) {
|
||||
const filterPermit = evaluateResults.filter(
|
||||
(resource) => resource.status === "PERMIT"
|
||||
);
|
||||
setFilteredResources(filterPermit);
|
||||
setFilterType(FilterType.resultPermit);
|
||||
|
||||
refresh();
|
||||
} else if (value === FilterType.resultDeny) {
|
||||
const filterDeny = evaluateResults.filter(
|
||||
(resource) => resource.status === "DENY"
|
||||
);
|
||||
setFilterType(FilterType.resultDeny);
|
||||
setFilteredResources(filterDeny);
|
||||
refresh();
|
||||
}
|
||||
setFilter(value as ResultsFilter);
|
||||
setFilterDropdownOpen(false);
|
||||
refresh();
|
||||
}}
|
||||
selections={filterType}
|
||||
selections={filter}
|
||||
>
|
||||
{options}
|
||||
<SelectOption
|
||||
data-testid="all-results-option"
|
||||
value={ResultsFilter.All}
|
||||
isPlaceholder
|
||||
>
|
||||
{t("allResults")}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
data-testid="result-permit-option"
|
||||
value={ResultsFilter.StatusPermitted}
|
||||
>
|
||||
{t("resultPermit")}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
data-testid="result-deny-option"
|
||||
value={ResultsFilter.StatusDenied}
|
||||
>
|
||||
{t("resultDeny")}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</ToolbarItem>
|
||||
</ToolbarGroup>
|
||||
</Toolbar>
|
||||
{!noEvaluatedData && !noFilteredData && (
|
||||
{!noFilteredData && (
|
||||
<TableComposable aria-label={t("evaluationResults")}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
|
@ -300,10 +295,7 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
<Th />
|
||||
</Tr>
|
||||
</Thead>
|
||||
{(filterType == FilterType.allResults
|
||||
? evaluateResults
|
||||
: filteredResources
|
||||
).map((resource, rowIndex) => (
|
||||
{filteredResources.map((resource, rowIndex) => (
|
||||
<AuthorizationEvaluateResource
|
||||
key={rowIndex}
|
||||
rowIndex={rowIndex}
|
||||
|
@ -313,14 +305,16 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
))}
|
||||
</TableComposable>
|
||||
)}
|
||||
{noEvaluatedData ||
|
||||
(noFilteredData && (
|
||||
{(noFilteredData || noEvaluatedData) && (
|
||||
<>
|
||||
<Divider />
|
||||
<ListEmptyState
|
||||
isSearchVariant
|
||||
message={t("common:noSearchResults")}
|
||||
instructions={t("common:noSearchResultsInstructions")}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
<ActionGroup className="kc-evaluated-options">
|
||||
<Button
|
||||
data-testid="authorization-eval"
|
||||
|
|
Loading…
Reference in a new issue