Add display names to contexts (#3032)

This commit is contained in:
Jon Koops 2022-08-03 15:15:04 +02:00 committed by GitHub
parent a6fd2cabfa
commit e363fb68b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 75 additions and 45 deletions

View file

@ -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>
); );

View file

@ -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);

View file

@ -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>
); );

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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.

View file

@ -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
); );

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View 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>;
}