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:
commit
c0c3fd6692
33 changed files with 569 additions and 728 deletions
|
@ -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",
|
||||
|
|
|
@ -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,53 +46,49 @@ export const RoleMappingForm = () => {
|
|||
const [selectedClient, setSelectedClient] = useState<ClientRepresentation>();
|
||||
const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
async () => {
|
||||
const clients = await adminClient.clients.find();
|
||||
useFetch(
|
||||
async () => {
|
||||
const clients = await adminClient.clients.find();
|
||||
|
||||
const asyncFilter = async (
|
||||
predicate: (client: ClientRepresentation) => Promise<boolean>
|
||||
) => {
|
||||
const results = await Promise.all(clients.map(predicate));
|
||||
return clients.filter((_, index) => results[index]);
|
||||
};
|
||||
const asyncFilter = async (
|
||||
predicate: (client: ClientRepresentation) => Promise<boolean>
|
||||
) => {
|
||||
const results = await Promise.all(clients.map(predicate));
|
||||
return clients.filter((_, index) => results[index]);
|
||||
};
|
||||
|
||||
const filteredClients = await asyncFilter(
|
||||
async (client) =>
|
||||
(await adminClient.clients.listRoles({ id: client.id! })).length > 0
|
||||
);
|
||||
const filteredClients = await asyncFilter(
|
||||
async (client) =>
|
||||
(await adminClient.clients.listRoles({ id: client.id! })).length > 0
|
||||
);
|
||||
|
||||
filteredClients.map(
|
||||
(client) =>
|
||||
(client.toString = function () {
|
||||
return this.clientId!;
|
||||
})
|
||||
);
|
||||
return filteredClients;
|
||||
},
|
||||
(filteredClients) => setClients(filteredClients),
|
||||
handleError
|
||||
);
|
||||
}, []);
|
||||
filteredClients.map(
|
||||
(client) =>
|
||||
(client.toString = function () {
|
||||
return this.clientId!;
|
||||
})
|
||||
);
|
||||
return filteredClients;
|
||||
},
|
||||
(filteredClients) => setClients(filteredClients),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
async () => {
|
||||
const client = selectedClient as ClientRepresentation;
|
||||
if (client && client.name !== "realmRoles") {
|
||||
const clientRoles = await adminClient.clients.listRoles({
|
||||
id: client.id!,
|
||||
});
|
||||
return clientRoles;
|
||||
} else {
|
||||
return await adminClient.roles.find();
|
||||
}
|
||||
},
|
||||
(clientRoles) => setClientRoles(clientRoles),
|
||||
handleError
|
||||
);
|
||||
}, [selectedClient]);
|
||||
useFetch(
|
||||
async () => {
|
||||
const client = selectedClient as ClientRepresentation;
|
||||
if (client && client.name !== "realmRoles") {
|
||||
const clientRoles = await adminClient.clients.listRoles({
|
||||
id: client.id!,
|
||||
});
|
||||
return clientRoles;
|
||||
} else {
|
||||
return await adminClient.roles.find();
|
||||
}
|
||||
},
|
||||
(clientRoles) => setClientRoles(clientRoles),
|
||||
[selectedClient]
|
||||
);
|
||||
|
||||
const save = async (mapping: ProtocolMapperRepresentation) => {
|
||||
try {
|
||||
|
|
|
@ -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,52 +56,50 @@ 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(
|
||||
async () => {
|
||||
if (mapperId.match(isGuid)) {
|
||||
const data = await adminClient.clientScopes.findProtocolMapper({
|
||||
id,
|
||||
mapperId,
|
||||
useFetch(
|
||||
async () => {
|
||||
if (mapperId.match(isGuid)) {
|
||||
const data = await adminClient.clientScopes.findProtocolMapper({
|
||||
id,
|
||||
mapperId,
|
||||
});
|
||||
if (data) {
|
||||
Object.entries(data).map((entry) => {
|
||||
convertToFormValues(entry[1], "config", setValue);
|
||||
});
|
||||
if (data) {
|
||||
Object.entries(data).map((entry) => {
|
||||
convertToFormValues(entry[1], "config", setValue);
|
||||
});
|
||||
}
|
||||
const mapperTypes = serverInfo.protocolMapperTypes![data!.protocol!];
|
||||
const properties = mapperTypes.find(
|
||||
(type) => type.id === data!.protocolMapper
|
||||
)?.properties!;
|
||||
|
||||
return {
|
||||
configProperties: properties,
|
||||
mapping: data,
|
||||
};
|
||||
} else {
|
||||
const scope = await adminClient.clientScopes.findOne({ id });
|
||||
const protocolMappers = serverInfo.protocolMapperTypes![
|
||||
scope.protocol!
|
||||
];
|
||||
const mapping = protocolMappers.find(
|
||||
(mapper) => mapper.id === mapperId
|
||||
)!;
|
||||
return {
|
||||
mapping: {
|
||||
name: mapping.name,
|
||||
protocol: scope.protocol,
|
||||
protocolMapper: mapperId,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
(result) => {
|
||||
setConfigProperties(result.configProperties);
|
||||
setMapping(result.mapping);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, []);
|
||||
const mapperTypes = serverInfo.protocolMapperTypes![data!.protocol!];
|
||||
const properties = mapperTypes.find(
|
||||
(type) => type.id === data!.protocolMapper
|
||||
)?.properties!;
|
||||
|
||||
return {
|
||||
configProperties: properties,
|
||||
mapping: data,
|
||||
};
|
||||
} else {
|
||||
const scope = await adminClient.clientScopes.findOne({ id });
|
||||
const protocolMappers = serverInfo.protocolMapperTypes![
|
||||
scope.protocol!
|
||||
];
|
||||
const mapping = protocolMappers.find(
|
||||
(mapper) => mapper.id === mapperId
|
||||
)!;
|
||||
return {
|
||||
mapping: {
|
||||
name: mapping.name,
|
||||
protocol: scope.protocol,
|
||||
protocolMapper: mapperId,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
(result) => {
|
||||
setConfigProperties(result.configProperties);
|
||||
setMapping(result.mapping);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
|
||||
titleKey: "common:deleteMappingTitle",
|
||||
|
|
|
@ -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,19 +33,17 @@ export const ClientScopeForm = () => {
|
|||
const [key, setKey] = useState(0);
|
||||
const refresh = () => setKey(new Date().getTime());
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
async () => {
|
||||
if (id) {
|
||||
return await adminClient.clientScopes.findOne({ id });
|
||||
}
|
||||
},
|
||||
(clientScope) => {
|
||||
setClientScope(clientScope);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [key, id]);
|
||||
useFetch(
|
||||
async () => {
|
||||
if (id) {
|
||||
return await adminClient.clientScopes.findOne({ id });
|
||||
}
|
||||
},
|
||||
(clientScope) => {
|
||||
setClientScope(clientScope);
|
||||
},
|
||||
[key, id]
|
||||
);
|
||||
|
||||
const loader = async () => {
|
||||
const assignedRoles = hide
|
||||
|
|
|
@ -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(
|
||||
() => adminClient.clients.findOne({ id: clientId }),
|
||||
(fetchedClient) => {
|
||||
setClient(fetchedClient);
|
||||
setupForm(fetchedClient);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [clientId]);
|
||||
useFetch(
|
||||
() => adminClient.clients.findOne({ id: clientId }),
|
||||
(fetchedClient) => {
|
||||
setClient(fetchedClient);
|
||||
setupForm(fetchedClient);
|
||||
},
|
||||
[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")} />
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,32 +30,27 @@ 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(
|
||||
() => adminClient.authenticationManagement.getFlows(),
|
||||
(flows) => {
|
||||
let filteredFlows = [
|
||||
...flows.filter((flow) => flow.providerId !== "client-flow"),
|
||||
];
|
||||
filteredFlows = _.sortBy(filteredFlows, [(f) => f.alias]);
|
||||
setFlows([
|
||||
<SelectOption key="empty" value="">
|
||||
{t("common:choose")}
|
||||
</SelectOption>,
|
||||
...filteredFlows.map((flow) => (
|
||||
<SelectOption key={flow.id} value={flow.id}>
|
||||
{flow.alias}
|
||||
</SelectOption>
|
||||
)),
|
||||
]);
|
||||
},
|
||||
handleError
|
||||
),
|
||||
useFetch(
|
||||
() => adminClient.authenticationManagement.getFlows(),
|
||||
(flows) => {
|
||||
let filteredFlows = [
|
||||
...flows.filter((flow) => flow.providerId !== "client-flow"),
|
||||
];
|
||||
filteredFlows = _.sortBy(filteredFlows, [(f) => f.alias]);
|
||||
setFlows([
|
||||
<SelectOption key="empty" value="">
|
||||
{t("common:choose")}
|
||||
</SelectOption>,
|
||||
...filteredFlows.map((flow) => (
|
||||
<SelectOption key={flow.id} value={flow.id}>
|
||||
{flow.alias}
|
||||
</SelectOption>
|
||||
)),
|
||||
]);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
|
|
|
@ -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,37 +65,33 @@ 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(
|
||||
async () => {
|
||||
const providers = await adminClient.authenticationManagement.getClientAuthenticatorProviders(
|
||||
{ id: clientId }
|
||||
);
|
||||
useFetch(
|
||||
async () => {
|
||||
const providers = await adminClient.authenticationManagement.getClientAuthenticatorProviders(
|
||||
{ id: clientId }
|
||||
);
|
||||
|
||||
const secret = await adminClient.clients.getClientSecret({
|
||||
id: clientId,
|
||||
});
|
||||
return {
|
||||
providers,
|
||||
secret: secret.value!,
|
||||
};
|
||||
},
|
||||
({ providers, secret }) => {
|
||||
setProviders(providers);
|
||||
setSecret(secret);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, []);
|
||||
const secret = await adminClient.clients.getClientSecret({
|
||||
id: clientId,
|
||||
});
|
||||
return {
|
||||
providers,
|
||||
secret: secret.value!,
|
||||
};
|
||||
},
|
||||
({ providers, secret }) => {
|
||||
setProviders(providers);
|
||||
setSecret(secret);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
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"
|
||||
|
|
|
@ -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(
|
||||
() => adminClient.clients.getKeyInfo({ id: clientId, attr }),
|
||||
(info) => setKeyInfo(info),
|
||||
errorHandler
|
||||
),
|
||||
|
||||
useFetch(
|
||||
() => adminClient.clients.getKeyInfo({ id: clientId, attr }),
|
||||
(info) => setKeyInfo(info),
|
||||
[]
|
||||
);
|
||||
|
||||
|
|
|
@ -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(
|
||||
() => adminClient.clients.listOptionalClientScopes({ id: clientId }),
|
||||
(optionalClientScopes) => setSelectableScopes(optionalClientScopes),
|
||||
handleError
|
||||
);
|
||||
}, []);
|
||||
useFetch(
|
||||
() => adminClient.clients.listOptionalClientScopes({ id: clientId }),
|
||||
(optionalClientScopes) => setSelectableScopes(optionalClientScopes),
|
||||
[]
|
||||
);
|
||||
|
||||
const toString = (user: UserRepresentation) => {
|
||||
return (
|
||||
|
@ -169,90 +162,82 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
() => {
|
||||
if (userSearch.length > 2) {
|
||||
return adminClient.users.find({ search: userSearch });
|
||||
} else {
|
||||
return Promise.resolve<UserRepresentation[]>([]);
|
||||
}
|
||||
},
|
||||
(users) =>
|
||||
setUserItems(
|
||||
users
|
||||
.map((user) => {
|
||||
user.toString = function () {
|
||||
return toString(this);
|
||||
};
|
||||
return user;
|
||||
})
|
||||
.map((user) => <SelectOption key={user.id} value={user} />)
|
||||
),
|
||||
handleError
|
||||
);
|
||||
}, [userSearch]);
|
||||
useFetch(
|
||||
() => {
|
||||
if (userSearch.length > 2) {
|
||||
return adminClient.users.find({ search: userSearch });
|
||||
} else {
|
||||
return Promise.resolve<UserRepresentation[]>([]);
|
||||
}
|
||||
},
|
||||
(users) =>
|
||||
setUserItems(
|
||||
users
|
||||
.map((user) => {
|
||||
user.toString = function () {
|
||||
return toString(this);
|
||||
};
|
||||
return user;
|
||||
})
|
||||
.map((user) => <SelectOption key={user.id} value={user} />)
|
||||
),
|
||||
[userSearch]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
async () => {
|
||||
const scope = selected.join(" ");
|
||||
const effectiveRoles = await adminClient.clients.evaluatePermission({
|
||||
useFetch(
|
||||
async () => {
|
||||
const scope = selected.join(" ");
|
||||
const effectiveRoles = await adminClient.clients.evaluatePermission({
|
||||
id: clientId,
|
||||
roleContainer: realm,
|
||||
scope,
|
||||
type: "granted",
|
||||
});
|
||||
|
||||
const mapperList = (await adminClient.clients.evaluateListProtocolMapper({
|
||||
id: clientId,
|
||||
scope,
|
||||
})) as ({
|
||||
type: ProtocolMapperTypeRepresentation;
|
||||
} & ProtocolMapperRepresentation)[];
|
||||
|
||||
return {
|
||||
mapperList,
|
||||
effectiveRoles,
|
||||
};
|
||||
},
|
||||
({ mapperList, effectiveRoles }) => {
|
||||
setEffectiveRoles(effectiveRoles);
|
||||
mapperList.map((mapper) => {
|
||||
mapper.type = mapperTypes.filter(
|
||||
(type) => type.id === mapper.protocolMapper
|
||||
)[0];
|
||||
});
|
||||
|
||||
setProtocolMappers(mapperList);
|
||||
refresh();
|
||||
},
|
||||
[selected]
|
||||
);
|
||||
|
||||
useFetch(
|
||||
() => {
|
||||
const scope = selected.join(" ");
|
||||
if (user) {
|
||||
return adminClient.clients.evaluateGenerateAccessToken({
|
||||
id: clientId,
|
||||
roleContainer: realm,
|
||||
userId: user.id!,
|
||||
scope,
|
||||
type: "granted",
|
||||
});
|
||||
|
||||
const mapperList = (await adminClient.clients.evaluateListProtocolMapper(
|
||||
{
|
||||
id: clientId,
|
||||
scope,
|
||||
}
|
||||
)) as ({
|
||||
type: ProtocolMapperTypeRepresentation;
|
||||
} & ProtocolMapperRepresentation)[];
|
||||
|
||||
return {
|
||||
mapperList,
|
||||
effectiveRoles,
|
||||
};
|
||||
},
|
||||
({ mapperList, effectiveRoles }) => {
|
||||
setEffectiveRoles(effectiveRoles);
|
||||
mapperList.map((mapper) => {
|
||||
mapper.type = mapperTypes.filter(
|
||||
(type) => type.id === mapper.protocolMapper
|
||||
)[0];
|
||||
});
|
||||
|
||||
setProtocolMappers(mapperList);
|
||||
refresh();
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [selected]);
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
() => {
|
||||
const scope = selected.join(" ");
|
||||
if (user) {
|
||||
return adminClient.clients.evaluateGenerateAccessToken({
|
||||
id: clientId,
|
||||
userId: user.id!,
|
||||
scope,
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
},
|
||||
(accessToken) => {
|
||||
setAccessToken(JSON.stringify(accessToken, undefined, 3));
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [user, selected]);
|
||||
} else {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
},
|
||||
(accessToken) => {
|
||||
setAccessToken(JSON.stringify(accessToken, undefined, 3));
|
||||
},
|
||||
[user, selected]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -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(
|
||||
() => props.loader(),
|
||||
(result) => setData(result),
|
||||
handleError
|
||||
);
|
||||
}, props.deps || []);
|
||||
useFetch(
|
||||
() => props.loader(),
|
||||
(result) => setData(result),
|
||||
props.deps || []
|
||||
);
|
||||
|
||||
if (data) {
|
||||
if (props.children instanceof Function) {
|
||||
|
|
|
@ -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,15 +20,17 @@ describe("<DataLoader />", () => {
|
|||
const loader = () => Promise.resolve(["a", "b"]);
|
||||
await act(async () => {
|
||||
render(
|
||||
<DataLoader loader={loader}>
|
||||
{(result) => (
|
||||
<div>
|
||||
{result.map((d, i) => (
|
||||
<i key={i}>{d}</i>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</DataLoader>,
|
||||
<MockAdminClient>
|
||||
<DataLoader loader={loader}>
|
||||
{(result) => (
|
||||
<div>
|
||||
{result.map((d, i) => (
|
||||
<i key={i}>{d}</i>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</DataLoader>
|
||||
</MockAdminClient>,
|
||||
container
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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,23 +46,21 @@ export const DownloadDialog = ({
|
|||
const [snippet, setSnippet] = useState("");
|
||||
const [openType, setOpenType] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
async () => {
|
||||
const snippet = await adminClient.clients.getInstallationProviders({
|
||||
id,
|
||||
providerId: selected,
|
||||
});
|
||||
if (typeof snippet === "string") {
|
||||
return snippet;
|
||||
} else {
|
||||
return JSON.stringify(snippet, undefined, 3);
|
||||
}
|
||||
},
|
||||
(snippet) => setSnippet(snippet),
|
||||
handleError
|
||||
);
|
||||
}, [id, selected]);
|
||||
useFetch(
|
||||
async () => {
|
||||
const snippet = await adminClient.clients.getInstallationProviders({
|
||||
id,
|
||||
providerId: selected,
|
||||
});
|
||||
if (typeof snippet === "string") {
|
||||
return snippet;
|
||||
} else {
|
||||
return JSON.stringify(snippet, undefined, 3);
|
||||
}
|
||||
},
|
||||
(snippet) => setSnippet(snippet),
|
||||
[id, selected]
|
||||
);
|
||||
return (
|
||||
<ConfirmDialogModal
|
||||
titleKey={t("clients:downloadAdaptorTitle")}
|
||||
|
|
|
@ -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,48 +60,42 @@ export const AddRoleMappingModal = ({
|
|||
const [selectedClients, setSelectedClients] = useState<ClientRole[]>([]);
|
||||
const [selectedRows, setSelectedRows] = useState<Row[]>([]);
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
asyncStateFetch(
|
||||
async () => {
|
||||
const clients = await adminClient.clients.find();
|
||||
return (
|
||||
await Promise.all(
|
||||
clients.map(async (client) => {
|
||||
let roles: RoleRepresentation[] = [];
|
||||
if (type === "service-account") {
|
||||
roles = await adminClient.users.listAvailableClientRoleMappings(
|
||||
{
|
||||
id: id,
|
||||
clientUniqueId: client.id!,
|
||||
}
|
||||
);
|
||||
} else if (type === "client-scope") {
|
||||
roles = await adminClient.clientScopes.listAvailableClientScopeMappings(
|
||||
{
|
||||
id,
|
||||
client: client.id!,
|
||||
}
|
||||
);
|
||||
useFetch(
|
||||
async () => {
|
||||
const clients = await adminClient.clients.find();
|
||||
return (
|
||||
await Promise.all(
|
||||
clients.map(async (client) => {
|
||||
let roles: RoleRepresentation[] = [];
|
||||
if (type === "service-account") {
|
||||
roles = await adminClient.users.listAvailableClientRoleMappings({
|
||||
id: id,
|
||||
clientUniqueId: client.id!,
|
||||
});
|
||||
} else if (type === "client-scope") {
|
||||
roles = await adminClient.clientScopes.listAvailableClientScopeMappings(
|
||||
{
|
||||
id,
|
||||
client: client.id!,
|
||||
}
|
||||
return {
|
||||
roles,
|
||||
client,
|
||||
};
|
||||
})
|
||||
)
|
||||
)
|
||||
.flat()
|
||||
.filter((row) => row.roles.length !== 0)
|
||||
.map((row) => {
|
||||
return { ...row.client, numberOfRoles: row.roles.length };
|
||||
});
|
||||
},
|
||||
(clients) => {
|
||||
setClients(clients);
|
||||
},
|
||||
errorHandler
|
||||
),
|
||||
);
|
||||
}
|
||||
return {
|
||||
roles,
|
||||
client,
|
||||
};
|
||||
})
|
||||
)
|
||||
)
|
||||
.flat()
|
||||
.filter((row) => row.roles.length !== 0)
|
||||
.map((row) => {
|
||||
return { ...row.client, numberOfRoles: row.roles.length };
|
||||
});
|
||||
},
|
||||
(clients) => {
|
||||
setClients(clients);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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(
|
||||
async () => {
|
||||
let data = unPaginatedData || (await loader(first, max, search));
|
||||
useFetch(
|
||||
async () => {
|
||||
setLoading(true);
|
||||
return unPaginatedData || (await loader(first, max, search));
|
||||
},
|
||||
(data) => {
|
||||
if (!isPaginated) {
|
||||
setUnPaginatedData(data);
|
||||
data = data.slice(first, first + max);
|
||||
}
|
||||
|
||||
if (!isPaginated) {
|
||||
setUnPaginatedData(data);
|
||||
data = data.slice(first, first + max);
|
||||
}
|
||||
|
||||
return convertToColumns(data);
|
||||
},
|
||||
(result) => {
|
||||
setRows(result);
|
||||
setFilteredData(result);
|
||||
setLoading(false);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [key, first, max, search]);
|
||||
const result = convertToColumns(data);
|
||||
setRows(result);
|
||||
setFilteredData(result);
|
||||
setLoading(false);
|
||||
},
|
||||
[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}
|
||||
|
|
|
@ -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(
|
||||
* () => adminClient.components.findOne({ id }),
|
||||
* (component) => setupForm(component)
|
||||
* );
|
||||
* }, []);
|
||||
* useFetch(
|
||||
* () => adminClient.components.findOne({ id }),
|
||||
* (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();
|
||||
|
||||
adminClientCall()
|
||||
.then((result) => {
|
||||
try {
|
||||
if (!canceled) {
|
||||
callback(result);
|
||||
const source = axios.CancelToken.source();
|
||||
adminClient.setConfig({ requestConfig: { cancelToken: source.token } });
|
||||
|
||||
useEffect(() => {
|
||||
adminClientCall()
|
||||
.then((result) => {
|
||||
callback(result);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (!axios.isCancel(error)) {
|
||||
onError(error);
|
||||
}
|
||||
} catch (error) {
|
||||
if (onError) onError(error);
|
||||
}
|
||||
})
|
||||
.catch(onError);
|
||||
});
|
||||
|
||||
return () => {
|
||||
canceled = true;
|
||||
};
|
||||
return () => {
|
||||
source.cancel();
|
||||
};
|
||||
}, deps);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
() => adminClient.realms.find(),
|
||||
(realms) => updateRealmsList(realms),
|
||||
errorHandler
|
||||
),
|
||||
useFetch(
|
||||
() => adminClient.realms.find(),
|
||||
(realms) => updateRealmsList(realms),
|
||||
[]
|
||||
);
|
||||
|
||||
|
|
|
@ -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(
|
||||
() => adminClient.whoAmI.find({ realm: "master" }),
|
||||
(me) => {
|
||||
const whoAmI = new WhoAmI(adminClient.keycloak?.realm, me);
|
||||
setWhoAmI(whoAmI);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [key]);
|
||||
useFetch(
|
||||
() => adminClient.whoAmI.find({ realm: "master" }),
|
||||
(me) => {
|
||||
const whoAmI = new WhoAmI(adminClient.keycloak?.realm, me);
|
||||
setWhoAmI(whoAmI);
|
||||
},
|
||||
[key]
|
||||
);
|
||||
|
||||
return (
|
||||
<WhoAmIContext.Provider value={{ refresh: () => setKey(key + 1), whoAmI }}>
|
||||
|
|
|
@ -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,28 +53,24 @@ export const GroupsSection = () => {
|
|||
return true;
|
||||
};
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
asyncStateFetch(
|
||||
async () => {
|
||||
const ids = getId(location.pathname);
|
||||
const isNavigationStateInValid = ids && ids.length > subGroups.length;
|
||||
useFetch(
|
||||
async () => {
|
||||
const ids = getId(location.pathname);
|
||||
const isNavigationStateInValid = ids && ids.length > subGroups.length;
|
||||
|
||||
if (isNavigationStateInValid) {
|
||||
const groups: GroupRepresentation[] = [];
|
||||
for (const i of ids!) {
|
||||
const group = await adminClient.groups.findOne({ id: i });
|
||||
if (group) groups.push(group);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
(groups: GroupRepresentation[]) => {
|
||||
if (groups.length) setSubGroups(groups);
|
||||
},
|
||||
errorHandler
|
||||
),
|
||||
if (isNavigationStateInValid) {
|
||||
const groups: GroupRepresentation[] = [];
|
||||
for (const i of ids!) {
|
||||
const group = await adminClient.groups.findOne({ id: i });
|
||||
if (group) groups.push(group);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
(groups: GroupRepresentation[]) => {
|
||||
if (groups.length) setSubGroups(groups);
|
||||
},
|
||||
[id]
|
||||
);
|
||||
|
||||
|
|
|
@ -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,23 +48,19 @@ export const MoveGroupDialog = ({
|
|||
const [id, setId] = useState<string>();
|
||||
const currentGroup = () => navigation[navigation.length - 1];
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
asyncStateFetch(
|
||||
async () => {
|
||||
if (id) {
|
||||
const group = await adminClient.groups.findOne({ id });
|
||||
return { group, groups: group.subGroups! };
|
||||
} else {
|
||||
return { groups: await adminClient.groups.find() };
|
||||
}
|
||||
},
|
||||
({ group: selectedGroup, groups }) => {
|
||||
if (selectedGroup) setNavigation([...navigation, selectedGroup]);
|
||||
setGroups(groups.filter((g) => g.id !== group.id));
|
||||
},
|
||||
errorHandler
|
||||
),
|
||||
useFetch(
|
||||
async () => {
|
||||
if (id) {
|
||||
const group = await adminClient.groups.findOne({ id });
|
||||
return { group, groups: group.subGroups! };
|
||||
} else {
|
||||
return { groups: await adminClient.groups.find() };
|
||||
}
|
||||
},
|
||||
({ group: selectedGroup, groups }) => {
|
||||
if (selectedGroup) setNavigation([...navigation, selectedGroup]);
|
||||
setGroups(groups.filter((g) => g.id !== group.id));
|
||||
},
|
||||
[id]
|
||||
);
|
||||
|
||||
|
|
|
@ -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(
|
||||
async () =>
|
||||
(await adminClient.realms.findOne({ realm })).identityProviders!,
|
||||
(providers) => {
|
||||
setProviders(providers);
|
||||
},
|
||||
errorHandler
|
||||
),
|
||||
useFetch(
|
||||
async () =>
|
||||
(await adminClient.realms.findOne({ realm })).identityProviders!,
|
||||
(providers) => {
|
||||
setProviders(providers);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
() => adminClient.identityProviders.findOne({ alias: id }),
|
||||
(provider) => {
|
||||
Object.entries(provider).map((entry) => setValue(entry[0], entry[1]));
|
||||
},
|
||||
errorHandler
|
||||
),
|
||||
useFetch(
|
||||
() => adminClient.identityProviders.findOne({ alias: id }),
|
||||
(provider) => {
|
||||
Object.entries(provider).map((entry) => setValue(entry[0], entry[1]));
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
} else {
|
||||
setName(t("createRole"));
|
||||
}
|
||||
}, []);
|
||||
useFetch(
|
||||
async () => {
|
||||
if (id) return await adminClient.roles.findOneById({ id });
|
||||
},
|
||||
(fetchedRole) => {
|
||||
if (fetchedRole) {
|
||||
setName(fetchedRole.name!);
|
||||
} else {
|
||||
setName(t("createRole"));
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const onFilterDropdownToggle = () => {
|
||||
setIsFilterDropdownOpen(!isFilterDropdownOpen);
|
||||
|
|
|
@ -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(
|
||||
() => adminClient.realms.findOne({ realm: realmName }),
|
||||
(realm) => {
|
||||
setupForm(realm);
|
||||
setRealm(realm);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, []);
|
||||
useFetch(
|
||||
() => adminClient.realms.findOne({ realm: realmName }),
|
||||
(realm) => {
|
||||
setupForm(realm);
|
||||
setRealm(realm);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const update = async () => {
|
||||
|
|
|
@ -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(() => {
|
||||
if (id) {
|
||||
return asyncStateFetch(
|
||||
() => adminClient.components.findOne({ id }),
|
||||
(fetchedComponent) => {
|
||||
if (fetchedComponent) {
|
||||
setupForm(fetchedComponent);
|
||||
}
|
||||
},
|
||||
errorHandler
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
useFetch(
|
||||
async () => {
|
||||
if (id) {
|
||||
return await adminClient.components.findOne({ id });
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
(fetchedComponent) => {
|
||||
if (fetchedComponent) {
|
||||
setupForm(fetchedComponent);
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const setupForm = (component: ComponentRepresentation) => {
|
||||
Object.entries(component).map((entry) => {
|
||||
|
|
|
@ -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,25 +39,22 @@ 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(
|
||||
() => {
|
||||
const testParams: { [name: string]: string | number } = {
|
||||
parentId: realm,
|
||||
type: "org.keycloak.storage.UserStorageProvider",
|
||||
};
|
||||
return adminClient.components.find(testParams);
|
||||
},
|
||||
(userFederations) => {
|
||||
setUserFederations(userFederations);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [key]);
|
||||
useFetch(
|
||||
() => {
|
||||
const testParams: { [name: string]: string | number } = {
|
||||
parentId: realm,
|
||||
type: "org.keycloak.storage.UserStorageProvider",
|
||||
};
|
||||
return adminClient.components.find(testParams);
|
||||
},
|
||||
(userFederations) => {
|
||||
setUserFederations(userFederations);
|
||||
},
|
||||
[key]
|
||||
);
|
||||
|
||||
const ufAddProviderDropdownItems = [
|
||||
<DropdownItem
|
||||
|
|
|
@ -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,42 +60,38 @@ export const JoinGroupDialog = ({
|
|||
|
||||
const { id } = useParams<{ id: string }>();
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
asyncStateFetch(
|
||||
async () => {
|
||||
const allGroups = await adminClient.groups.find();
|
||||
useFetch(
|
||||
async () => {
|
||||
const allGroups = await adminClient.groups.find();
|
||||
|
||||
if (groupId) {
|
||||
const group = await adminClient.groups.findOne({ id: groupId });
|
||||
return { group, groups: group.subGroups! };
|
||||
} else if (id) {
|
||||
const existingUserGroups = await adminClient.users.listGroups({
|
||||
id,
|
||||
});
|
||||
if (groupId) {
|
||||
const group = await adminClient.groups.findOne({ id: groupId });
|
||||
return { group, groups: group.subGroups! };
|
||||
} else if (id) {
|
||||
const existingUserGroups = await adminClient.users.listGroups({
|
||||
id,
|
||||
});
|
||||
|
||||
return {
|
||||
groups: _.differenceBy(allGroups, existingUserGroups, "id"),
|
||||
};
|
||||
} else
|
||||
return {
|
||||
groups: allGroups,
|
||||
};
|
||||
},
|
||||
async ({ group: selectedGroup, groups }) => {
|
||||
if (selectedGroup) {
|
||||
setNavigation([...navigation, selectedGroup]);
|
||||
}
|
||||
return {
|
||||
groups: _.differenceBy(allGroups, existingUserGroups, "id"),
|
||||
};
|
||||
} else
|
||||
return {
|
||||
groups: allGroups,
|
||||
};
|
||||
},
|
||||
async ({ group: selectedGroup, groups }) => {
|
||||
if (selectedGroup) {
|
||||
setNavigation([...navigation, selectedGroup]);
|
||||
}
|
||||
|
||||
groups.forEach((group: Group) => {
|
||||
group.checked = !!selectedRows.find((r) => r.id === group.id);
|
||||
});
|
||||
id
|
||||
? setGroups(groups)
|
||||
: setGroups([...groups.filter((row) => !chips.includes(row.name))]);
|
||||
},
|
||||
errorHandler
|
||||
),
|
||||
groups.forEach((group: Group) => {
|
||||
group.checked = !!selectedRows.find((r) => r.id === group.id);
|
||||
});
|
||||
id
|
||||
? setGroups(groups)
|
||||
: setGroups([...groups.filter((row) => !chips.includes(row.name))]);
|
||||
},
|
||||
[groupId]
|
||||
);
|
||||
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}
|
||||
}, [chips]);
|
||||
useFetch(
|
||||
async () => {
|
||||
if (editMode) return await adminClient.users.findOne({ id: id });
|
||||
},
|
||||
(user) => {
|
||||
if (user) setupForm(user);
|
||||
},
|
||||
[chips]
|
||||
);
|
||||
|
||||
const setupForm = (user: UserRepresentation) => {
|
||||
reset();
|
||||
|
|
|
@ -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 }));
|
||||
},
|
||||
(response) => {
|
||||
setListGroups(!!(response && response.length > 0));
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, []);
|
||||
useFetch(
|
||||
() => adminClient.users.listGroups({ id }),
|
||||
(response) => {
|
||||
setListGroups(!!(response && response.length > 0));
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
|
|
|
@ -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,27 +48,25 @@ export const UsersSection = () => {
|
|||
const [key, setKey] = useState("");
|
||||
const refresh = () => setKey(`${new Date().getTime()}`);
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
() => {
|
||||
const testParams = {
|
||||
type: "org.keycloak.storage.UserStorageProvider",
|
||||
};
|
||||
useFetch(
|
||||
() => {
|
||||
const testParams = {
|
||||
type: "org.keycloak.storage.UserStorageProvider",
|
||||
};
|
||||
|
||||
return Promise.all([
|
||||
adminClient.components.find(testParams),
|
||||
adminClient.users.count(),
|
||||
]);
|
||||
},
|
||||
(response) => {
|
||||
//should *only* list users when no user federation is configured and uses count > 100
|
||||
setListUsers(
|
||||
!((response[0] && response[0].length > 0) || response[1] > 100)
|
||||
);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, []);
|
||||
return Promise.all([
|
||||
adminClient.components.find(testParams),
|
||||
adminClient.users.count(),
|
||||
]);
|
||||
},
|
||||
(response) => {
|
||||
//should *only* list users when no user federation is configured and uses count > 100
|
||||
setListUsers(
|
||||
!((response[0] && response[0].length > 0) || response[1] > 100)
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const UserDetailLink = (user: UserRepresentation) => (
|
||||
<>
|
||||
|
|
|
@ -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==
|
||||
|
|
Loading…
Reference in a new issue