Merge pull request #556 from edewit/change-asyncFetch-to-it's-own-hook

changed `asyncStateFetch` to be it's own hook
This commit is contained in:
mfrances17 2021-05-18 10:13:30 -04:00 committed by GitHub
commit c0c3fd6692
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 569 additions and 728 deletions

View file

@ -25,6 +25,7 @@
"@patternfly/react-core": "4.115.1",
"@patternfly/react-icons": "4.10.1",
"@patternfly/react-table": "4.26.7",
"axios": "^0.21.1",
"file-saver": "^2.0.5",
"i18next": "^19.6.2",
"keycloak-admin": "1.14.16",

View file

@ -1,8 +1,7 @@
import React, { useContext, useEffect, useState } from "react";
import React, { useContext, useState } from "react";
import { useHistory, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Controller, useForm } from "react-hook-form";
import { useErrorHandler } from "react-error-boundary";
import {
FormGroup,
PageSection,
@ -24,10 +23,7 @@ import ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentation";
import ProtocolMapperRepresentation from "keycloak-admin/lib/defs/protocolMapperRepresentation";
import { useAlerts } from "../../components/alert/Alerts";
import { RealmContext } from "../../context/realm-context/RealmContext";
import {
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import { HelpItem } from "../../components/help-enabler/HelpItem";
@ -36,7 +32,6 @@ import { FormAccess } from "../../components/form-access/FormAccess";
export const RoleMappingForm = () => {
const { realm } = useContext(RealmContext);
const adminClient = useAdminClient();
const handleError = useErrorHandler();
const history = useHistory();
const { addAlert } = useAlerts();
@ -51,8 +46,7 @@ export const RoleMappingForm = () => {
const [selectedClient, setSelectedClient] = useState<ClientRepresentation>();
const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>([]);
useEffect(() => {
return asyncStateFetch(
useFetch(
async () => {
const clients = await adminClient.clients.find();
@ -77,12 +71,10 @@ export const RoleMappingForm = () => {
return filteredClients;
},
(filteredClients) => setClients(filteredClients),
handleError
[]
);
}, []);
useEffect(() => {
return asyncStateFetch(
useFetch(
async () => {
const client = selectedClient as ClientRepresentation;
if (client && client.name !== "realmRoles") {
@ -95,9 +87,8 @@ export const RoleMappingForm = () => {
}
},
(clientRoles) => setClientRoles(clientRoles),
handleError
[selectedClient]
);
}, [selectedClient]);
const save = async (mapping: ProtocolMapperRepresentation) => {
try {

View file

@ -1,7 +1,6 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { useHistory, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import {
ActionGroup,
AlertVariant,
@ -24,10 +23,7 @@ import { ConfigPropertyRepresentation } from "keycloak-admin/lib/defs/configProp
import ProtocolMapperRepresentation from "keycloak-admin/lib/defs/protocolMapperRepresentation";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import {
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { Controller, useForm } from "react-hook-form";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { useAlerts } from "../../components/alert/Alerts";
@ -45,7 +41,6 @@ type Params = {
export const MappingDetails = () => {
const { t } = useTranslation("client-scopes");
const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { addAlert } = useAlerts();
const { id, mapperId } = useParams<Params>();
@ -61,8 +56,7 @@ export const MappingDetails = () => {
const serverInfo = useServerInfo();
const isGuid = /^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$/;
useEffect(() => {
return asyncStateFetch(
useFetch(
async () => {
if (mapperId.match(isGuid)) {
const data = await adminClient.clientScopes.findProtocolMapper({
@ -104,9 +98,8 @@ export const MappingDetails = () => {
setConfigProperties(result.configProperties);
setMapping(result.mapping);
},
handleError
[]
);
}, []);
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: "common:deleteMappingTitle",

View file

@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next";
import {
AlertVariant,
@ -11,10 +10,7 @@ import {
} from "@patternfly/react-core";
import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation";
import {
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { KeycloakTabs } from "../../components/keycloak-tabs/KeycloakTabs";
import { useAlerts } from "../../components/alert/Alerts";
import { ViewHeader } from "../../components/view-header/ViewHeader";
@ -30,7 +26,6 @@ export const ClientScopeForm = () => {
const [hide, setHide] = useState(false);
const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { id } = useParams<{ id: string }>();
const { addAlert } = useAlerts();
@ -38,8 +33,7 @@ export const ClientScopeForm = () => {
const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
useEffect(() => {
return asyncStateFetch(
useFetch(
async () => {
if (id) {
return await adminClient.clientScopes.findOne({ id });
@ -48,9 +42,8 @@ export const ClientScopeForm = () => {
(clientScope) => {
setClientScope(clientScope);
},
handleError
[key, id]
);
}, [key, id]);
const loader = async () => {
const assignedRoles = hide

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import {
Alert,
AlertVariant,
@ -12,9 +12,8 @@ import {
TabTitleText,
} from "@patternfly/react-core";
import { useHistory, useParams } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
import ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentation";
import _ from "lodash";
@ -26,7 +25,7 @@ import {
} from "../components/confirm-dialog/ConfirmDialog";
import { DownloadDialog } from "../components/download-dialog/DownloadDialog";
import { ViewHeader } from "../components/view-header/ViewHeader";
import { useAdminClient, asyncStateFetch } from "../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { Credentials } from "./credentials/Credentials";
import {
convertFormValuesToObject,
@ -125,7 +124,6 @@ export const ClientDetails = () => {
const { t } = useTranslation("clients");
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const handleError = useErrorHandler();
const { realm } = useRealm();
const history = useHistory();
@ -140,6 +138,12 @@ export const ClientDetails = () => {
const form = useForm<ClientForm>();
const { clientId } = useParams<{ clientId: string }>();
const clientAuthenticatorType = useWatch({
control: form.control,
name: "clientAuthenticatorType",
defaultValue: "client-secret",
});
const [client, setClient] = useState<ClientRepresentation>();
const loader = async () => {
@ -178,16 +182,14 @@ export const ClientDetails = () => {
});
};
useEffect(() => {
return asyncStateFetch(
useFetch(
() => adminClient.clients.findOne({ id: clientId }),
(fetchedClient) => {
setClient(fetchedClient);
setupForm(fetchedClient);
},
handleError
[clientId]
);
}, [clientId]);
const save = async (
{ confirmed = false, messageKey = "clientSaveSuccess" }: SaveOptions = {
@ -198,8 +200,7 @@ export const ClientDetails = () => {
if (await form.trigger()) {
if (
!client?.publicClient &&
client?.clientAuthenticatorType !==
form.getValues("clientAuthenticatorType") &&
client?.clientAuthenticatorType !== clientAuthenticatorType &&
!confirmed
) {
toggleChangeAuthenticator();
@ -241,7 +242,7 @@ export const ClientDetails = () => {
<ConfirmDialogModal
continueButtonLabel="common:yes"
titleKey={t("changeAuthenticatorConfirmTitle", {
clientAuthenticatorType: form.getValues("clientAuthenticatorType"),
clientAuthenticatorType: clientAuthenticatorType,
})}
open={changeAuthenticatorOpen}
toggleDialog={toggleChangeAuthenticator}
@ -249,9 +250,9 @@ export const ClientDetails = () => {
>
<>
{t("changeAuthenticatorConfirm", {
clientAuthenticatorType: form.getValues("clientAuthenticatorType"),
clientAuthenticatorType: clientAuthenticatorType,
})}
{form.getValues("clientAuthenticatorType") === "client-jwt" && (
{clientAuthenticatorType === "client-jwt" && (
<Alert variant="info" isInline title={t("signedJWTConfirm")} />
)}
</>

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { Link, useHistory } from "react-router-dom";
import { useTranslation } from "react-i18next";
import {
@ -49,8 +49,6 @@ export const ClientsSection = () => {
return await adminClient.clients.find({ ...params });
};
useEffect(refresh, [selectedClient]);
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: t("clientDelete", { clientId: selectedClient?.clientId }),
messageKey: "clients:clientDeleteConfirm",
@ -62,7 +60,7 @@ export const ClientsSection = () => {
id: selectedClient!.id!,
});
addAlert(t("clientDeletedSuccess"), AlertVariant.success);
setSelectedClient(undefined);
refresh();
} catch (error) {
addAlert(t("clientDeleteError", { error }), AlertVariant.danger);
}

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { Control, Controller } from "react-hook-form";
import { useTranslation } from "react-i18next";
import _ from "lodash";
@ -11,12 +11,8 @@ import {
import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import {
asyncStateFetch,
useAdminClient,
} from "../../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../../context/auth/AdminClient";
import { SaveReset } from "./SaveReset";
import { useErrorHandler } from "react-error-boundary";
type AuthenticationOverridesProps = {
control: Control<Record<string, any>>;
@ -34,13 +30,10 @@ export const AuthenticationOverrides = ({
const adminClient = useAdminClient();
const { t } = useTranslation("clients");
const [flows, setFlows] = useState<JSX.Element[]>([]);
const handleError = useErrorHandler();
const [browserFlowOpen, setBrowserFlowOpen] = useState(false);
const [directGrantOpen, setDirectGrantOpen] = useState(false);
useEffect(
() =>
asyncStateFetch(
useFetch(
() => adminClient.authenticationManagement.getFlows(),
(flows) => {
let filteredFlows = [
@ -58,8 +51,6 @@ export const AuthenticationOverrides = ({
)),
]);
},
handleError
),
[]
);

View file

@ -24,10 +24,7 @@ import { useAlerts } from "../../components/alert/Alerts";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import {
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { ClientSecret } from "./ClientSecret";
import { SignedJWT } from "./SignedJWT";
@ -55,8 +52,12 @@ export type CredentialsProps = {
export const Credentials = ({ clientId, save }: CredentialsProps) => {
const { t } = useTranslation("clients");
const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { addAlert } = useAlerts();
const [providers, setProviders] = useState<ClientAuthenticatorProviders[]>(
[]
);
const {
control,
formState: { isDirty },
@ -64,17 +65,14 @@ export const Credentials = ({ clientId, save }: CredentialsProps) => {
const clientAuthenticatorType = useWatch({
control: control,
name: "clientAuthenticatorType",
defaultValue: "",
});
const [providers, setProviders] = useState<ClientAuthenticatorProviders[]>(
[]
);
const [secret, setSecret] = useState("");
const [accessToken, setAccessToken] = useState("");
const [open, isOpen] = useState(false);
useEffect(() => {
return asyncStateFetch(
useFetch(
async () => {
const providers = await adminClient.authenticationManagement.getClientAuthenticatorProviders(
{ id: clientId }
@ -92,9 +90,8 @@ export const Credentials = ({ clientId, save }: CredentialsProps) => {
setProviders(providers);
setSecret(secret);
},
handleError
[]
);
}, []);
async function regenerate<T>(
call: (clientId: string) => Promise<T>,
@ -164,6 +161,7 @@ export const Credentials = ({ clientId, save }: CredentialsProps) => {
<Controller
name="clientAuthenticatorType"
control={control}
defaultValue=""
render={({ onChange, value }) => (
<Select
toggleId="kc-client-authenticator-type"

View file

@ -25,13 +25,9 @@ import { FormAccess } from "../../components/form-access/FormAccess";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { ClientForm } from "../ClientDetails";
import { GenerateKeyDialog } from "./GenerateKeyDialog";
import {
asyncStateFetch,
useAdminClient,
} from "../../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../../context/auth/AdminClient";
import { useAlerts } from "../../components/alert/Alerts";
import { ImportKeyDialog, ImportFile } from "./ImportKeyDialog";
import { useErrorHandler } from "react-error-boundary";
type KeysProps = {
save: () => void;
@ -48,7 +44,6 @@ export const Keys = ({ clientId, save }: KeysProps) => {
formState: { isDirty },
} = useFormContext<ClientForm>();
const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const { addAlert } = useAlerts();
const [keyInfo, setKeyInfo] = useState<CertificateRepresentation>();
@ -60,13 +55,10 @@ export const Keys = ({ clientId, save }: KeysProps) => {
name: "attributes.use-jwks-url",
defaultValue: "false",
});
useEffect(
() =>
asyncStateFetch(
useFetch(
() => adminClient.clients.getKeyInfo({ id: clientId, attr }),
(info) => setKeyInfo(info),
errorHandler
),
[]
);

View file

@ -1,6 +1,5 @@
import React, { useContext, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import {
ClipboardCopy,
EmptyState,
@ -31,10 +30,7 @@ import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
import ProtocolMapperRepresentation from "keycloak-admin/lib/defs/protocolMapperRepresentation";
import { ProtocolMapperTypeRepresentation } from "keycloak-admin/lib/defs/serverInfoRepesentation";
import {
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { RealmContext } from "../../context/realm-context/RealmContext";
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
@ -149,14 +145,11 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
const tabContent2 = useRef(null);
const tabContent3 = useRef(null);
const handleError = useErrorHandler();
useEffect(() => {
return asyncStateFetch(
useFetch(
() => adminClient.clients.listOptionalClientScopes({ id: clientId }),
(optionalClientScopes) => setSelectableScopes(optionalClientScopes),
handleError
[]
);
}, []);
const toString = (user: UserRepresentation) => {
return (
@ -169,8 +162,7 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
);
};
useEffect(() => {
return asyncStateFetch(
useFetch(
() => {
if (userSearch.length > 2) {
return adminClient.users.find({ search: userSearch });
@ -189,12 +181,10 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
})
.map((user) => <SelectOption key={user.id} value={user} />)
),
handleError
[userSearch]
);
}, [userSearch]);
useEffect(() => {
return asyncStateFetch(
useFetch(
async () => {
const scope = selected.join(" ");
const effectiveRoles = await adminClient.clients.evaluatePermission({
@ -204,12 +194,10 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
type: "granted",
});
const mapperList = (await adminClient.clients.evaluateListProtocolMapper(
{
const mapperList = (await adminClient.clients.evaluateListProtocolMapper({
id: clientId,
scope,
}
)) as ({
})) as ({
type: ProtocolMapperTypeRepresentation;
} & ProtocolMapperRepresentation)[];
@ -229,12 +217,10 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
setProtocolMappers(mapperList);
refresh();
},
handleError
[selected]
);
}, [selected]);
useEffect(() => {
return asyncStateFetch(
useFetch(
() => {
const scope = selected.join(" ");
if (user) {
@ -250,9 +236,8 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
(accessToken) => {
setAccessToken(JSON.stringify(accessToken, undefined, 3));
},
handleError
[user, selected]
);
}, [user, selected]);
return (
<>

View file

@ -1,8 +1,7 @@
import React, { DependencyList, useEffect, useState } from "react";
import React, { DependencyList, useState } from "react";
import { Spinner } from "@patternfly/react-core";
import { useErrorHandler } from "react-error-boundary";
import { asyncStateFetch } from "../../context/auth/AdminClient";
import { useFetch } from "../../context/auth/AdminClient";
type DataLoaderProps<T> = {
loader: () => Promise<T>;
@ -12,15 +11,12 @@ type DataLoaderProps<T> = {
export function DataLoader<T>(props: DataLoaderProps<T>) {
const [data, setData] = useState<T | undefined>();
const handleError = useErrorHandler();
useEffect(() => {
return asyncStateFetch(
useFetch(
() => props.loader(),
(result) => setData(result),
handleError
props.deps || []
);
}, props.deps || []);
if (data) {
if (props.children instanceof Function) {

View file

@ -2,6 +2,7 @@ import React from "react";
import { DataLoader } from "../DataLoader";
import { act } from "@testing-library/react";
import { render, unmountComponentAtNode } from "react-dom";
import { MockAdminClient } from "../../../stories/MockAdminClient";
let container: HTMLDivElement;
beforeEach(() => {
@ -19,6 +20,7 @@ describe("<DataLoader />", () => {
const loader = () => Promise.resolve(["a", "b"]);
await act(async () => {
render(
<MockAdminClient>
<DataLoader loader={loader}>
{(result) => (
<div>
@ -27,7 +29,8 @@ describe("<DataLoader />", () => {
))}
</div>
)}
</DataLoader>,
</DataLoader>
</MockAdminClient>,
container
);
});

View file

@ -1,5 +1,4 @@
import React, { useState, useEffect, useContext } from "react";
import { useErrorHandler } from "react-error-boundary";
import React, { useState, useContext } from "react";
import {
Alert,
AlertVariant,
@ -19,10 +18,7 @@ import { ConfirmDialogModal } from "../confirm-dialog/ConfirmDialog";
import { HelpItem } from "../help-enabler/HelpItem";
import { useTranslation } from "react-i18next";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import {
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { HelpContext } from "../help-enabler/HelpHeader";
type DownloadDialogProps = {
@ -39,7 +35,6 @@ export const DownloadDialog = ({
protocol = "openid-connect",
}: DownloadDialogProps) => {
const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { t } = useTranslation("common");
const { enabled } = useContext(HelpContext);
const serverInfo = useServerInfo();
@ -51,8 +46,7 @@ export const DownloadDialog = ({
const [snippet, setSnippet] = useState("");
const [openType, setOpenType] = useState(false);
useEffect(() => {
return asyncStateFetch(
useFetch(
async () => {
const snippet = await adminClient.clients.getInstallationProviders({
id,
@ -65,9 +59,8 @@ export const DownloadDialog = ({
}
},
(snippet) => setSnippet(snippet),
handleError
[id, selected]
);
}, [id, selected]);
return (
<ConfirmDialogModal
titleKey={t("clients:downloadAdaptorTitle")}

View file

@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import _ from "lodash";
import {
Badge,
@ -18,10 +17,7 @@ import {
} from "@patternfly/react-core";
import { KeycloakDataTable } from "../table-toolbar/KeycloakDataTable";
import {
asyncStateFetch,
useAdminClient,
} from "../../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../../context/auth/AdminClient";
import ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentation";
import { FilterIcon } from "@patternfly/react-icons";
import { Row, ServiceRole } from "./RoleMapping";
@ -54,7 +50,6 @@ export const AddRoleMappingModal = ({
}: AddRoleMappingModalProps) => {
const { t } = useTranslation("clients");
const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const [clients, setClients] = useState<ClientRole[]>([]);
const [searchToggle, setSearchToggle] = useState(false);
@ -65,9 +60,7 @@ export const AddRoleMappingModal = ({
const [selectedClients, setSelectedClients] = useState<ClientRole[]>([]);
const [selectedRows, setSelectedRows] = useState<Row[]>([]);
useEffect(
() =>
asyncStateFetch(
useFetch(
async () => {
const clients = await adminClient.clients.find();
return (
@ -75,12 +68,10 @@ export const AddRoleMappingModal = ({
clients.map(async (client) => {
let roles: RoleRepresentation[] = [];
if (type === "service-account") {
roles = await adminClient.users.listAvailableClientRoleMappings(
{
roles = await adminClient.users.listAvailableClientRoleMappings({
id: id,
clientUniqueId: client.id!,
}
);
});
} else if (type === "client-scope") {
roles = await adminClient.clientScopes.listAvailableClientScopeMappings(
{
@ -105,8 +96,6 @@ export const AddRoleMappingModal = ({
(clients) => {
setClients(clients);
},
errorHandler
),
[]
);

View file

@ -1,4 +1,4 @@
import React, { Children } from "react";
import React, { Children, Fragment } from "react";
import { useTranslation } from "react-i18next";
import {
Grid,
@ -38,22 +38,18 @@ export const ScrollForm = ({
<Grid hasGutter {...rest}>
<GridItem span={8}>
{sections.map((cat, index) => (
<>
<Fragment key={cat}>
{!borders && (
<ScrollPanel
scrollId={spacesToHyphens(cat)}
key={cat}
title={cat}
>
<ScrollPanel scrollId={spacesToHyphens(cat)} title={cat}>
{nodes[index]}
</ScrollPanel>
)}
{borders && (
<FormPanel scrollId={spacesToHyphens(cat)} key={cat} title={cat}>
<FormPanel scrollId={spacesToHyphens(cat)} title={cat}>
{nodes[index]}
</FormPanel>
)}
</>
</Fragment>
))}
</GridItem>
<GridItem span={4}>

View file

@ -1,6 +1,5 @@
import React, { isValidElement, ReactNode, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import {
IAction,
IActions,
@ -16,7 +15,7 @@ import { Spinner } from "@patternfly/react-core";
import _ from "lodash";
import { PaginatingTableToolbar } from "./PaginatingTableToolbar";
import { asyncStateFetch } from "../../context/auth/AdminClient";
import { useFetch } from "../../context/auth/AdminClient";
import { ListEmptyState } from "../list-empty-state/ListEmptyState";
import { SVGIconProps } from "@patternfly/react-icons/dist/js/createIcon";
@ -181,7 +180,6 @@ export function KeycloakDataTable<T>({
const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
const handleError = useErrorHandler();
useEffect(() => {
if (canSelectAll) {
@ -199,27 +197,24 @@ export function KeycloakDataTable<T>({
}
}, [selected]);
useEffect(() => {
setLoading(true);
return asyncStateFetch(
useFetch(
async () => {
let data = unPaginatedData || (await loader(first, max, search));
setLoading(true);
return unPaginatedData || (await loader(first, max, search));
},
(data) => {
if (!isPaginated) {
setUnPaginatedData(data);
data = data.slice(first, first + max);
}
return convertToColumns(data);
},
(result) => {
const result = convertToColumns(data);
setRows(result);
setFilteredData(result);
setLoading(false);
},
handleError
[key, first, max, search]
);
}, [key, first, max, search]);
const getNodeText = (node: Cell<T>): string => {
if (["string", "number"].includes(typeof node)) {
@ -356,6 +351,7 @@ export function KeycloakDataTable<T>({
return (
<>
{!rows && loading && <Loading />}
{rows && (
<PaginatingTableToolbar
count={rows.length}

View file

@ -1,5 +1,8 @@
import { createContext, useContext } from "react";
import { createContext, DependencyList, useContext, useEffect } from "react";
import axios from "axios";
import KeycloakAdminClient from "keycloak-admin";
import { useErrorHandler } from "react-error-boundary";
export const AdminClient = createContext<KeycloakAdminClient | undefined>(
undefined
@ -15,37 +18,39 @@ export const useAdminClient = () => {
* It takes 2 functions one you do your adminClient call in and the other to set your state
*
* @example
* useEffect(() => {
* return asyncStateFetch(
* useFetch(
* () => adminClient.components.findOne({ id }),
* (component) => setupForm(component)
* (component) => setupForm(component),
* []
* );
* }, []);
*
* @param adminClientCall use this to do your adminClient call
* @param callback when the data is fetched this is where you set your state
* @param onError custom error handler
*/
export function asyncStateFetch<T>(
export function useFetch<T>(
adminClientCall: () => Promise<T>,
callback: (param: T) => void,
onError: (error: Error) => void
deps?: DependencyList
) {
let canceled = false;
const adminClient = useAdminClient();
const onError = useErrorHandler();
const source = axios.CancelToken.source();
adminClient.setConfig({ requestConfig: { cancelToken: source.token } });
useEffect(() => {
adminClientCall()
.then((result) => {
try {
if (!canceled) {
callback(result);
}
} catch (error) {
if (onError) onError(error);
}
})
.catch(onError);
.catch((error) => {
if (!axios.isCancel(error)) {
onError(error);
}
});
return () => {
canceled = true;
source.cancel();
};
}, deps);
}

View file

@ -1,10 +1,9 @@
import React, { useContext, useEffect, useState } from "react";
import React, { useContext, useState } from "react";
import _ from "lodash";
import RealmRepresentation from "keycloak-admin/lib/defs/realmRepresentation";
import { RecentUsed } from "../../components/realm-selector/recent-used";
import { useErrorHandler } from "react-error-boundary";
import { asyncStateFetch, useAdminClient } from "../auth/AdminClient";
import { useAdminClient, useFetch } from "../auth/AdminClient";
import { WhoAmIContext } from "../whoami/WhoAmI";
type RealmContextType = {
@ -30,7 +29,6 @@ export const RealmContextProvider = ({
const [realm, setRealm] = useState(whoAmI.getHomeRealm());
const [realms, setRealms] = useState<RealmRepresentation[]>([]);
const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const recentUsed = new RecentUsed();
const updateRealmsList = (realms: RealmRepresentation[]) => {
@ -38,13 +36,9 @@ export const RealmContextProvider = ({
recentUsed.clean(realms.map((r) => r.realm!));
};
useEffect(
() =>
asyncStateFetch(
useFetch(
() => adminClient.realms.find(),
(realms) => updateRealmsList(realms),
errorHandler
),
[]
);

View file

@ -1,11 +1,10 @@
import React, { useEffect, useState } from "react";
import { useErrorHandler } from "react-error-boundary";
import React, { useState } from "react";
import i18n from "../../i18n";
import { asyncStateFetch, useAdminClient } from "../auth/AdminClient";
import WhoAmIRepresentation, {
AccessType,
} from "keycloak-admin/lib/defs/whoAmIRepresentation";
import { useAdminClient, useFetch } from "../auth/AdminClient";
export class WhoAmI {
constructor(
@ -62,20 +61,17 @@ export const WhoAmIContext = React.createContext<WhoAmIProps>({
type WhoAmIProviderProps = { children: React.ReactNode };
export const WhoAmIContextProvider = ({ children }: WhoAmIProviderProps) => {
const adminClient = useAdminClient();
const handleError = useErrorHandler();
const [whoAmI, setWhoAmI] = useState<WhoAmI>(new WhoAmI());
const [key, setKey] = useState(0);
useEffect(() => {
return asyncStateFetch(
useFetch(
() => adminClient.whoAmI.find({ realm: "master" }),
(me) => {
const whoAmI = new WhoAmI(adminClient.keycloak?.realm, me);
setWhoAmI(whoAmI);
},
handleError
[key]
);
}, [key]);
return (
<WhoAmIContext.Provider value={{ refresh: () => setKey(key + 1), whoAmI }}>

View file

@ -1,7 +1,6 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { useHistory, useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import {
DropdownItem,
PageSection,
@ -14,7 +13,7 @@ import {
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
import { ViewHeader } from "../components/view-header/ViewHeader";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import { useAlerts } from "../components/alert/Alerts";
import { useRealm } from "../context/realm-context/RealmContext";
@ -35,7 +34,6 @@ export const GroupsSection = () => {
const { subGroups, setSubGroups, currentGroup } = useSubGroups();
const { addAlert } = useAlerts();
const { realm } = useRealm();
const errorHandler = useErrorHandler();
const [rename, setRename] = useState<string>();
@ -55,9 +53,7 @@ export const GroupsSection = () => {
return true;
};
useEffect(
() =>
asyncStateFetch(
useFetch(
async () => {
const ids = getId(location.pathname);
const isNavigationStateInValid = ids && ids.length > subGroups.length;
@ -75,8 +71,6 @@ export const GroupsSection = () => {
(groups: GroupRepresentation[]) => {
if (groups.length) setSubGroups(groups);
},
errorHandler
),
[id]
);

View file

@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import {
Breadcrumb,
BreadcrumbItem,
@ -23,7 +22,7 @@ import {
import { AngleRightIcon, SearchIcon } from "@patternfly/react-icons";
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
type MoveGroupDialogProps = {
@ -40,7 +39,6 @@ export const MoveGroupDialog = ({
const { t } = useTranslation("groups");
const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const [navigation, setNavigation] = useState<GroupRepresentation[]>([]);
const [groups, setGroups] = useState<GroupRepresentation[]>([]);
@ -50,9 +48,7 @@ export const MoveGroupDialog = ({
const [id, setId] = useState<string>();
const currentGroup = () => navigation[navigation.length - 1];
useEffect(
() =>
asyncStateFetch(
useFetch(
async () => {
if (id) {
const group = await adminClient.groups.findOne({ id });
@ -65,8 +61,6 @@ export const MoveGroupDialog = ({
if (selectedGroup) setNavigation([...navigation, selectedGroup]);
setGroups(groups.filter((g) => g.id !== group.id));
},
errorHandler
),
[id]
);

View file

@ -1,6 +1,5 @@
import React, { Fragment, useEffect, useState } from "react";
import React, { Fragment, useState } from "react";
import { Link, useHistory, useRouteMatch } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next";
import _ from "lodash";
import {
@ -26,7 +25,7 @@ import {
import IdentityProviderRepresentation from "keycloak-admin/lib/defs/identityProviderRepresentation";
import { ViewHeader } from "../components/view-header/ViewHeader";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { useRealm } from "../context/realm-context/RealmContext";
import { useAlerts } from "../components/alert/Alerts";
@ -58,19 +57,14 @@ export const IdentityProvidersSection = () => {
>();
const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const { addAlert } = useAlerts();
useEffect(
() =>
asyncStateFetch(
useFetch(
async () =>
(await adminClient.realms.findOne({ realm })).identityProviders!,
(providers) => {
setProviders(providers);
},
errorHandler
),
[]
);

View file

@ -1,5 +1,4 @@
import React, { useEffect, useState } from "react";
import { useErrorHandler } from "react-error-boundary";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import {
@ -12,10 +11,7 @@ import {
} from "@patternfly/react-core";
import AuthenticationFlowRepresentation from "keycloak-admin/lib/defs/authenticationFlowRepresentation";
import {
asyncStateFetch,
useAdminClient,
} from "../../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../../context/auth/AdminClient";
import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField";
import { HelpItem } from "../../components/help-enabler/HelpItem";
@ -30,19 +26,10 @@ const LoginFlow = ({
const { control } = useFormContext();
const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const [flows, setFlows] = useState<AuthenticationFlowRepresentation[]>();
const [open, setOpen] = useState(false);
useEffect(
() =>
asyncStateFetch(
() => adminClient.authenticationManagement.getFlows(),
setFlows,
errorHandler
),
[]
);
useFetch(() => adminClient.authenticationManagement.getFlows(), setFlows, []);
return (
<FormGroup

View file

@ -1,6 +1,5 @@
import React, { useEffect } from "react";
import React from "react";
import { useHistory, useParams } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next";
import { Controller, FormProvider, useForm } from "react-hook-form";
import {
@ -18,10 +17,7 @@ import IdentityProviderRepresentation from "keycloak-admin/lib/defs/identityProv
import { FormAccess } from "../../components/form-access/FormAccess";
import { ScrollForm } from "../../components/scroll-form/ScrollForm";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import {
asyncStateFetch,
useAdminClient,
} from "../../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../../context/auth/AdminClient";
import { toUpperCase } from "../../util";
import { GeneralSettings } from "./GeneralSettings";
import { AdvancedSettings } from "./AdvancedSettings";
@ -91,17 +87,12 @@ export const DetailSettings = () => {
const { addAlert } = useAlerts();
const history = useHistory();
const { realm } = useRealm();
const errorHandler = useErrorHandler();
useEffect(
() =>
asyncStateFetch(
useFetch(
() => adminClient.identityProviders.findOne({ alias: id }),
(provider) => {
Object.entries(provider).map((entry) => setValue(entry[0], entry[1]));
},
errorHandler
),
[]
);

View file

@ -10,13 +10,12 @@ import {
ModalVariant,
} from "@patternfly/react-core";
import { useTranslation } from "react-i18next";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
import { CaretDownIcon, FilterIcon } from "@patternfly/react-icons";
import _ from "lodash";
import { useErrorHandler } from "react-error-boundary";
type Role = RoleRepresentation & {
clientId?: string;
@ -34,7 +33,6 @@ export const AssociatedRolesModal = (props: AssociatedRolesModalProps) => {
const [name, setName] = useState("");
const adminClient = useAdminClient();
const [selectedRows, setSelectedRows] = useState<RoleRepresentation[]>([]);
const errorHandler = useErrorHandler();
const [isFilterDropdownOpen, setIsFilterDropdownOpen] = useState(false);
const [filterType, setFilterType] = useState("roles");
@ -129,17 +127,19 @@ export const AssociatedRolesModal = (props: AssociatedRolesModalProps) => {
refresh();
}, [filterType]);
useEffect(() => {
if (id) {
return asyncStateFetch(
() => adminClient.roles.findOneById({ id }),
(fetchedRole) => setName(fetchedRole.name!),
errorHandler
);
useFetch(
async () => {
if (id) return await adminClient.roles.findOneById({ id });
},
(fetchedRole) => {
if (fetchedRole) {
setName(fetchedRole.name!);
} else {
setName(t("createRole"));
}
}, []);
},
[]
);
const onFilterDropdownToggle = () => {
setIsFilterDropdownOpen(!isFilterDropdownOpen);

View file

@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { useErrorHandler } from "react-error-boundary";
import {
AlertVariant,
ButtonVariant,
@ -17,7 +16,7 @@ import {
import RealmRepresentation from "keycloak-admin/lib/defs/realmRepresentation";
import { toUpperCase } from "../util";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { useAdminClient, asyncStateFetch } from "../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { useRealm } from "../context/realm-context/RealmContext";
import { ViewHeader } from "../components/view-header/ViewHeader";
import { useAlerts } from "../components/alert/Alerts";
@ -124,7 +123,6 @@ const RealmSettingsHeader = ({
export const RealmSettingsSection = () => {
const { t } = useTranslation("realm-settings");
const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { realm: realmName } = useRealm();
const { addAlert } = useAlerts();
const form = useForm();
@ -136,16 +134,14 @@ export const RealmSettingsSection = () => {
ComponentRepresentation[]
>([]);
useEffect(() => {
return asyncStateFetch(
useFetch(
() => adminClient.realms.findOne({ realm: realmName }),
(realm) => {
setupForm(realm);
setRealm(realm);
},
handleError
[]
);
}, []);
useEffect(() => {
const update = async () => {

View file

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React from "react";
import {
ActionGroup,
AlertVariant,
@ -26,7 +26,7 @@ import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresenta
import { Controller, useForm } from "react-hook-form";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { useAlerts } from "../components/alert/Alerts";
import { useTranslation } from "react-i18next";
import { ViewHeader } from "../components/view-header/ViewHeader";
@ -35,7 +35,6 @@ import { ScrollForm } from "../components/scroll-form/ScrollForm";
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
import { LdapMapperList } from "./ldap/mappers/LdapMapperList";
import { useErrorHandler } from "react-error-boundary";
type ldapComponentRepresentation = ComponentRepresentation & {
config?: {
@ -179,24 +178,24 @@ export const UserFederationLdapSettings = () => {
const history = useHistory();
const adminClient = useAdminClient();
const { realm } = useRealm();
const errorHandler = useErrorHandler();
const { id } = useParams<{ id: string }>();
const { addAlert } = useAlerts();
useEffect(() => {
useFetch(
async () => {
if (id) {
return asyncStateFetch(
() => adminClient.components.findOne({ id }),
return await adminClient.components.findOne({ id });
}
return undefined;
},
(fetchedComponent) => {
if (fetchedComponent) {
setupForm(fetchedComponent);
}
},
errorHandler
[]
);
}
}, []);
const setupForm = (component: ComponentRepresentation) => {
Object.entries(component).map((entry) => {

View file

@ -1,6 +1,5 @@
import React, { useContext, useEffect, useState } from "react";
import React, { useContext, useState } from "react";
import { useHistory, useRouteMatch } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import {
AlertVariant,
ButtonVariant,
@ -24,7 +23,7 @@ import { ViewHeader } from "../components/view-header/ViewHeader";
import { DatabaseIcon } from "@patternfly/react-icons";
import { useTranslation } from "react-i18next";
import { RealmContext } from "../context/realm-context/RealmContext";
import { useAdminClient, asyncStateFetch } from "../context/auth/AdminClient";
import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import "./user-federation.css";
@ -40,12 +39,10 @@ export const UserFederationSection = () => {
const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
const handleError = useErrorHandler();
const { url } = useRouteMatch();
const history = useHistory();
useEffect(() => {
return asyncStateFetch(
useFetch(
() => {
const testParams: { [name: string]: string | number } = {
parentId: realm,
@ -56,9 +53,8 @@ export const UserFederationSection = () => {
(userFederations) => {
setUserFederations(userFederations);
},
handleError
[key]
);
}, [key]);
const ufAddProviderDropdownItems = [
<DropdownItem

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import {
Breadcrumb,
BreadcrumbItem,
@ -20,10 +20,9 @@ import {
ToolbarItem,
} from "@patternfly/react-core";
import { useTranslation } from "react-i18next";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import { AngleRightIcon, SearchIcon } from "@patternfly/react-icons";
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
import { useErrorHandler } from "react-error-boundary";
import _ from "lodash";
import { useParams } from "react-router-dom";
@ -52,8 +51,6 @@ export const JoinGroupDialog = ({
const adminClient = useAdminClient();
const [selectedRows, setSelectedRows] = useState<Group[]>([]);
const errorHandler = useErrorHandler();
const [navigation, setNavigation] = useState<Group[]>([]);
const [groups, setGroups] = useState<Group[]>([]);
const [filtered, setFiltered] = useState<GroupRepresentation[]>();
@ -63,9 +60,7 @@ export const JoinGroupDialog = ({
const { id } = useParams<{ id: string }>();
useEffect(
() =>
asyncStateFetch(
useFetch(
async () => {
const allGroups = await adminClient.groups.find();
@ -97,8 +92,6 @@ export const JoinGroupDialog = ({
? setGroups(groups)
: setGroups([...groups.filter((row) => !chips.includes(row.name))]);
},
errorHandler
),
[groupId]
);

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import {
ActionGroup,
AlertVariant,
@ -19,8 +19,7 @@ import { FormAccess } from "../components/form-access/FormAccess";
import UserRepresentation from "keycloak-admin/lib/defs/userRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem";
import { useRealm } from "../context/realm-context/RealmContext";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useErrorHandler } from "react-error-boundary";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import moment from "moment";
import { JoinGroupDialog } from "./JoinGroupDialog";
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
@ -51,7 +50,6 @@ export const UserForm = ({
const history = useHistory();
const adminClient = useAdminClient();
const { id } = useParams<{ id: string }>();
const handleError = useErrorHandler();
const watchUsernameInput = watch("username");
const [timestamp, setTimestamp] = useState(null);
@ -64,17 +62,15 @@ export const UserForm = ({
const [open, setOpen] = useState(false);
useEffect(() => {
if (editMode) {
return asyncStateFetch(
() => adminClient.users.findOne({ id: id }),
(user) => {
setupForm(user);
useFetch(
async () => {
if (editMode) return await adminClient.users.findOne({ id: id });
},
handleError
(user) => {
if (user) setupForm(user);
},
[chips]
);
}
}, [chips]);
const setupForm = (user: UserRepresentation) => {
reset();

View file

@ -14,10 +14,9 @@ import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable
import { useAlerts } from "../components/alert/Alerts";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { emptyFormatter } from "../util";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
import { cellWidth } from "@patternfly/react-table";
import { useErrorHandler } from "react-error-boundary";
import _ from "lodash";
import UserRepresentation from "keycloak-admin/lib/defs/userRepresentation";
import { JoinGroupDialog } from "./JoinGroupDialog";
@ -43,7 +42,6 @@ export const UserGroups = () => {
const { addAlert } = useAlerts();
const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
const handleError = useErrorHandler();
const [selectedGroup, setSelectedGroup] = useState<GroupRepresentation>();
const [list, setList] = useState(false);
@ -177,17 +175,13 @@ export const UserGroups = () => {
return alphabetize(filterDupesfromGroups);
};
useEffect(() => {
return asyncStateFetch(
() => {
return Promise.resolve(adminClient.users.listGroups({ id }));
},
useFetch(
() => adminClient.users.listGroups({ id }),
(response) => {
setListGroups(!!(response && response.length > 0));
},
handleError
[]
);
}, []);
useEffect(() => {
refresh();

View file

@ -1,5 +1,4 @@
import React, { useContext, useEffect, useState } from "react";
import { useErrorHandler } from "react-error-boundary";
import React, { useContext, useState } from "react";
import { useTranslation } from "react-i18next";
import {
AlertVariant,
@ -17,7 +16,7 @@ import {
} from "@patternfly/react-icons";
import UserRepresentation from "keycloak-admin/lib/defs/userRepresentation";
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import { useFetch, useAdminClient } from "../context/auth/AdminClient";
import { ViewHeader } from "../components/view-header/ViewHeader";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { useAlerts } from "../components/alert/Alerts";
@ -36,7 +35,6 @@ type BruteUser = UserRepresentation & {
export const UsersSection = () => {
const { t } = useTranslation("users");
const handleError = useErrorHandler();
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const { realm: realmName } = useContext(RealmContext);
@ -50,8 +48,7 @@ export const UsersSection = () => {
const [key, setKey] = useState("");
const refresh = () => setKey(`${new Date().getTime()}`);
useEffect(() => {
return asyncStateFetch(
useFetch(
() => {
const testParams = {
type: "org.keycloak.storage.UserStorageProvider",
@ -68,9 +65,8 @@ export const UsersSection = () => {
!((response[0] && response[0].length > 0) || response[1] > 100)
);
},
handleError
[]
);
}, []);
const UserDetailLink = (user: UserRepresentation) => (
<>

View file

@ -5974,7 +5974,7 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
axios@^0.21.0:
axios@^0.21.0, axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==