diff --git a/src/components/table-toolbar/KeycloakDataTable.tsx b/src/components/table-toolbar/KeycloakDataTable.tsx index b8034653ff..0abab0027c 100644 --- a/src/components/table-toolbar/KeycloakDataTable.tsx +++ b/src/components/table-toolbar/KeycloakDataTable.tsx @@ -121,11 +121,17 @@ export type Action = IAction & { onRowClick?: (row: T) => Promise | void; }; +type LoaderFunction = ( + first?: number, + max?: number, + search?: string +) => Promise; + export type DataListProps = Omit< TableProps, "rows" | "cells" | "onSelect" > & { - loader: (first?: number, max?: number, search?: string) => Promise; + loader: T[] | LoaderFunction; onSelect?: (value: T[]) => void; canSelectAll?: boolean; detailColumns?: DetailField[]; @@ -290,7 +296,9 @@ export function KeycloakDataTable({ useFetch( async () => { setLoading(true); - return unPaginatedData || (await loader(first, max + 1, search)); + return typeof loader === "function" + ? unPaginatedData || (await loader(first, max + 1, search)) + : loader; }, (data) => { if (!isPaginated) { @@ -302,7 +310,7 @@ export function KeycloakDataTable({ setRows(result); setLoading(false); }, - [key, first, max, search] + [key, first, max, search, typeof loader !== "function" ? loader : undefined] ); const convertAction = () => diff --git a/src/realm-settings/keys/KeysListTab.tsx b/src/realm-settings/keys/KeysListTab.tsx index f8a5765ce0..5d1fc2a359 100644 --- a/src/realm-settings/keys/KeysListTab.tsx +++ b/src/realm-settings/keys/KeysListTab.tsx @@ -18,13 +18,16 @@ import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { emptyFormatter } from "../../util"; -import { useAdminClient } from "../../context/auth/AdminClient"; -import { useRealm } from "../../context/realm-context/RealmContext"; +import { useAdminClient, useFetch } from "../../context/auth/AdminClient"; import { toKeysTab } from "../routes/KeysTab"; +import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; +import { useRealm } from "../../context/realm-context/RealmContext"; +import useToggle from "../../utils/useToggle"; import "../realm-settings-section.css"; const FILTER_OPTIONS = ["ACTIVE", "PASSIVE", "DISABLED"] as const; +type FilterType = typeof FILTER_OPTIONS[number]; type KeyData = KeyMetadataRepresentation & { provider?: string; @@ -34,43 +37,74 @@ type KeysListTabProps = { realmComponents: ComponentRepresentation[]; }; +type SelectFilterProps = { + onFilter: (filter: FilterType) => void; +}; + +const SelectFilter = ({ onFilter }: SelectFilterProps) => { + const { t } = useTranslation("realm-settings"); + const [filterType, setFilterType] = useState(FILTER_OPTIONS[0]); + + const [filterDropdownOpen, toggleFilter] = useToggle(); + return ( + + ); +}; + export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { const { t } = useTranslation("realm-settings"); const history = useHistory(); - const [key, setKey] = useState(0); const [publicKey, setPublicKey] = useState(""); const [certificate, setCertificate] = useState(""); - const [filterDropdownOpen, setFilterDropdownOpen] = useState(false); - const [filterType, setFilterType] = useState( - FILTER_OPTIONS[0] - ); - - const refresh = () => { - setKey(key + 1); - }; const adminClient = useAdminClient(); - const { realm: realmName } = useRealm(); + const { realm } = useRealm(); - const loader = async () => { - const keysMetaData = await adminClient.realms.getKeys({ - realm: realmName, - }); + const [keyData, setKeyData] = useState(); + const [filteredKeyData, setFilteredKeyData] = useState(); - const keys = keysMetaData.keys; - const filtered = - filterType !== FILTER_OPTIONS[0] - ? keys?.filter(({ status }) => status === filterType) - : keys; - - return filtered?.map((key) => { - const provider = realmComponents.find( - (component: ComponentRepresentation) => component.id === key.providerId - ); - return { ...key, provider: provider?.name } as KeyData; - })!; - }; + useFetch( + async () => { + const keysMetaData = await adminClient.realms.getKeys({ realm }); + return keysMetaData.keys?.map((key) => { + const provider = realmComponents.find( + (component: ComponentRepresentation) => + component.id === key.providerId + ); + return { ...key, provider: provider?.name } as KeyData; + })!; + }, + setKeyData, + [] + ); const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({ titleKey: t("publicKeys").slice(0, -1), @@ -132,51 +166,35 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { } }; + if (!keyData) { + return ; + } + return ( setFilterDropdownOpen(!filterDropdownOpen)} - toggleIcon={} - onSelect={(_, value) => { - setFilterType( - FILTER_OPTIONS.find((o) => o === value.toString()) || - FILTER_OPTIONS[0] - ); - refresh(); - setFilterDropdownOpen(false); - }} - selections={filterType} - > - {FILTER_OPTIONS.map((option) => ( - - {t(`keysFilter.${option}`)} - - ))} - + + setFilteredKeyData( + filterType !== FILTER_OPTIONS[0] + ? keyData!.filter(({ status }) => status === filterType) + : undefined + ) + } + /> } canSelectAll columns={[ { name: "algorithm", - displayKey: "algorithm", + displayKey: "realm-settings:algorithm", cellFormatters: [emptyFormatter()], transforms: [cellWidth(15)], }, @@ -188,26 +206,26 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { }, { name: "kid", - displayKey: "kid", + displayKey: "realm-settings:kid", cellFormatters: [emptyFormatter()], transforms: [cellWidth(10)], }, { name: "provider", - displayKey: "provider", + displayKey: "realm-settings:provider", cellRenderer: ProviderRenderer, cellFormatters: [emptyFormatter()], transforms: [cellWidth(10)], }, { name: "publicKeys", - displayKey: "publicKeys", + displayKey: "realm-settings:publicKeys", cellRenderer: ButtonRenderer, cellFormatters: [], transforms: [cellWidth(20)], }, ]} - isSearching={filterType !== FILTER_OPTIONS[0]} + isSearching={!!filteredKeyData} emptyState={ { instructions={t("noKeysDescription")} primaryActionText={t("addProvider")} onPrimaryAction={() => - history.push(toKeysTab({ realm: realmName, tab: "providers" })) + history.push(toKeysTab({ realm, tab: "providers" })) } /> }