Split realm context into two (#1523)
This commit is contained in:
parent
2b45a83109
commit
d7362a97a0
8 changed files with 96 additions and 68 deletions
|
@ -15,6 +15,7 @@ import { routes, RouteDef } from "./route-config";
|
|||
import { PageBreadCrumbs } from "./components/bread-crumb/PageBreadCrumbs";
|
||||
import { ForbiddenSection } from "./ForbiddenSection";
|
||||
import { SubGroups } from "./groups/SubGroupsContext";
|
||||
import { RealmsProvider } from "./context/RealmsContext";
|
||||
import { RealmContextProvider } from "./context/realm-context/RealmContext";
|
||||
import { ErrorRenderer } from "./components/error/ErrorRenderer";
|
||||
import { AdminClient } from "./context/auth/AdminClient";
|
||||
|
@ -34,6 +35,7 @@ const AppContexts: FunctionComponent<AdminClientProps> = ({
|
|||
<Router>
|
||||
<AdminClient.Provider value={adminClient}>
|
||||
<WhoAmIContextProvider>
|
||||
<RealmsProvider>
|
||||
<RealmContextProvider>
|
||||
<AccessContextProvider>
|
||||
<Help>
|
||||
|
@ -45,6 +47,7 @@ const AppContexts: FunctionComponent<AdminClientProps> = ({
|
|||
</Help>
|
||||
</AccessContextProvider>
|
||||
</RealmContextProvider>
|
||||
</RealmsProvider>
|
||||
</WhoAmIContextProvider>
|
||||
</AdminClient.Provider>
|
||||
</Router>
|
||||
|
|
|
@ -47,13 +47,7 @@ export const MockAdminClient: FunctionComponent<{ mock?: object }> = (
|
|||
}
|
||||
>
|
||||
<WhoAmIContextProvider>
|
||||
<RealmContext.Provider
|
||||
value={{
|
||||
realm: "master",
|
||||
realms: [],
|
||||
refresh: () => Promise.resolve(),
|
||||
}}
|
||||
>
|
||||
<RealmContext.Provider value={{ realm: "master" }}>
|
||||
<AccessContextProvider>{props.children}</AccessContextProvider>
|
||||
</RealmContext.Provider>
|
||||
</WhoAmIContextProvider>
|
||||
|
|
|
@ -22,13 +22,7 @@ describe("FormAccess", () => {
|
|||
whoAmI: new WhoAmI(whoami as WhoAmIRepresentation),
|
||||
}}
|
||||
>
|
||||
<RealmContext.Provider
|
||||
value={{
|
||||
realm,
|
||||
realms: [],
|
||||
refresh: () => Promise.resolve(),
|
||||
}}
|
||||
>
|
||||
<RealmContext.Provider value={{ realm }}>
|
||||
<AccessContextProvider>
|
||||
<FormAccess role="manage-clients">
|
||||
<FormGroup label="test" fieldId="field">
|
||||
|
|
|
@ -16,6 +16,7 @@ import { useTranslation } from "react-i18next";
|
|||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { useRealms } from "../../context/RealmsContext";
|
||||
import { useWhoAmI } from "../../context/whoami/WhoAmI";
|
||||
import { toDashboard } from "../../dashboard/routes/Dashboard";
|
||||
import { toAddRealm } from "../../realm/routes/AddRealm";
|
||||
|
@ -25,7 +26,8 @@ import { RecentUsed } from "./recent-used";
|
|||
import "./realm-selector.css";
|
||||
|
||||
export const RealmSelector = () => {
|
||||
const { realm, realms } = useRealm();
|
||||
const { realm } = useRealm();
|
||||
const { realms } = useRealms();
|
||||
const { whoAmI } = useWhoAmI();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
|
|
58
src/context/RealmsContext.tsx
Normal file
58
src/context/RealmsContext.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||
import { sortBy } from "lodash";
|
||||
import React, {
|
||||
createContext,
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { RecentUsed } from "../components/realm-selector/recent-used";
|
||||
import useRequiredContext from "../utils/useRequiredContext";
|
||||
import { useAdminClient, useFetch } from "./auth/AdminClient";
|
||||
|
||||
type RealmsContextProps = {
|
||||
/** A list of all the realms. */
|
||||
realms: RealmRepresentation[];
|
||||
/** Refreshes the realms with the latest information. */
|
||||
refresh: () => Promise<void>;
|
||||
};
|
||||
|
||||
export const RealmsContext = createContext<RealmsContextProps | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
export const RealmsProvider: FunctionComponent = ({ children }) => {
|
||||
const adminClient = useAdminClient();
|
||||
const [realms, setRealms] = useState<RealmRepresentation[]>([]);
|
||||
const recentUsed = useMemo(() => new RecentUsed(), []);
|
||||
|
||||
function updateRealms(realms: RealmRepresentation[]) {
|
||||
setRealms(sortBy(realms, "realm"));
|
||||
recentUsed.clean(realms.map(({ realm }) => realm!));
|
||||
}
|
||||
|
||||
useFetch(
|
||||
() => adminClient.realms.find(),
|
||||
(realms) => updateRealms(realms),
|
||||
[]
|
||||
);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
//this is needed otherwise the realm find function will not return
|
||||
//new or renamed realms because of the cached realms in the token (perhaps?)
|
||||
await adminClient.keycloak?.updateToken(Number.MAX_VALUE);
|
||||
updateRealms(await adminClient.realms.find());
|
||||
}, []);
|
||||
|
||||
const value = useMemo<RealmsContextProps>(
|
||||
() => ({ realms, refresh }),
|
||||
[realms, refresh]
|
||||
);
|
||||
|
||||
return (
|
||||
<RealmsContext.Provider value={value}>{children}</RealmsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useRealms = () => useRequiredContext(RealmsContext);
|
|
@ -1,6 +1,4 @@
|
|||
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||
import _ from "lodash";
|
||||
import React, { FunctionComponent, useEffect, useMemo, useState } from "react";
|
||||
import React, { FunctionComponent, useEffect, useMemo } from "react";
|
||||
import { useRouteMatch } from "react-router-dom";
|
||||
import { RecentUsed } from "../../components/realm-selector/recent-used";
|
||||
import {
|
||||
|
@ -9,12 +7,10 @@ import {
|
|||
} from "../../dashboard/routes/Dashboard";
|
||||
import environment from "../../environment";
|
||||
import useRequiredContext from "../../utils/useRequiredContext";
|
||||
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
||||
import { useAdminClient } from "../auth/AdminClient";
|
||||
|
||||
type RealmContextType = {
|
||||
realm: string;
|
||||
realms: RealmRepresentation[];
|
||||
refresh: () => Promise<void>;
|
||||
};
|
||||
|
||||
export const RealmContext = React.createContext<RealmContextType | undefined>(
|
||||
|
@ -22,6 +18,8 @@ export const RealmContext = React.createContext<RealmContextType | undefined>(
|
|||
);
|
||||
|
||||
export const RealmContextProvider: FunctionComponent = ({ children }) => {
|
||||
const adminClient = useAdminClient();
|
||||
const recentUsed = useMemo(() => new RecentUsed(), []);
|
||||
const routeMatch = useRouteMatch<DashboardParams>(DashboardRoute.path);
|
||||
const realmParam = routeMatch?.params.realm;
|
||||
const realm = useMemo(
|
||||
|
@ -29,43 +27,16 @@ export const RealmContextProvider: FunctionComponent = ({ children }) => {
|
|||
[realmParam]
|
||||
);
|
||||
|
||||
const [realms, setRealms] = useState<RealmRepresentation[]>([]);
|
||||
const adminClient = useAdminClient();
|
||||
const recentUsed = new RecentUsed();
|
||||
|
||||
const updateRealmsList = (realms: RealmRepresentation[]) => {
|
||||
setRealms(_.sortBy(realms, "realm"));
|
||||
recentUsed.clean(realms.map((r) => r.realm!));
|
||||
};
|
||||
|
||||
useFetch(
|
||||
() => adminClient.realms.find(),
|
||||
(realms) => updateRealmsList(realms),
|
||||
[]
|
||||
);
|
||||
|
||||
// Configure admin client to use selected realm when it changes.
|
||||
useEffect(() => adminClient.setConfig({ realmName: realm }), [realm]);
|
||||
|
||||
// Keep track of recently used realms when selected realm changes.
|
||||
useEffect(() => recentUsed.setRecentUsed(realm), [realm]);
|
||||
|
||||
const value = useMemo(() => ({ realm }), [realm]);
|
||||
|
||||
return (
|
||||
<RealmContext.Provider
|
||||
value={{
|
||||
realm,
|
||||
realms,
|
||||
refresh: async () => {
|
||||
//this is needed otherwise the realm find function will not return
|
||||
//new or renamed realms because of the cached realms in the token (perhaps?)
|
||||
await adminClient.keycloak?.updateToken(Number.MAX_VALUE);
|
||||
const list = await adminClient.realms.find();
|
||||
updateRealmsList(list);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</RealmContext.Provider>
|
||||
<RealmContext.Provider value={value}>{children}</RealmContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/de
|
|||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { useRealms } from "../context/RealmsContext";
|
||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||
|
@ -48,6 +49,8 @@ import { toRealmSettings } from "./routes/RealmSettings";
|
|||
import { LocalizationTab } from "./LocalizationTab";
|
||||
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||
import { DEFAULT_LOCALE } from "../i18n";
|
||||
import { toDashboard } from "../dashboard/routes/Dashboard";
|
||||
import environment from "../environment";
|
||||
|
||||
type RealmSettingsHeaderProps = {
|
||||
onChange: (value: boolean) => void;
|
||||
|
@ -66,6 +69,7 @@ const RealmSettingsHeader = ({
|
|||
}: RealmSettingsHeaderProps) => {
|
||||
const { t } = useTranslation("realm-settings");
|
||||
const adminClient = useAdminClient();
|
||||
const { refresh: refreshRealms } = useRealms();
|
||||
const { addAlert, addError } = useAlerts();
|
||||
const history = useHistory();
|
||||
const [partialImportOpen, setPartialImportOpen] = useState(false);
|
||||
|
@ -90,7 +94,8 @@ const RealmSettingsHeader = ({
|
|||
try {
|
||||
await adminClient.realms.del({ realm: realmName });
|
||||
addAlert(t("deletedSuccess"), AlertVariant.success);
|
||||
history.push("/master/");
|
||||
await refreshRealms();
|
||||
history.push(toDashboard({ realm: environment.masterRealm }));
|
||||
refresh();
|
||||
} catch (error) {
|
||||
addError("realm-settings:deleteError", error);
|
||||
|
@ -163,7 +168,8 @@ export const RealmSettingsTabs = ({
|
|||
const { t } = useTranslation("realm-settings");
|
||||
const adminClient = useAdminClient();
|
||||
const { addAlert, addError } = useAlerts();
|
||||
const { realm: realmName, refresh: refreshRealm } = useRealm();
|
||||
const { realm: realmName } = useRealm();
|
||||
const { refresh: refreshRealms } = useRealms();
|
||||
const history = useHistory();
|
||||
|
||||
const kpComponentTypes =
|
||||
|
@ -215,7 +221,7 @@ export const RealmSettingsTabs = ({
|
|||
setupForm(realm);
|
||||
const isRealmRenamed = realmName !== realm.realm;
|
||||
if (isRealmRenamed) {
|
||||
await refreshRealm();
|
||||
await refreshRealms();
|
||||
history.push(toRealmSettings({ realm: realm.realm! }));
|
||||
}
|
||||
addAlert(t("saveSuccess"), AlertVariant.success);
|
||||
|
|
|
@ -17,7 +17,7 @@ import { FormAccess } from "../../components/form-access/FormAccess";
|
|||
import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload";
|
||||
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
||||
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { useRealms } from "../../context/RealmsContext";
|
||||
import { useWhoAmI } from "../../context/whoami/WhoAmI";
|
||||
import { toDashboard } from "../../dashboard/routes/Dashboard";
|
||||
|
||||
|
@ -25,7 +25,7 @@ export default function NewRealmForm() {
|
|||
const { t } = useTranslation("realm");
|
||||
const history = useHistory();
|
||||
const { refresh } = useWhoAmI();
|
||||
const { refresh: realmRefresh } = useRealm();
|
||||
const { refresh: refreshRealms } = useRealms();
|
||||
const adminClient = useAdminClient();
|
||||
const { addAlert, addError } = useAlerts();
|
||||
|
||||
|
@ -45,7 +45,7 @@ export default function NewRealmForm() {
|
|||
addAlert(t("saveRealmSuccess"), AlertVariant.success);
|
||||
|
||||
refresh();
|
||||
await realmRefresh();
|
||||
await refreshRealms();
|
||||
history.push(toDashboard({ realm: realm.realm }));
|
||||
} catch (error) {
|
||||
addError("realm:saveRealmError", error);
|
||||
|
|
Loading…
Reference in a new issue