only update state when component is mounted (#266)

* only update state when component is mounted

* removed unused import

* `useFetch` function to update state when mounted
This commit is contained in:
Erik Jan de Wit 2021-01-05 14:39:27 +01:00 committed by GitHub
parent 03e7ec760c
commit 27d9dadee7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 346 additions and 291 deletions

View file

@ -24,7 +24,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 { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } 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";
@ -47,7 +47,8 @@ export const RoleMappingForm = () => {
const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>([]); const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>([]);
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
async () => {
const clients = await adminClient.clients.find(); const clients = await adminClient.clients.find();
const asyncFilter = async ( const asyncFilter = async (
@ -68,19 +69,27 @@ export const RoleMappingForm = () => {
return this.clientId!; return this.clientId!;
}) })
); );
setClients(filteredClients); return filteredClients;
})(); },
(filteredClients) => setClients(filteredClients)
);
}, []); }, []);
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
async () => {
const client = selectedClient as ClientRepresentation; const client = selectedClient as ClientRepresentation;
if (client && client.name !== "realmRoles") { if (client && client.name !== "realmRoles") {
setClientRoles(await adminClient.clients.listRoles({ id: client.id! })); const clientRoles = await adminClient.clients.listRoles({
id: client.id!,
});
return clientRoles;
} else { } else {
setClientRoles(await adminClient.roles.find()); return await adminClient.roles.find();
} }
})(); },
(clientRoles) => setClientRoles(clientRoles)
);
}, [selectedClient]); }, [selectedClient]);
const save = async (mapping: ProtocolMapperRepresentation) => { const save = async (mapping: ProtocolMapperRepresentation) => {

View file

@ -24,7 +24,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 { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } 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";
@ -55,8 +55,9 @@ export const MappingDetails = () => {
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(() => { useEffect(() => {
return useFetch(
async () => {
if (id.match(isGuid)) { if (id.match(isGuid)) {
(async () => {
const data = await adminClient.clientScopes.findProtocolMapper({ const data = await adminClient.clientScopes.findProtocolMapper({
id: scopeId, id: scopeId,
mapperId: id, mapperId: id,
@ -70,16 +71,23 @@ export const MappingDetails = () => {
const properties = mapperTypes.find( const properties = mapperTypes.find(
(type) => type.id === data!.protocolMapper (type) => type.id === data!.protocolMapper
)?.properties!; )?.properties!;
setConfigProperties(properties);
setMapping(data); return {
})(); configProperties: properties,
mapping: data,
};
} else { } else {
(async () => {
const scope = await adminClient.clientScopes.findOne({ id: scopeId }); const scope = await adminClient.clientScopes.findOne({ id: scopeId });
setMapping({ protocol: scope.protocol, protocolMapper: id }); return {
})(); mapping: { protocol: scope.protocol, protocolMapper: id },
};
} }
},
(result) => {
setConfigProperties(result.configProperties);
setMapping(result.mapping);
}
);
}, []); }, []);
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({

View file

@ -22,7 +22,7 @@ import { Controller, useForm } from "react-hook-form";
import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation"; import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { 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 { useLoginProviders } from "../../context/server-info/ServerInfoProvider"; import { useLoginProviders } from "../../context/server-info/ServerInfoProvider";
import { ViewHeader } from "../../components/view-header/ViewHeader"; import { ViewHeader } from "../../components/view-header/ViewHeader";
@ -45,7 +45,12 @@ export const ClientScopeForm = () => {
const [open, isOpen] = useState(false); const [open, isOpen] = useState(false);
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const load = async () => { const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
useEffect(() => {
return useFetch(
async () => {
if (id) { if (id) {
const data = await adminClient.clientScopes.findOne({ id }); const data = await adminClient.clientScopes.findOne({ id });
if (data) { if (data) {
@ -57,13 +62,12 @@ export const ClientScopeForm = () => {
}); });
} }
setClientScope(data); return data;
} }
}; },
(data) => setClientScope(data)
useEffect(() => { );
load(); }, [key]);
}, []);
const save = async (clientScopes: ClientScopeRepresentation) => { const save = async (clientScopes: ClientScopeRepresentation) => {
try { try {
@ -305,7 +309,7 @@ export const ClientScopeForm = () => {
</Tab> </Tab>
<Tab eventKey={1} title={<TabTitleText>{t("mappers")}</TabTitleText>}> <Tab eventKey={1} title={<TabTitleText>{t("mappers")}</TabTitleText>}>
{clientScope && ( {clientScope && (
<MapperList clientScope={clientScope} refresh={load} /> <MapperList clientScope={clientScope} refresh={refresh} />
)} )}
</Tab> </Tab>
</Tabs> </Tabs>

View file

@ -19,7 +19,7 @@ import { useAlerts } from "../components/alert/Alerts";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { useDownloadDialog } from "../components/download-dialog/DownloadDialog"; import { useDownloadDialog } from "../components/download-dialog/DownloadDialog";
import { ViewHeader } from "../components/view-header/ViewHeader"; import { ViewHeader } from "../components/view-header/ViewHeader";
import { useAdminClient } 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,
@ -144,13 +144,13 @@ export const ClientDetails = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedClient = await adminClient.clients.findOne({ id }); () => adminClient.clients.findOne({ id }),
if (fetchedClient) { (fetchedClient) => {
setClient(fetchedClient); setClient(fetchedClient);
setupForm(fetchedClient); setupForm(fetchedClient);
} }
})(); );
}, []); }, []);
const save = async () => { const save = async () => {

View file

@ -22,7 +22,7 @@ import { useAlerts } from "../../components/alert/Alerts";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { ClientSecret } from "./ClientSecret"; import { ClientSecret } from "./ClientSecret";
import { SignedJWT } from "./SignedJWT"; import { SignedJWT } from "./SignedJWT";
import { X509 } from "./X509"; import { X509 } from "./X509";
@ -64,17 +64,25 @@ export const Credentials = ({ clientId, form, save }: CredentialsProps) => {
const [open, isOpen] = useState(false); const [open, isOpen] = useState(false);
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
async () => {
const providers = await adminClient.authenticationManagement.getClientAuthenticatorProviders( const providers = await adminClient.authenticationManagement.getClientAuthenticatorProviders(
{ id: clientId } { id: clientId }
); );
setProviders(providers);
const secret = await adminClient.clients.getClientSecret({ const secret = await adminClient.clients.getClientSecret({
id: clientId, id: clientId,
}); });
setSecret(secret.value!); return {
})(); providers,
secret: secret.value!,
};
},
({ providers, secret }) => {
setProviders(providers);
setSecret(secret);
}
);
}, []); }, []);
async function regenerate<T>( async function regenerate<T>(

View file

@ -23,7 +23,7 @@ import { FilterIcon } from "@patternfly/react-icons";
import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation"; import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation";
import KeycloakAdminClient from "keycloak-admin"; import KeycloakAdminClient from "keycloak-admin";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { TableToolbar } from "../../components/table-toolbar/TableToolbar"; import { TableToolbar } from "../../components/table-toolbar/TableToolbar";
import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState"; import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState";
import { AddScopeDialog } from "./AddScopeDialog"; import { AddScopeDialog } from "./AddScopeDialog";
@ -133,7 +133,12 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
const [rows, setRows] = useState<TableRow[]>(); const [rows, setRows] = useState<TableRow[]>();
const [rest, setRest] = useState<ClientScopeRepresentation[]>(); const [rest, setRest] = useState<ClientScopeRepresentation[]>();
const loader = async () => { const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
useEffect(() => {
return useFetch(
async () => {
const defaultClientScopes = await adminClient.clients.listDefaultClientScopes( const defaultClientScopes = await adminClient.clients.listDefaultClientScopes(
{ id: clientId } { id: clientId }
); );
@ -165,20 +170,20 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
}; };
}); });
const data = [...optional, ...defaultScopes]; const rows = [...optional, ...defaultScopes];
setRows(data); const names = rows.map((row) => row.cells[0]);
const names = data.map((row) => row.cells[0]);
setRest( const rest = clientScopes
clientScopes
.filter((scope) => !names.includes(scope.name)) .filter((scope) => !names.includes(scope.name))
.filter((scope) => scope.protocol === protocol) .filter((scope) => scope.protocol === protocol);
return { rows, rest };
},
({ rows, rest }) => {
setRows(rows);
setRest(rest);
}
); );
}; }, [key]);
useEffect(() => {
loader();
}, []);
const dropdown = (): IFormatter => (data?: IFormatterValueType) => { const dropdown = (): IFormatter => (data?: IFormatterValueType) => {
if (!data) { if (!data) {
@ -199,7 +204,7 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
value value
); );
addAlert(t("clientScopeSuccess"), AlertVariant.success); addAlert(t("clientScopeSuccess"), AlertVariant.success);
await loader(); await refresh();
} catch (error) { } catch (error) {
addAlert(t("clientScopeError", { error }), AlertVariant.danger); addAlert(t("clientScopeError", { error }), AlertVariant.danger);
} }
@ -237,7 +242,7 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
) )
); );
addAlert(t("clientScopeSuccess"), AlertVariant.success); addAlert(t("clientScopeSuccess"), AlertVariant.success);
loader(); refresh();
} catch (error) { } catch (error) {
addAlert(t("clientScopeError", { error }), AlertVariant.danger); addAlert(t("clientScopeError", { error }), AlertVariant.danger);
} }
@ -316,7 +321,7 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
}) })
); );
setAddToggle(false); setAddToggle(false);
await loader(); await refresh();
addAlert(t("clientScopeSuccess"), AlertVariant.success); addAlert(t("clientScopeSuccess"), AlertVariant.success);
} catch (error) { } catch (error) {
addAlert( addAlert(
@ -363,7 +368,7 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
t("clientScopeRemoveSuccess"), t("clientScopeRemoveSuccess"),
AlertVariant.success AlertVariant.success
); );
loader(); refresh();
} catch (error) { } catch (error) {
addAlert( addAlert(
t("clientScopeRemoveError", { error }), t("clientScopeRemoveError", { error }),
@ -416,7 +421,7 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
t("clientScopeRemoveSuccess"), t("clientScopeRemoveSuccess"),
AlertVariant.success AlertVariant.success
); );
loader(); refresh();
} catch (error) { } catch (error) {
addAlert( addAlert(
t("clientScopeRemoveError", { error }), t("clientScopeRemoveError", { error }),

View file

@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Spinner } from "@patternfly/react-core"; import { Spinner } from "@patternfly/react-core";
import { useFetch } from "../../context/auth/AdminClient";
type DataLoaderProps<T> = { type DataLoaderProps<T> = {
loader: () => Promise<T>; loader: () => Promise<T>;
@ -14,20 +15,22 @@ type Result<T> = {
export function DataLoader<T>(props: DataLoaderProps<T>) { export function DataLoader<T>(props: DataLoaderProps<T>) {
const [data, setData] = useState<{ result: T } | undefined>(undefined); const [data, setData] = useState<{ result: T } | undefined>(undefined);
const loadData = async () => {
const result = await props.loader(); const [key, setKey] = useState(0);
setData({ result }); const refresh = () => setKey(new Date().getTime());
};
useEffect(() => { useEffect(() => {
setData(undefined); return useFetch(
loadData(); () => props.loader(),
}, [props]); (result) => setData({ result })
);
}, [key]);
if (data) { if (data) {
if (props.children instanceof Function) { if (props.children instanceof Function) {
return props.children({ return props.children({
data: data.result, data: data.result,
refresh: () => loadData(), refresh: refresh,
}); });
} }
return props.children; return props.children;

View file

@ -18,7 +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 { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { HelpContext } from "../help-enabler/HelpHeader"; import { HelpContext } from "../help-enabler/HelpHeader";
export type DownloadDialogProps = { export type DownloadDialogProps = {
@ -65,23 +65,20 @@ export const DownloadDialog = ({
const [openType, setOpenType] = useState(false); const [openType, setOpenType] = useState(false);
useEffect(() => { useEffect(() => {
let isMounted = true; return useFetch(
(async () => { async () => {
const snippet = await adminClient.clients.getInstallationProviders({ const snippet = await adminClient.clients.getInstallationProviders({
id, id,
providerId: selected, providerId: selected,
}); });
if (isMounted) {
if (typeof snippet === "string") { if (typeof snippet === "string") {
setSnippet(snippet); return snippet;
} else { } else {
setSnippet(JSON.stringify(snippet, undefined, 3)); return JSON.stringify(snippet, undefined, 3);
} }
} },
})(); (snippet) => setSnippet(snippet)
return () => { );
isMounted = false;
};
}, [selected]); }, [selected]);
return ( return (
<ConfirmDialogModal <ConfirmDialogModal

View file

@ -1,4 +1,4 @@
import React, { Children, useState } from "react"; import React, { Children } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
Grid, Grid,
@ -19,14 +19,24 @@ type ScrollFormProps = {
// This must match the page id created in App.tsx unless another page section has been given hasScrollableContent // This must match the page id created in App.tsx unless another page section has been given hasScrollableContent
const mainPageContentId = "#kc-main-content-page-container"; const mainPageContentId = "#kc-main-content-page-container";
let spacesToHyphens = (string: string): string => { const spacesToHyphens = (string: string): string => {
return string.replace(/\s+/g, "-"); return string.replace(/\s+/g, "-");
}; };
export const ScrollForm = ({ sections, children }: ScrollFormProps) => { export const ScrollForm = ({ sections, children }: ScrollFormProps) => {
const { t } = useTranslation("common"); const { t } = useTranslation("common");
const Nav = () => ( const nodes = Children.toArray(children);
return (
<Grid hasGutter>
<GridItem span={8}>
{sections.map((cat, index) => (
<FormPanel scrollId={spacesToHyphens(cat)} key={cat} title={cat}>
{nodes[index]}
</FormPanel>
))}
</GridItem>
<GridItem span={4}>
<PageSection className="kc-scroll-form--sticky"> <PageSection className="kc-scroll-form--sticky">
<JumpLinks <JumpLinks
isVertical isVertical
@ -38,25 +48,12 @@ export const ScrollForm = ({ sections, children }: ScrollFormProps) => {
> >
{sections.map((cat) => ( {sections.map((cat) => (
// note that JumpLinks currently does not work with spaces in the href // note that JumpLinks currently does not work with spaces in the href
<JumpLinksItem href={`#${spacesToHyphens(cat)}`}>{cat}</JumpLinksItem> <JumpLinksItem key={cat} href={`#${spacesToHyphens(cat)}`}>
{cat}
</JumpLinksItem>
))} ))}
</JumpLinks> </JumpLinks>
</PageSection> </PageSection>
);
const nodes = Children.toArray(children);
return (
<Grid hasGutter>
<GridItem span={8}>
{sections.map((cat, index) => (
<FormPanel scrollId={spacesToHyphens(cat)} key={cat} title={cat}>
{/* <FormPanel scrollId={cat.replace(/\s+/g, "-")} key={cat} title={cat}> */}
{nodes[index]}
</FormPanel>
))}
</GridItem>
<GridItem span={4}>
<Nav />
</GridItem> </GridItem>
</Grid> </Grid>
); );

View file

@ -14,6 +14,7 @@ import _ from "lodash";
import { PaginatingTableToolbar } from "./PaginatingTableToolbar"; import { PaginatingTableToolbar } from "./PaginatingTableToolbar";
import { TableToolbar } from "./TableToolbar"; import { TableToolbar } from "./TableToolbar";
import { useFetch } from "../../context/auth/AdminClient";
type Row<T> = { type Row<T> = {
data: T; data: T;
@ -127,12 +128,16 @@ export function KeycloakDataTable<T>({
const [first, setFirst] = useState(0); const [first, setFirst] = useState(0);
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const load = async () => { const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
useEffect(() => {
return useFetch(
async () => {
setLoading(true); setLoading(true);
const data = await loader(first, max, search); const data = await loader(first, max, search);
setRows( const result = data!.map((value) => {
data!.map((value) => {
return { return {
data: value, data: value,
selected: false, selected: false,
@ -143,14 +148,15 @@ export function KeycloakDataTable<T>({
return (value as any)[col.name]; return (value as any)[col.name];
}), }),
}; };
}) });
); return result;
},
(result) => {
setRows(result);
setLoading(false); setLoading(false);
}; }
);
useEffect(() => { }, [key, first, max]);
load();
}, [first, max]);
const getNodeText = (node: keyof T | JSX.Element): string => { const getNodeText = (node: keyof T | JSX.Element): string => {
if (["string", "number"].includes(typeof node)) { if (["string", "number"].includes(typeof node)) {
@ -184,7 +190,7 @@ export function KeycloakDataTable<T>({
action.onClick = async (_, rowIndex) => { action.onClick = async (_, rowIndex) => {
const result = await actions[index].onRowClick!(rows![rowIndex].data); const result = await actions[index].onRowClick!(rows![rowIndex].data);
if (result) { if (result) {
load(); refresh();
} }
}; };
return action; return action;
@ -235,7 +241,7 @@ export function KeycloakDataTable<T>({
}} }}
inputGroupName={`${ariaLabelKey}input`} inputGroupName={`${ariaLabelKey}input`}
inputGroupOnChange={searchOnChange} inputGroupOnChange={searchOnChange}
inputGroupOnClick={load} inputGroupOnClick={refresh}
inputGroupPlaceholder={t(searchPlaceholderKey)} inputGroupPlaceholder={t(searchPlaceholderKey)}
toolbarItem={toolbarItem} toolbarItem={toolbarItem}
> >

View file

@ -16,3 +16,20 @@ export const useAdminClient = () => {
return adminClient; return adminClient;
}; };
export function useFetch<T>(
adminClientCall: () => Promise<T>,
callback: (param: T) => void
) {
let canceled = false;
adminClientCall().then((result) => {
if (!canceled) {
callback(result);
}
});
return () => {
canceled = true;
};
}

View file

@ -24,7 +24,7 @@ import { FormAccess } from "../components/form-access/FormAccess";
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";
import { useAdminClient } 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 { RoleAttributes } from "./RoleAttributes"; import { RoleAttributes } from "./RoleAttributes";
@ -110,15 +110,22 @@ export const RealmRolesForm = () => {
const [activeTab, setActiveTab] = useState(0); const [activeTab, setActiveTab] = useState(0);
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
async () => {
if (id) { if (id) {
const fetchedRole = await adminClient.roles.findOneById({ id }); const role = await adminClient.roles.findOneById({ id });
setName(fetchedRole.name!); return { role, name: role.name };
setupForm(fetchedRole);
} else { } else {
setName(t("createRole")); return { name: t("createRole") };
} }
})(); },
({ role, name }) => {
setName(name!);
if (role) {
setupForm(role);
}
}
);
}, []); }, []);
const setupForm = (role: RoleRepresentation) => { const setupForm = (role: RoleRepresentation) => {

View file

@ -17,7 +17,7 @@ import { Controller, useForm } from "react-hook-form";
import { FormAccess } from "../components/form-access/FormAccess"; import { FormAccess } from "../components/form-access/FormAccess";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { useAdminClient } from "../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation"; import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
import { RoleAttributes } from "./RoleAttributes"; import { RoleAttributes } from "./RoleAttributes";
import "./RealmRolesSection.css"; import "./RealmRolesSection.css";
@ -35,11 +35,13 @@ export const RolesTabs = () => {
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedRole = await adminClient.roles.findOneById({ id }); () => adminClient.roles.findOneById({ id }),
(fetchedRole) => {
setName(fetchedRole.name!); setName(fetchedRole.name!);
setupForm(fetchedRole); setupForm(fetchedRole);
})(); }
);
}, []); }, []);
const setupForm = (role: RoleRepresentation) => { const setupForm = (role: RoleRepresentation) => {

View file

@ -5,7 +5,7 @@ import { useParams } from "react-router-dom";
import { Button, ButtonVariant, TextInput } from "@patternfly/react-core"; import { Button, ButtonVariant, TextInput } from "@patternfly/react-core";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import "./RealmRolesSection.css"; import "./RealmRolesSection.css";
import { useAdminClient } from "../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation"; import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -46,11 +46,13 @@ export const RoleAttributes = () => {
]; ];
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedRole = await adminClient.roles.findOneById({ id }); () => adminClient.roles.findOneById({ id }),
(fetchedRole) => {
setName(fetchedRole.name!); setName(fetchedRole.name!);
setupForm(fetchedRole); setupForm(fetchedRole);
})(); }
);
}, []); }, []);
const setupForm = (role: RoleRepresentation) => { const setupForm = (role: RoleRepresentation) => {

View file

@ -22,7 +22,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 } 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";
@ -34,19 +34,23 @@ export const UserFederationSection = () => {
const { t } = useTranslation("user-federation"); const { t } = useTranslation("user-federation");
const { realm } = useContext(RealmContext); const { realm } = useContext(RealmContext);
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
const loader = async () => { useEffect(() => {
return useFetch(
() => {
const testParams: { [name: string]: string | number } = { const testParams: { [name: string]: string | number } = {
parentId: realm, parentId: realm,
type: "org.keycloak.storage.UserStorageProvider", // MF note that this is providerType in the output, but API call is still type type: "org.keycloak.storage.UserStorageProvider", // MF note that this is providerType in the output, but API call is still type
}; };
const userFederations = await adminClient.components.find(testParams); return adminClient.components.find(testParams);
},
(userFederations) => {
setUserFederations(userFederations); setUserFederations(userFederations);
}; }
);
useEffect(() => { }, [key]);
loader();
}, []);
const ufAddProviderDropdownItems = [ const ufAddProviderDropdownItems = [
<DropdownItem key="itemLDAP">LDAP</DropdownItem>, <DropdownItem key="itemLDAP">LDAP</DropdownItem>,
@ -54,7 +58,7 @@ export const UserFederationSection = () => {
]; ];
const learnMoreLinkProps = { const learnMoreLinkProps = {
title: `${t("common:learnMore")}`, title: t("common:learnMore"),
href: href:
"https://www.keycloak.org/docs/latest/server_admin/index.html#_user-storage-federation", "https://www.keycloak.org/docs/latest/server_admin/index.html#_user-storage-federation",
}; };
@ -70,7 +74,7 @@ export const UserFederationSection = () => {
onConfirm: async () => { onConfirm: async () => {
try { try {
await adminClient.components.del({ id: currentCard }); await adminClient.components.del({ id: currentCard });
await loader(); refresh();
addAlert(t("userFedDeletedSuccess"), AlertVariant.success); addAlert(t("userFedDeletedSuccess"), AlertVariant.success);
} catch (error) { } catch (error) {
addAlert(t("userFedDeleteError", { error }), AlertVariant.danger); addAlert(t("userFedDeleteError", { error }), AlertVariant.danger);

View file

@ -12,7 +12,7 @@ import { convertToFormValues } from "../../util";
import { useForm, Controller, useWatch } from "react-hook-form"; import { useForm, Controller, useWatch } from "react-hook-form";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import _ from "lodash"; import _ from "lodash";
@ -41,12 +41,10 @@ export const KerberosSettingsCache = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedComponent = await adminClient.components.findOne({ id }); () => adminClient.components.findOne({ id }),
if (fetchedComponent) { (component) => setupForm(component)
setupForm(fetchedComponent); );
}
})();
}, []); }, []);
const [isCachePolicyDropdownOpen, setIsCachePolicyDropdownOpen] = useState( const [isCachePolicyDropdownOpen, setIsCachePolicyDropdownOpen] = useState(

View file

@ -6,7 +6,7 @@ import { useForm, Controller } from "react-hook-form";
import { convertToFormValues } from "../../util"; import { convertToFormValues } from "../../util";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
export const LdapSettingsAdvanced = () => { export const LdapSettingsAdvanced = () => {
@ -27,12 +27,10 @@ export const LdapSettingsAdvanced = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedComponent = await adminClient.components.findOne({ id }); () => adminClient.components.findOne({ id }),
if (fetchedComponent) { (fetchedComponent) => setupForm(fetchedComponent)
setupForm(fetchedComponent); );
}
})();
}, []); }, []);
return ( return (

View file

@ -16,7 +16,7 @@ import { convertToFormValues } from "../../util";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { EyeIcon } from "@patternfly/react-icons"; import { EyeIcon } from "@patternfly/react-icons";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
export const LdapSettingsConnection = () => { export const LdapSettingsConnection = () => {
@ -62,12 +62,10 @@ export const LdapSettingsConnection = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedComponent = await adminClient.components.findOne({ id }); () => adminClient.components.findOne({ id }),
if (fetchedComponent) { (fetchedComponent) => setupForm(fetchedComponent)
setupForm(fetchedComponent); );
}
})();
}, []); }, []);
return ( return (

View file

@ -12,7 +12,7 @@ import { useForm, Controller } from "react-hook-form";
import { convertToFormValues } from "../../util"; import { convertToFormValues } from "../../util";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
export const LdapSettingsGeneral = () => { export const LdapSettingsGeneral = () => {
@ -37,12 +37,10 @@ export const LdapSettingsGeneral = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedComponent = await adminClient.components.findOne({ id }); () => adminClient.components.findOne({ id }),
if (fetchedComponent) { (fetchedComponent) => setupForm(fetchedComponent)
setupForm(fetchedComponent); );
}
})();
}, []); }, []);
const convertVendorNames = (vendorName: string) => { const convertVendorNames = (vendorName: string) => {

View file

@ -6,7 +6,7 @@ import { useForm, Controller } from "react-hook-form";
import { convertToFormValues } from "../../util"; import { convertToFormValues } from "../../util";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
export const LdapSettingsKerberosIntegration = () => { export const LdapSettingsKerberosIntegration = () => {
@ -28,12 +28,10 @@ export const LdapSettingsKerberosIntegration = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedComponent = await adminClient.components.findOne({ id }); () => adminClient.components.findOne({ id }),
if (fetchedComponent) { (fetchedComponent) => setupForm(fetchedComponent)
setupForm(fetchedComponent); );
}
})();
}, []); }, []);
return ( return (

View file

@ -12,7 +12,7 @@ import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useForm, Controller } from "react-hook-form"; import { useForm, Controller } from "react-hook-form";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { convertToFormValues } from "../../util"; import { convertToFormValues } from "../../util";
@ -54,12 +54,10 @@ export const LdapSettingsSearching = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedComponent = await adminClient.components.findOne({ id }); () => adminClient.components.findOne({ id }),
if (fetchedComponent) { (fetchedComponent) => setupForm(fetchedComponent)
setupForm(fetchedComponent); );
}
})();
}, []); }, []);
return ( return (

View file

@ -6,7 +6,7 @@ import { useForm, Controller } from "react-hook-form";
import { convertToFormValues } from "../../util"; import { convertToFormValues } from "../../util";
import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
export const LdapSettingsSynchronization = () => { export const LdapSettingsSynchronization = () => {
@ -27,12 +27,10 @@ export const LdapSettingsSynchronization = () => {
}; };
useEffect(() => { useEffect(() => {
(async () => { return useFetch(
const fetchedComponent = await adminClient.components.findOne({ id }); () => adminClient.components.findOne({ id }),
if (fetchedComponent) { (fetchedComponent) => setupForm(fetchedComponent)
setupForm(fetchedComponent); );
}
})();
}, []); }, []);
return ( return (