Add display names to contexts (#3032)
This commit is contained in:
parent
a6fd2cabfa
commit
e363fb68b0
13 changed files with 75 additions and 45 deletions
|
@ -21,7 +21,7 @@ import { SubGroups } from "./groups/SubGroupsContext";
|
||||||
import { RealmsProvider } from "./context/RealmsContext";
|
import { RealmsProvider } from "./context/RealmsContext";
|
||||||
import { RealmContextProvider } from "./context/realm-context/RealmContext";
|
import { RealmContextProvider } from "./context/realm-context/RealmContext";
|
||||||
import { ErrorRenderer } from "./components/error/ErrorRenderer";
|
import { ErrorRenderer } from "./components/error/ErrorRenderer";
|
||||||
import { AdminClient } from "./context/auth/AdminClient";
|
import { AdminClientContext } from "./context/auth/AdminClient";
|
||||||
import { WhoAmIContextProvider } from "./context/whoami/WhoAmI";
|
import { WhoAmIContextProvider } from "./context/whoami/WhoAmI";
|
||||||
|
|
||||||
export const mainPageContentId = "kc-main-content-page-container";
|
export const mainPageContentId = "kc-main-content-page-container";
|
||||||
|
@ -37,7 +37,7 @@ const AppContexts: FunctionComponent<AdminClientProps> = ({
|
||||||
adminClient,
|
adminClient,
|
||||||
}) => (
|
}) => (
|
||||||
<Router>
|
<Router>
|
||||||
<AdminClient.Provider value={{ keycloak, adminClient }}>
|
<AdminClientContext.Provider value={{ keycloak, adminClient }}>
|
||||||
<WhoAmIContextProvider>
|
<WhoAmIContextProvider>
|
||||||
<RealmsProvider>
|
<RealmsProvider>
|
||||||
<RealmContextProvider>
|
<RealmContextProvider>
|
||||||
|
@ -51,7 +51,7 @@ const AppContexts: FunctionComponent<AdminClientProps> = ({
|
||||||
</RealmContextProvider>
|
</RealmContextProvider>
|
||||||
</RealmsProvider>
|
</RealmsProvider>
|
||||||
</WhoAmIContextProvider>
|
</WhoAmIContextProvider>
|
||||||
</AdminClient.Provider>
|
</AdminClientContext.Provider>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { createContext, FunctionComponent, useState } from "react";
|
import { FunctionComponent, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { AlertVariant } from "@patternfly/react-core";
|
import { AlertVariant } from "@patternfly/react-core";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import type { AxiosError } from "axios";
|
import type { AxiosError } from "axios";
|
||||||
|
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
import { AlertPanel } from "./AlertPanel";
|
import { AlertPanel } from "./AlertPanel";
|
||||||
|
|
||||||
|
@ -20,7 +21,10 @@ type AlertProps = {
|
||||||
addError: AddErrorFunction;
|
addError: AddErrorFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AlertContext = createContext<AlertProps | undefined>(undefined);
|
export const AlertContext = createNamedContext<AlertProps | undefined>(
|
||||||
|
"AlertContext",
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
export const useAlerts = () => useRequiredContext(AlertContext);
|
export const useAlerts = () => useRequiredContext(AlertContext);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { FunctionComponent } from "react";
|
||||||
import { HashRouter } from "react-router-dom";
|
import { HashRouter } from "react-router-dom";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { AccessContextProvider } from "../../context/access/Access";
|
import { AccessContextProvider } from "../../context/access/Access";
|
||||||
import { AdminClient } from "../../context/auth/AdminClient";
|
import { AdminClientContext } from "../../context/auth/AdminClient";
|
||||||
import { RealmContext } from "../../context/realm-context/RealmContext";
|
import { RealmContext } from "../../context/realm-context/RealmContext";
|
||||||
import { ServerInfoContext } from "../../context/server-info/ServerInfoProvider";
|
import { ServerInfoContext } from "../../context/server-info/ServerInfoProvider";
|
||||||
import serverInfo from "../../context/server-info/__tests__/mock.json";
|
import serverInfo from "../../context/server-info/__tests__/mock.json";
|
||||||
|
@ -31,13 +31,13 @@ const MockAdminClient: FunctionComponent = ({ children }) => {
|
||||||
<ServerInfoContext.Provider
|
<ServerInfoContext.Provider
|
||||||
value={serverInfo as unknown as ServerInfoRepresentation}
|
value={serverInfo as unknown as ServerInfoRepresentation}
|
||||||
>
|
>
|
||||||
<AdminClient.Provider value={{ keycloak, adminClient }}>
|
<AdminClientContext.Provider value={{ keycloak, adminClient }}>
|
||||||
<WhoAmIContextProvider>
|
<WhoAmIContextProvider>
|
||||||
<RealmContext.Provider value={{ realm: "master" }}>
|
<RealmContext.Provider value={{ realm: "master" }}>
|
||||||
<AccessContextProvider>{children}</AccessContextProvider>
|
<AccessContextProvider>{children}</AccessContextProvider>
|
||||||
</RealmContext.Provider>
|
</RealmContext.Provider>
|
||||||
</WhoAmIContextProvider>
|
</WhoAmIContextProvider>
|
||||||
</AdminClient.Provider>
|
</AdminClientContext.Provider>
|
||||||
</ServerInfoContext.Provider>
|
</ServerInfoContext.Provider>
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,8 +9,10 @@ import {
|
||||||
TextContent,
|
TextContent,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { ExternalLinkAltIcon, HelpIcon } from "@patternfly/react-icons";
|
import { ExternalLinkAltIcon, HelpIcon } from "@patternfly/react-icons";
|
||||||
import { createContext, FunctionComponent, useState } from "react";
|
import { FunctionComponent, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
import helpUrls from "../../help-urls";
|
import helpUrls from "../../help-urls";
|
||||||
|
|
||||||
|
@ -21,7 +23,8 @@ type HelpContextProps = {
|
||||||
toggleHelp: () => void;
|
toggleHelp: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const HelpContext = createContext<HelpContextProps | undefined>(
|
export const HelpContext = createNamedContext<HelpContextProps | undefined>(
|
||||||
|
"HelpContext",
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||||
import { sortBy } from "lodash-es";
|
import { sortBy } from "lodash-es";
|
||||||
import {
|
import { FunctionComponent, useCallback, useMemo, useState } from "react";
|
||||||
createContext,
|
|
||||||
FunctionComponent,
|
|
||||||
useCallback,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
} from "react";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { RecentUsed } from "../components/realm-selector/recent-used";
|
import { RecentUsed } from "../components/realm-selector/recent-used";
|
||||||
|
import { createNamedContext } from "../utils/createNamedContext";
|
||||||
import useRequiredContext from "../utils/useRequiredContext";
|
import useRequiredContext from "../utils/useRequiredContext";
|
||||||
import { useAdminClient, useFetch } from "./auth/AdminClient";
|
import { useAdminClient, useFetch } from "./auth/AdminClient";
|
||||||
|
|
||||||
|
@ -20,7 +15,8 @@ type RealmsContextProps = {
|
||||||
refresh: () => Promise<void>;
|
refresh: () => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RealmsContext = createContext<RealmsContextProps | undefined>(
|
export const RealmsContext = createNamedContext<RealmsContextProps | undefined>(
|
||||||
|
"RealmsContext",
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import type { AccessType } from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
|
import type { AccessType } from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
|
||||||
import { createContext, FunctionComponent, useEffect, useState } from "react";
|
import { FunctionComponent, useEffect, useState } from "react";
|
||||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
import { useWhoAmI } from "../../context/whoami/WhoAmI";
|
import { useWhoAmI } from "../../context/whoami/WhoAmI";
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
|
|
||||||
type AccessContextProps = {
|
type AccessContextProps = {
|
||||||
|
@ -9,7 +10,8 @@ type AccessContextProps = {
|
||||||
hasSomeAccess: (...types: AccessType[]) => boolean;
|
hasSomeAccess: (...types: AccessType[]) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AccessContext = createContext<AccessContextProps | undefined>(
|
export const AccessContext = createNamedContext<AccessContextProps | undefined>(
|
||||||
|
"AccessContext",
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Keycloak from "keycloak-js";
|
import Keycloak from "keycloak-js";
|
||||||
import { createContext, DependencyList, useEffect } from "react";
|
import { DependencyList, useEffect } from "react";
|
||||||
import { useErrorHandler } from "react-error-boundary";
|
import { useErrorHandler } from "react-error-boundary";
|
||||||
|
|
||||||
import environment from "../../environment";
|
import environment from "../../environment";
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
|
|
||||||
export type AdminClientProps = {
|
export type AdminClientProps = {
|
||||||
|
@ -12,11 +13,11 @@ export type AdminClientProps = {
|
||||||
adminClient: KeycloakAdminClient;
|
adminClient: KeycloakAdminClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdminClient = createContext<AdminClientProps | undefined>(
|
export const AdminClientContext = createNamedContext<
|
||||||
undefined
|
AdminClientProps | undefined
|
||||||
);
|
>("AdminClientContext", undefined);
|
||||||
|
|
||||||
export const useAdminClient = () => useRequiredContext(AdminClient);
|
export const useAdminClient = () => useRequiredContext(AdminClientContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Util function to only set the state when the component is still mounted.
|
* Util function to only set the state when the component is still mounted.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createContext, FunctionComponent, useEffect, useMemo } from "react";
|
import { FunctionComponent, useEffect, useMemo } from "react";
|
||||||
import { useRouteMatch } from "react-router-dom";
|
import { useRouteMatch } from "react-router-dom";
|
||||||
import { RecentUsed } from "../../components/realm-selector/recent-used";
|
import { RecentUsed } from "../../components/realm-selector/recent-used";
|
||||||
import {
|
import {
|
||||||
|
@ -6,6 +6,7 @@ import {
|
||||||
DashboardRoute,
|
DashboardRoute,
|
||||||
} from "../../dashboard/routes/Dashboard";
|
} from "../../dashboard/routes/Dashboard";
|
||||||
import environment from "../../environment";
|
import environment from "../../environment";
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
import { useAdminClient } from "../auth/AdminClient";
|
import { useAdminClient } from "../auth/AdminClient";
|
||||||
|
|
||||||
|
@ -13,7 +14,8 @@ type RealmContextType = {
|
||||||
realm: string;
|
realm: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RealmContext = createContext<RealmContextType | undefined>(
|
export const RealmContext = createNamedContext<RealmContextType | undefined>(
|
||||||
|
"RealmContext",
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { createContext, FunctionComponent, useState } from "react";
|
import { FunctionComponent, useState } from "react";
|
||||||
|
|
||||||
import type { ServerInfoRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation";
|
import type { ServerInfoRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation";
|
||||||
|
|
||||||
import { sortProviders } from "../../util";
|
import { sortProviders } from "../../util";
|
||||||
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
|
|
||||||
export const ServerInfoContext = createContext<
|
export const ServerInfoContext = createNamedContext<
|
||||||
ServerInfoRepresentation | undefined
|
ServerInfoRepresentation | undefined
|
||||||
>(undefined);
|
>("ServerInfoContext", undefined);
|
||||||
|
|
||||||
export const useServerInfo = () => useRequiredContext(ServerInfoContext);
|
export const useServerInfo = () => useRequiredContext(ServerInfoContext);
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import type WhoAmIRepresentation from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
|
import type WhoAmIRepresentation from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
|
||||||
import type { AccessType } from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
|
import type { AccessType } from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
|
||||||
import { createContext, FunctionComponent, useState } from "react";
|
import { FunctionComponent, useState } from "react";
|
||||||
|
|
||||||
import environment from "../../environment";
|
import environment from "../../environment";
|
||||||
import i18n, { DEFAULT_LOCALE } from "../../i18n";
|
import i18n, { DEFAULT_LOCALE } from "../../i18n";
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
||||||
|
|
||||||
|
@ -53,7 +55,10 @@ type WhoAmIProps = {
|
||||||
whoAmI: WhoAmI;
|
whoAmI: WhoAmI;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WhoAmIContext = createContext<WhoAmIProps | undefined>(undefined);
|
export const WhoAmIContext = createNamedContext<WhoAmIProps | undefined>(
|
||||||
|
"WhoAmIContext",
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
export const useWhoAmI = () => useRequiredContext(WhoAmIContext);
|
export const useWhoAmI = () => useRequiredContext(WhoAmIContext);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation";
|
import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation";
|
||||||
import { createContext, FunctionComponent, useState } from "react";
|
import { FunctionComponent, useState } from "react";
|
||||||
|
import { createNamedContext } from "../utils/createNamedContext";
|
||||||
import useRequiredContext from "../utils/useRequiredContext";
|
import useRequiredContext from "../utils/useRequiredContext";
|
||||||
|
|
||||||
type SubGroupsProps = {
|
type SubGroupsProps = {
|
||||||
|
@ -10,7 +11,10 @@ type SubGroupsProps = {
|
||||||
currentGroup: () => GroupRepresentation | undefined;
|
currentGroup: () => GroupRepresentation | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SubGroupContext = createContext<SubGroupsProps | undefined>(undefined);
|
const SubGroupsContext = createNamedContext<SubGroupsProps | undefined>(
|
||||||
|
"SubGroupsContext",
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
export const SubGroups: FunctionComponent = ({ children }) => {
|
export const SubGroups: FunctionComponent = ({ children }) => {
|
||||||
const [subGroups, setSubGroups] = useState<GroupRepresentation[]>([]);
|
const [subGroups, setSubGroups] = useState<GroupRepresentation[]>([]);
|
||||||
|
@ -22,12 +26,12 @@ export const SubGroups: FunctionComponent = ({ children }) => {
|
||||||
);
|
);
|
||||||
const currentGroup = () => subGroups[subGroups.length - 1];
|
const currentGroup = () => subGroups[subGroups.length - 1];
|
||||||
return (
|
return (
|
||||||
<SubGroupContext.Provider
|
<SubGroupsContext.Provider
|
||||||
value={{ subGroups, setSubGroups, clear, remove, currentGroup }}
|
value={{ subGroups, setSubGroups, clear, remove, currentGroup }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</SubGroupContext.Provider>
|
</SubGroupsContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSubGroups = () => useRequiredContext(SubGroupContext);
|
export const useSubGroups = () => useRequiredContext(SubGroupsContext);
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import type UserProfileConfig from "@keycloak/keycloak-admin-client/lib/defs/userProfileConfig";
|
import type UserProfileConfig from "@keycloak/keycloak-admin-client/lib/defs/userProfileConfig";
|
||||||
import { AlertVariant } from "@patternfly/react-core";
|
import { AlertVariant } from "@patternfly/react-core";
|
||||||
import { createContext, FunctionComponent, useState } from "react";
|
import { FunctionComponent, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
|
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
|
||||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
|
import { createNamedContext } from "../../utils/createNamedContext";
|
||||||
import useRequiredContext from "../../utils/useRequiredContext";
|
import useRequiredContext from "../../utils/useRequiredContext";
|
||||||
|
|
||||||
type UserProfileProps = {
|
type UserProfileProps = {
|
||||||
|
@ -23,9 +24,9 @@ export type SaveOptions = {
|
||||||
errorMessageKey?: string;
|
errorMessageKey?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserProfile = createContext<UserProfileProps | undefined>(
|
export const UserProfileContext = createNamedContext<
|
||||||
undefined
|
UserProfileProps | undefined
|
||||||
);
|
>("UserProfileContext", undefined);
|
||||||
|
|
||||||
export const UserProfileProvider: FunctionComponent = ({ children }) => {
|
export const UserProfileProvider: FunctionComponent = ({ children }) => {
|
||||||
const { adminClient } = useAdminClient();
|
const { adminClient } = useAdminClient();
|
||||||
|
@ -71,10 +72,10 @@ export const UserProfileProvider: FunctionComponent = ({ children }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserProfile.Provider value={{ config, save, isSaving }}>
|
<UserProfileContext.Provider value={{ config, save, isSaving }}>
|
||||||
{children}
|
{children}
|
||||||
</UserProfile.Provider>
|
</UserProfileContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useUserProfile = () => useRequiredContext(UserProfile);
|
export const useUserProfile = () => useRequiredContext(UserProfileContext);
|
||||||
|
|
11
src/utils/createNamedContext.ts
Normal file
11
src/utils/createNamedContext.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import type { Context } from "react";
|
||||||
|
import { createContext } from "react";
|
||||||
|
|
||||||
|
export type NamedContext<T> = Context<T> &
|
||||||
|
Required<Pick<Context<T>, "displayName">>;
|
||||||
|
|
||||||
|
export function createNamedContext<T>(displayName: string, defaultValue: T) {
|
||||||
|
const context = createContext(defaultValue);
|
||||||
|
context.displayName = displayName;
|
||||||
|
return context as NamedContext<T>;
|
||||||
|
}
|
Loading…
Reference in a new issue