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-core": "4.115.1",
"@patternfly/react-icons": "4.10.1", "@patternfly/react-icons": "4.10.1",
"@patternfly/react-table": "4.26.7", "@patternfly/react-table": "4.26.7",
"axios": "^0.21.1",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"i18next": "^19.6.2", "i18next": "^19.6.2",
"keycloak-admin": "1.14.16", "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 { useHistory, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { useErrorHandler } from "react-error-boundary";
import { import {
FormGroup, FormGroup,
PageSection, PageSection,
@ -24,10 +23,7 @@ import ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentation";
import ProtocolMapperRepresentation from "keycloak-admin/lib/defs/protocolMapperRepresentation"; import ProtocolMapperRepresentation from "keycloak-admin/lib/defs/protocolMapperRepresentation";
import { useAlerts } from "../../components/alert/Alerts"; import { useAlerts } from "../../components/alert/Alerts";
import { RealmContext } from "../../context/realm-context/RealmContext"; import { RealmContext } from "../../context/realm-context/RealmContext";
import { import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { ViewHeader } from "../../components/view-header/ViewHeader"; import { ViewHeader } from "../../components/view-header/ViewHeader";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
@ -36,7 +32,6 @@ import { FormAccess } from "../../components/form-access/FormAccess";
export const RoleMappingForm = () => { export const RoleMappingForm = () => {
const { realm } = useContext(RealmContext); const { realm } = useContext(RealmContext);
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const handleError = useErrorHandler();
const history = useHistory(); const history = useHistory();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
@ -51,8 +46,7 @@ export const RoleMappingForm = () => {
const [selectedClient, setSelectedClient] = useState<ClientRepresentation>(); const [selectedClient, setSelectedClient] = useState<ClientRepresentation>();
const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>([]); const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>([]);
useEffect(() => { useFetch(
return asyncStateFetch(
async () => { async () => {
const clients = await adminClient.clients.find(); const clients = await adminClient.clients.find();
@ -77,12 +71,10 @@ export const RoleMappingForm = () => {
return filteredClients; return filteredClients;
}, },
(filteredClients) => setClients(filteredClients), (filteredClients) => setClients(filteredClients),
handleError []
); );
}, []);
useEffect(() => { useFetch(
return asyncStateFetch(
async () => { async () => {
const client = selectedClient as ClientRepresentation; const client = selectedClient as ClientRepresentation;
if (client && client.name !== "realmRoles") { if (client && client.name !== "realmRoles") {
@ -95,9 +87,8 @@ export const RoleMappingForm = () => {
} }
}, },
(clientRoles) => setClientRoles(clientRoles), (clientRoles) => setClientRoles(clientRoles),
handleError [selectedClient]
); );
}, [selectedClient]);
const save = async (mapping: ProtocolMapperRepresentation) => { const save = async (mapping: ProtocolMapperRepresentation) => {
try { 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 { useHistory, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
@ -24,10 +23,7 @@ import { ConfigPropertyRepresentation } from "keycloak-admin/lib/defs/configProp
import ProtocolMapperRepresentation from "keycloak-admin/lib/defs/protocolMapperRepresentation"; import ProtocolMapperRepresentation from "keycloak-admin/lib/defs/protocolMapperRepresentation";
import { ViewHeader } from "../../components/view-header/ViewHeader"; import { ViewHeader } from "../../components/view-header/ViewHeader";
import { import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { useAlerts } from "../../components/alert/Alerts"; import { useAlerts } from "../../components/alert/Alerts";
@ -45,7 +41,6 @@ type Params = {
export const MappingDetails = () => { export const MappingDetails = () => {
const { t } = useTranslation("client-scopes"); const { t } = useTranslation("client-scopes");
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const { id, mapperId } = useParams<Params>(); const { id, mapperId } = useParams<Params>();
@ -61,8 +56,7 @@ export const MappingDetails = () => {
const serverInfo = useServerInfo(); const serverInfo = useServerInfo();
const isGuid = /^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$/; const isGuid = /^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$/;
useEffect(() => { useFetch(
return asyncStateFetch(
async () => { async () => {
if (mapperId.match(isGuid)) { if (mapperId.match(isGuid)) {
const data = await adminClient.clientScopes.findProtocolMapper({ const data = await adminClient.clientScopes.findProtocolMapper({
@ -104,9 +98,8 @@ export const MappingDetails = () => {
setConfigProperties(result.configProperties); setConfigProperties(result.configProperties);
setMapping(result.mapping); setMapping(result.mapping);
}, },
handleError []
); );
}, []);
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: "common:deleteMappingTitle", 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 { useParams } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
AlertVariant, AlertVariant,
@ -11,10 +10,7 @@ import {
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation"; import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation";
import { import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { KeycloakTabs } from "../../components/keycloak-tabs/KeycloakTabs"; import { KeycloakTabs } from "../../components/keycloak-tabs/KeycloakTabs";
import { useAlerts } from "../../components/alert/Alerts"; import { useAlerts } from "../../components/alert/Alerts";
import { ViewHeader } from "../../components/view-header/ViewHeader"; import { ViewHeader } from "../../components/view-header/ViewHeader";
@ -30,7 +26,6 @@ export const ClientScopeForm = () => {
const [hide, setHide] = useState(false); const [hide, setHide] = useState(false);
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
@ -38,8 +33,7 @@ export const ClientScopeForm = () => {
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime()); const refresh = () => setKey(new Date().getTime());
useEffect(() => { useFetch(
return asyncStateFetch(
async () => { async () => {
if (id) { if (id) {
return await adminClient.clientScopes.findOne({ id }); return await adminClient.clientScopes.findOne({ id });
@ -48,9 +42,8 @@ export const ClientScopeForm = () => {
(clientScope) => { (clientScope) => {
setClientScope(clientScope); setClientScope(clientScope);
}, },
handleError [key, id]
); );
}, [key, id]);
const loader = async () => { const loader = async () => {
const assignedRoles = hide const assignedRoles = hide

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { import {
Alert, Alert,
AlertVariant, AlertVariant,
@ -12,9 +12,8 @@ import {
TabTitleText, TabTitleText,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useHistory, useParams } from "react-router-dom"; import { useHistory, useParams } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next"; 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 ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentation";
import _ from "lodash"; import _ from "lodash";
@ -26,7 +25,7 @@ import {
} from "../components/confirm-dialog/ConfirmDialog"; } from "../components/confirm-dialog/ConfirmDialog";
import { DownloadDialog } from "../components/download-dialog/DownloadDialog"; import { DownloadDialog } from "../components/download-dialog/DownloadDialog";
import { ViewHeader } from "../components/view-header/ViewHeader"; 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 { Credentials } from "./credentials/Credentials";
import { import {
convertFormValuesToObject, convertFormValuesToObject,
@ -125,7 +124,6 @@ export const ClientDetails = () => {
const { t } = useTranslation("clients"); const { t } = useTranslation("clients");
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const handleError = useErrorHandler();
const { realm } = useRealm(); const { realm } = useRealm();
const history = useHistory(); const history = useHistory();
@ -140,6 +138,12 @@ export const ClientDetails = () => {
const form = useForm<ClientForm>(); const form = useForm<ClientForm>();
const { clientId } = useParams<{ clientId: string }>(); const { clientId } = useParams<{ clientId: string }>();
const clientAuthenticatorType = useWatch({
control: form.control,
name: "clientAuthenticatorType",
defaultValue: "client-secret",
});
const [client, setClient] = useState<ClientRepresentation>(); const [client, setClient] = useState<ClientRepresentation>();
const loader = async () => { const loader = async () => {
@ -178,16 +182,14 @@ export const ClientDetails = () => {
}); });
}; };
useEffect(() => { useFetch(
return asyncStateFetch(
() => adminClient.clients.findOne({ id: clientId }), () => adminClient.clients.findOne({ id: clientId }),
(fetchedClient) => { (fetchedClient) => {
setClient(fetchedClient); setClient(fetchedClient);
setupForm(fetchedClient); setupForm(fetchedClient);
}, },
handleError [clientId]
); );
}, [clientId]);
const save = async ( const save = async (
{ confirmed = false, messageKey = "clientSaveSuccess" }: SaveOptions = { { confirmed = false, messageKey = "clientSaveSuccess" }: SaveOptions = {
@ -198,8 +200,7 @@ export const ClientDetails = () => {
if (await form.trigger()) { if (await form.trigger()) {
if ( if (
!client?.publicClient && !client?.publicClient &&
client?.clientAuthenticatorType !== client?.clientAuthenticatorType !== clientAuthenticatorType &&
form.getValues("clientAuthenticatorType") &&
!confirmed !confirmed
) { ) {
toggleChangeAuthenticator(); toggleChangeAuthenticator();
@ -241,7 +242,7 @@ export const ClientDetails = () => {
<ConfirmDialogModal <ConfirmDialogModal
continueButtonLabel="common:yes" continueButtonLabel="common:yes"
titleKey={t("changeAuthenticatorConfirmTitle", { titleKey={t("changeAuthenticatorConfirmTitle", {
clientAuthenticatorType: form.getValues("clientAuthenticatorType"), clientAuthenticatorType: clientAuthenticatorType,
})} })}
open={changeAuthenticatorOpen} open={changeAuthenticatorOpen}
toggleDialog={toggleChangeAuthenticator} toggleDialog={toggleChangeAuthenticator}
@ -249,9 +250,9 @@ export const ClientDetails = () => {
> >
<> <>
{t("changeAuthenticatorConfirm", { {t("changeAuthenticatorConfirm", {
clientAuthenticatorType: form.getValues("clientAuthenticatorType"), clientAuthenticatorType: clientAuthenticatorType,
})} })}
{form.getValues("clientAuthenticatorType") === "client-jwt" && ( {clientAuthenticatorType === "client-jwt" && (
<Alert variant="info" isInline title={t("signedJWTConfirm")} /> <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 { Link, useHistory } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
@ -49,8 +49,6 @@ export const ClientsSection = () => {
return await adminClient.clients.find({ ...params }); return await adminClient.clients.find({ ...params });
}; };
useEffect(refresh, [selectedClient]);
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: t("clientDelete", { clientId: selectedClient?.clientId }), titleKey: t("clientDelete", { clientId: selectedClient?.clientId }),
messageKey: "clients:clientDeleteConfirm", messageKey: "clients:clientDeleteConfirm",
@ -62,7 +60,7 @@ export const ClientsSection = () => {
id: selectedClient!.id!, id: selectedClient!.id!,
}); });
addAlert(t("clientDeletedSuccess"), AlertVariant.success); addAlert(t("clientDeletedSuccess"), AlertVariant.success);
setSelectedClient(undefined); refresh();
} catch (error) { } catch (error) {
addAlert(t("clientDeleteError", { error }), AlertVariant.danger); 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 { Control, Controller } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import _ from "lodash"; import _ from "lodash";
@ -11,12 +11,8 @@ import {
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { import { useFetch, useAdminClient } from "../../context/auth/AdminClient";
asyncStateFetch,
useAdminClient,
} from "../../context/auth/AdminClient";
import { SaveReset } from "./SaveReset"; import { SaveReset } from "./SaveReset";
import { useErrorHandler } from "react-error-boundary";
type AuthenticationOverridesProps = { type AuthenticationOverridesProps = {
control: Control<Record<string, any>>; control: Control<Record<string, any>>;
@ -34,13 +30,10 @@ export const AuthenticationOverrides = ({
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { t } = useTranslation("clients"); const { t } = useTranslation("clients");
const [flows, setFlows] = useState<JSX.Element[]>([]); const [flows, setFlows] = useState<JSX.Element[]>([]);
const handleError = useErrorHandler();
const [browserFlowOpen, setBrowserFlowOpen] = useState(false); const [browserFlowOpen, setBrowserFlowOpen] = useState(false);
const [directGrantOpen, setDirectGrantOpen] = useState(false); const [directGrantOpen, setDirectGrantOpen] = useState(false);
useEffect( useFetch(
() =>
asyncStateFetch(
() => adminClient.authenticationManagement.getFlows(), () => adminClient.authenticationManagement.getFlows(),
(flows) => { (flows) => {
let filteredFlows = [ 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 { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
useAdminClient,
asyncStateFetch,
} from "../../context/auth/AdminClient";
import { ClientSecret } from "./ClientSecret"; import { ClientSecret } from "./ClientSecret";
import { SignedJWT } from "./SignedJWT"; import { SignedJWT } from "./SignedJWT";
@ -55,8 +52,12 @@ export type CredentialsProps = {
export const Credentials = ({ clientId, save }: CredentialsProps) => { export const Credentials = ({ clientId, save }: CredentialsProps) => {
const { t } = useTranslation("clients"); const { t } = useTranslation("clients");
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const handleError = useErrorHandler();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const [providers, setProviders] = useState<ClientAuthenticatorProviders[]>(
[]
);
const { const {
control, control,
formState: { isDirty }, formState: { isDirty },
@ -64,17 +65,14 @@ export const Credentials = ({ clientId, save }: CredentialsProps) => {
const clientAuthenticatorType = useWatch({ const clientAuthenticatorType = useWatch({
control: control, control: control,
name: "clientAuthenticatorType", name: "clientAuthenticatorType",
defaultValue: "",
}); });
const [providers, setProviders] = useState<ClientAuthenticatorProviders[]>(
[]
);
const [secret, setSecret] = useState(""); const [secret, setSecret] = useState("");
const [accessToken, setAccessToken] = useState(""); const [accessToken, setAccessToken] = useState("");
const [open, isOpen] = useState(false); const [open, isOpen] = useState(false);
useEffect(() => { useFetch(
return asyncStateFetch(
async () => { async () => {
const providers = await adminClient.authenticationManagement.getClientAuthenticatorProviders( const providers = await adminClient.authenticationManagement.getClientAuthenticatorProviders(
{ id: clientId } { id: clientId }
@ -92,9 +90,8 @@ export const Credentials = ({ clientId, save }: CredentialsProps) => {
setProviders(providers); setProviders(providers);
setSecret(secret); setSecret(secret);
}, },
handleError []
); );
}, []);
async function regenerate<T>( async function regenerate<T>(
call: (clientId: string) => Promise<T>, call: (clientId: string) => Promise<T>,
@ -164,6 +161,7 @@ export const Credentials = ({ clientId, save }: CredentialsProps) => {
<Controller <Controller
name="clientAuthenticatorType" name="clientAuthenticatorType"
control={control} control={control}
defaultValue=""
render={({ onChange, value }) => ( render={({ onChange, value }) => (
<Select <Select
toggleId="kc-client-authenticator-type" 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 { Controller, useFormContext, useWatch } from "react-hook-form";
import { ClientForm } from "../ClientDetails"; import { ClientForm } from "../ClientDetails";
import { GenerateKeyDialog } from "./GenerateKeyDialog"; import { GenerateKeyDialog } from "./GenerateKeyDialog";
import { import { useFetch, useAdminClient } from "../../context/auth/AdminClient";
asyncStateFetch,
useAdminClient,
} from "../../context/auth/AdminClient";
import { useAlerts } from "../../components/alert/Alerts"; import { useAlerts } from "../../components/alert/Alerts";
import { ImportKeyDialog, ImportFile } from "./ImportKeyDialog"; import { ImportKeyDialog, ImportFile } from "./ImportKeyDialog";
import { useErrorHandler } from "react-error-boundary";
type KeysProps = { type KeysProps = {
save: () => void; save: () => void;
@ -48,7 +44,6 @@ export const Keys = ({ clientId, save }: KeysProps) => {
formState: { isDirty }, formState: { isDirty },
} = useFormContext<ClientForm>(); } = useFormContext<ClientForm>();
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const [keyInfo, setKeyInfo] = useState<CertificateRepresentation>(); const [keyInfo, setKeyInfo] = useState<CertificateRepresentation>();
@ -60,13 +55,10 @@ export const Keys = ({ clientId, save }: KeysProps) => {
name: "attributes.use-jwks-url", name: "attributes.use-jwks-url",
defaultValue: "false", defaultValue: "false",
}); });
useEffect(
() => useFetch(
asyncStateFetch(
() => adminClient.clients.getKeyInfo({ id: clientId, attr }), () => adminClient.clients.getKeyInfo({ id: clientId, attr }),
(info) => setKeyInfo(info), (info) => setKeyInfo(info),
errorHandler
),
[] []
); );

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,5 @@
import React, { isValidElement, ReactNode, useEffect, useState } from "react"; import React, { isValidElement, ReactNode, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import { import {
IAction, IAction,
IActions, IActions,
@ -16,7 +15,7 @@ import { Spinner } from "@patternfly/react-core";
import _ from "lodash"; import _ from "lodash";
import { PaginatingTableToolbar } from "./PaginatingTableToolbar"; import { PaginatingTableToolbar } from "./PaginatingTableToolbar";
import { asyncStateFetch } from "../../context/auth/AdminClient"; import { useFetch } from "../../context/auth/AdminClient";
import { ListEmptyState } from "../list-empty-state/ListEmptyState"; import { ListEmptyState } from "../list-empty-state/ListEmptyState";
import { SVGIconProps } from "@patternfly/react-icons/dist/js/createIcon"; import { SVGIconProps } from "@patternfly/react-icons/dist/js/createIcon";
@ -181,7 +180,6 @@ export function KeycloakDataTable<T>({
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime()); const refresh = () => setKey(new Date().getTime());
const handleError = useErrorHandler();
useEffect(() => { useEffect(() => {
if (canSelectAll) { if (canSelectAll) {
@ -199,27 +197,24 @@ export function KeycloakDataTable<T>({
} }
}, [selected]); }, [selected]);
useEffect(() => { useFetch(
setLoading(true);
return asyncStateFetch(
async () => { async () => {
let data = unPaginatedData || (await loader(first, max, search)); setLoading(true);
return unPaginatedData || (await loader(first, max, search));
},
(data) => {
if (!isPaginated) { if (!isPaginated) {
setUnPaginatedData(data); setUnPaginatedData(data);
data = data.slice(first, first + max); data = data.slice(first, first + max);
} }
return convertToColumns(data); const result = convertToColumns(data);
},
(result) => {
setRows(result); setRows(result);
setFilteredData(result); setFilteredData(result);
setLoading(false); setLoading(false);
}, },
handleError [key, first, max, search]
); );
}, [key, first, max, search]);
const getNodeText = (node: Cell<T>): string => { const getNodeText = (node: Cell<T>): string => {
if (["string", "number"].includes(typeof node)) { if (["string", "number"].includes(typeof node)) {
@ -356,6 +351,7 @@ export function KeycloakDataTable<T>({
return ( return (
<> <>
{!rows && loading && <Loading />}
{rows && ( {rows && (
<PaginatingTableToolbar <PaginatingTableToolbar
count={rows.length} 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 KeycloakAdminClient from "keycloak-admin";
import { useErrorHandler } from "react-error-boundary";
export const AdminClient = createContext<KeycloakAdminClient | undefined>( export const AdminClient = createContext<KeycloakAdminClient | undefined>(
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 * It takes 2 functions one you do your adminClient call in and the other to set your state
* *
* @example * @example
* useEffect(() => { * useFetch(
* return asyncStateFetch(
* () => adminClient.components.findOne({ id }), * () => adminClient.components.findOne({ id }),
* (component) => setupForm(component) * (component) => setupForm(component),
* []
* ); * );
* }, []);
* *
* @param adminClientCall use this to do your adminClient call * @param adminClientCall use this to do your adminClient call
* @param callback when the data is fetched this is where you set your state * @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>, adminClientCall: () => Promise<T>,
callback: (param: T) => void, 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() adminClientCall()
.then((result) => { .then((result) => {
try {
if (!canceled) {
callback(result); callback(result);
}
} catch (error) {
if (onError) onError(error);
}
}) })
.catch(onError); .catch((error) => {
if (!axios.isCancel(error)) {
onError(error);
}
});
return () => { 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 _ from "lodash";
import RealmRepresentation from "keycloak-admin/lib/defs/realmRepresentation"; import RealmRepresentation from "keycloak-admin/lib/defs/realmRepresentation";
import { RecentUsed } from "../../components/realm-selector/recent-used"; import { RecentUsed } from "../../components/realm-selector/recent-used";
import { useErrorHandler } from "react-error-boundary"; import { useAdminClient, useFetch } from "../auth/AdminClient";
import { asyncStateFetch, useAdminClient } from "../auth/AdminClient";
import { WhoAmIContext } from "../whoami/WhoAmI"; import { WhoAmIContext } from "../whoami/WhoAmI";
type RealmContextType = { type RealmContextType = {
@ -30,7 +29,6 @@ export const RealmContextProvider = ({
const [realm, setRealm] = useState(whoAmI.getHomeRealm()); const [realm, setRealm] = useState(whoAmI.getHomeRealm());
const [realms, setRealms] = useState<RealmRepresentation[]>([]); const [realms, setRealms] = useState<RealmRepresentation[]>([]);
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const recentUsed = new RecentUsed(); const recentUsed = new RecentUsed();
const updateRealmsList = (realms: RealmRepresentation[]) => { const updateRealmsList = (realms: RealmRepresentation[]) => {
@ -38,13 +36,9 @@ export const RealmContextProvider = ({
recentUsed.clean(realms.map((r) => r.realm!)); recentUsed.clean(realms.map((r) => r.realm!));
}; };
useEffect( useFetch(
() =>
asyncStateFetch(
() => adminClient.realms.find(), () => adminClient.realms.find(),
(realms) => updateRealmsList(realms), (realms) => updateRealmsList(realms),
errorHandler
),
[] []
); );

View file

@ -1,11 +1,10 @@
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { useErrorHandler } from "react-error-boundary";
import i18n from "../../i18n"; import i18n from "../../i18n";
import { asyncStateFetch, useAdminClient } from "../auth/AdminClient";
import WhoAmIRepresentation, { import WhoAmIRepresentation, {
AccessType, AccessType,
} from "keycloak-admin/lib/defs/whoAmIRepresentation"; } from "keycloak-admin/lib/defs/whoAmIRepresentation";
import { useAdminClient, useFetch } from "../auth/AdminClient";
export class WhoAmI { export class WhoAmI {
constructor( constructor(
@ -62,20 +61,17 @@ export const WhoAmIContext = React.createContext<WhoAmIProps>({
type WhoAmIProviderProps = { children: React.ReactNode }; type WhoAmIProviderProps = { children: React.ReactNode };
export const WhoAmIContextProvider = ({ children }: WhoAmIProviderProps) => { export const WhoAmIContextProvider = ({ children }: WhoAmIProviderProps) => {
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const handleError = useErrorHandler();
const [whoAmI, setWhoAmI] = useState<WhoAmI>(new WhoAmI()); const [whoAmI, setWhoAmI] = useState<WhoAmI>(new WhoAmI());
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
useEffect(() => { useFetch(
return asyncStateFetch(
() => adminClient.whoAmI.find({ realm: "master" }), () => adminClient.whoAmI.find({ realm: "master" }),
(me) => { (me) => {
const whoAmI = new WhoAmI(adminClient.keycloak?.realm, me); const whoAmI = new WhoAmI(adminClient.keycloak?.realm, me);
setWhoAmI(whoAmI); setWhoAmI(whoAmI);
}, },
handleError [key]
); );
}, [key]);
return ( return (
<WhoAmIContext.Provider value={{ refresh: () => setKey(key + 1), whoAmI }}> <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 { useHistory, useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import { import {
DropdownItem, DropdownItem,
PageSection, PageSection,
@ -14,7 +13,7 @@ import {
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation"; import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
import { ViewHeader } from "../components/view-header/ViewHeader"; 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 { useAlerts } from "../components/alert/Alerts";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
@ -35,7 +34,6 @@ export const GroupsSection = () => {
const { subGroups, setSubGroups, currentGroup } = useSubGroups(); const { subGroups, setSubGroups, currentGroup } = useSubGroups();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const { realm } = useRealm(); const { realm } = useRealm();
const errorHandler = useErrorHandler();
const [rename, setRename] = useState<string>(); const [rename, setRename] = useState<string>();
@ -55,9 +53,7 @@ export const GroupsSection = () => {
return true; return true;
}; };
useEffect( useFetch(
() =>
asyncStateFetch(
async () => { async () => {
const ids = getId(location.pathname); const ids = getId(location.pathname);
const isNavigationStateInValid = ids && ids.length > subGroups.length; const isNavigationStateInValid = ids && ids.length > subGroups.length;
@ -75,8 +71,6 @@ export const GroupsSection = () => {
(groups: GroupRepresentation[]) => { (groups: GroupRepresentation[]) => {
if (groups.length) setSubGroups(groups); if (groups.length) setSubGroups(groups);
}, },
errorHandler
),
[id] [id]
); );

View file

@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useErrorHandler } from "react-error-boundary";
import { import {
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
@ -23,7 +22,7 @@ import {
import { AngleRightIcon, SearchIcon } from "@patternfly/react-icons"; import { AngleRightIcon, SearchIcon } from "@patternfly/react-icons";
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation"; 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"; import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
type MoveGroupDialogProps = { type MoveGroupDialogProps = {
@ -40,7 +39,6 @@ export const MoveGroupDialog = ({
const { t } = useTranslation("groups"); const { t } = useTranslation("groups");
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const [navigation, setNavigation] = useState<GroupRepresentation[]>([]); const [navigation, setNavigation] = useState<GroupRepresentation[]>([]);
const [groups, setGroups] = useState<GroupRepresentation[]>([]); const [groups, setGroups] = useState<GroupRepresentation[]>([]);
@ -50,9 +48,7 @@ export const MoveGroupDialog = ({
const [id, setId] = useState<string>(); const [id, setId] = useState<string>();
const currentGroup = () => navigation[navigation.length - 1]; const currentGroup = () => navigation[navigation.length - 1];
useEffect( useFetch(
() =>
asyncStateFetch(
async () => { async () => {
if (id) { if (id) {
const group = await adminClient.groups.findOne({ id }); const group = await adminClient.groups.findOne({ id });
@ -65,8 +61,6 @@ export const MoveGroupDialog = ({
if (selectedGroup) setNavigation([...navigation, selectedGroup]); if (selectedGroup) setNavigation([...navigation, selectedGroup]);
setGroups(groups.filter((g) => g.id !== group.id)); setGroups(groups.filter((g) => g.id !== group.id));
}, },
errorHandler
),
[id] [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 { Link, useHistory, useRouteMatch } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import _ from "lodash"; import _ from "lodash";
import { import {
@ -26,7 +25,7 @@ import {
import IdentityProviderRepresentation from "keycloak-admin/lib/defs/identityProviderRepresentation"; import IdentityProviderRepresentation from "keycloak-admin/lib/defs/identityProviderRepresentation";
import { ViewHeader } from "../components/view-header/ViewHeader"; 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 { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
@ -58,19 +57,14 @@ export const IdentityProvidersSection = () => {
>(); >();
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const errorHandler = useErrorHandler();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
useEffect( useFetch(
() =>
asyncStateFetch(
async () => async () =>
(await adminClient.realms.findOne({ realm })).identityProviders!, (await adminClient.realms.findOne({ realm })).identityProviders!,
(providers) => { (providers) => {
setProviders(providers); setProviders(providers);
}, },
errorHandler
),
[] []
); );

View file

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

View file

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

View file

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

View file

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

View file

@ -1,4 +1,4 @@
import React, { useEffect } from "react"; import React from "react";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
@ -26,7 +26,7 @@ import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresenta
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; 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 { useAlerts } from "../components/alert/Alerts";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ViewHeader } from "../components/view-header/ViewHeader"; 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 { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
import { LdapMapperList } from "./ldap/mappers/LdapMapperList"; import { LdapMapperList } from "./ldap/mappers/LdapMapperList";
import { useErrorHandler } from "react-error-boundary";
type ldapComponentRepresentation = ComponentRepresentation & { type ldapComponentRepresentation = ComponentRepresentation & {
config?: { config?: {
@ -179,24 +178,24 @@ export const UserFederationLdapSettings = () => {
const history = useHistory(); const history = useHistory();
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { realm } = useRealm(); const { realm } = useRealm();
const errorHandler = useErrorHandler();
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
useEffect(() => { useFetch(
async () => {
if (id) { if (id) {
return asyncStateFetch( return await adminClient.components.findOne({ id });
() => adminClient.components.findOne({ id }), }
return undefined;
},
(fetchedComponent) => { (fetchedComponent) => {
if (fetchedComponent) { if (fetchedComponent) {
setupForm(fetchedComponent); setupForm(fetchedComponent);
} }
}, },
errorHandler []
); );
}
}, []);
const setupForm = (component: ComponentRepresentation) => { const setupForm = (component: ComponentRepresentation) => {
Object.entries(component).map((entry) => { 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 { useHistory, useRouteMatch } from "react-router-dom";
import { useErrorHandler } from "react-error-boundary";
import { import {
AlertVariant, AlertVariant,
ButtonVariant, ButtonVariant,
@ -24,7 +23,7 @@ import { ViewHeader } from "../components/view-header/ViewHeader";
import { DatabaseIcon } from "@patternfly/react-icons"; import { DatabaseIcon } from "@patternfly/react-icons";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { RealmContext } from "../context/realm-context/RealmContext"; 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 { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import "./user-federation.css"; import "./user-federation.css";
@ -40,12 +39,10 @@ export const UserFederationSection = () => {
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime()); const refresh = () => setKey(new Date().getTime());
const handleError = useErrorHandler();
const { url } = useRouteMatch(); const { url } = useRouteMatch();
const history = useHistory(); const history = useHistory();
useEffect(() => { useFetch(
return asyncStateFetch(
() => { () => {
const testParams: { [name: string]: string | number } = { const testParams: { [name: string]: string | number } = {
parentId: realm, parentId: realm,
@ -56,9 +53,8 @@ export const UserFederationSection = () => {
(userFederations) => { (userFederations) => {
setUserFederations(userFederations); setUserFederations(userFederations);
}, },
handleError [key]
); );
}, [key]);
const ufAddProviderDropdownItems = [ const ufAddProviderDropdownItems = [
<DropdownItem <DropdownItem

View file

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

View file

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

View file

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

View file

@ -1,5 +1,4 @@
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useState } from "react";
import { useErrorHandler } from "react-error-boundary";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
AlertVariant, AlertVariant,
@ -17,7 +16,7 @@ import {
} from "@patternfly/react-icons"; } from "@patternfly/react-icons";
import UserRepresentation from "keycloak-admin/lib/defs/userRepresentation"; 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 { ViewHeader } from "../components/view-header/ViewHeader";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
@ -36,7 +35,6 @@ type BruteUser = UserRepresentation & {
export const UsersSection = () => { export const UsersSection = () => {
const { t } = useTranslation("users"); const { t } = useTranslation("users");
const handleError = useErrorHandler();
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const { realm: realmName } = useContext(RealmContext); const { realm: realmName } = useContext(RealmContext);
@ -50,8 +48,7 @@ export const UsersSection = () => {
const [key, setKey] = useState(""); const [key, setKey] = useState("");
const refresh = () => setKey(`${new Date().getTime()}`); const refresh = () => setKey(`${new Date().getTime()}`);
useEffect(() => { useFetch(
return asyncStateFetch(
() => { () => {
const testParams = { const testParams = {
type: "org.keycloak.storage.UserStorageProvider", type: "org.keycloak.storage.UserStorageProvider",
@ -68,9 +65,8 @@ export const UsersSection = () => {
!((response[0] && response[0].length > 0) || response[1] > 100) !((response[0] && response[0].length > 0) || response[1] > 100)
); );
}, },
handleError []
); );
}, []);
const UserDetailLink = (user: UserRepresentation) => ( 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" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
axios@^0.21.0: axios@^0.21.0, axios@^0.21.1:
version "0.21.1" version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==