diff --git a/frontend/packages/console-app/package.json b/frontend/packages/console-app/package.json index 802e5162b81..337f6902119 100644 --- a/frontend/packages/console-app/package.json +++ b/frontend/packages/console-app/package.json @@ -59,7 +59,7 @@ "NamespaceDropdown": "src/components/user-preferences/namespace/NamespaceDropdown.tsx", "LanguageDropdown": "src/components/user-preferences/language/LanguageDropdown.tsx", "perspective": "src/utils/perspective.tsx", - "perspectiveConfiguration": "src/components/detect-perspective/PerspectiveConfiguration.tsx", + "perspectiveConfiguration": "src/components/detect-context/PerspectiveConfiguration.tsx", "DynamicPluginsPopover": "src/components/dashboards-page/dynamic-plugins-health-resource/DynamicPluginsPopover.tsx", "getDynamicPluginHealthState": "src/components/dashboards-page/dynamic-plugins-health-resource/status.ts", "k8sHealth": "src/components/dashboards-page/status.ts", diff --git a/frontend/packages/console-app/src/components/detect-context/DetectContext.tsx b/frontend/packages/console-app/src/components/detect-context/DetectContext.tsx new file mode 100644 index 00000000000..99fbf0705be --- /dev/null +++ b/frontend/packages/console-app/src/components/detect-context/DetectContext.tsx @@ -0,0 +1,179 @@ +import type { FC, Provider as ProviderComponent, ReactNode } from 'react'; +import { createContext, Suspense, useContext, useEffect } from 'react'; +import type { LoadedAndResolvedExtension } from '@openshift/dynamic-plugin-sdk'; +import { + Masthead, + MastheadContent, + MastheadMain, + Page, + PageSection, + PageSidebar, + PageSidebarBody, +} from '@patternfly/react-core'; +import { createPath, useLocation } from 'react-router'; +import type { Perspective, ReduxReducer, ContextProvider } from '@console/dynamic-plugin-sdk'; +import { + PerspectiveContext, + useResolvedExtensions, + isContextProvider, + isReduxReducer, +} from '@console/dynamic-plugin-sdk'; +import { applyReduxExtensions } from '@console/internal/redux'; +import { LoadingBox } from '@console/shared/src/components/loading/LoadingBox'; +import { usePerspectives } from '@console/shared/src/hooks/usePerspectives'; +import { useLanguage } from '../user-preferences/language/useLanguage'; +import { usePreferredLanguage } from '../user-preferences/language/usePreferredLanguage'; +import { NamespaceContext, useValuesForNamespaceContext } from './namespace'; +import PerspectiveDetector from './PerspectiveDetector'; +import { useValuesForPerspectiveContext } from './useValuesForPerspectiveContext'; + +const getPerspectiveURLParam = (perspectives: Perspective[]) => { + const perspectiveIDs = perspectives.map( + (nextPerspective: Perspective) => nextPerspective.properties.id, + ); + + const urlParams = new URLSearchParams(window.location.search); + const perspectiveParam = urlParams.get('perspective'); + return perspectiveParam && perspectiveIDs.includes(perspectiveParam) ? perspectiveParam : ''; +}; + +const ContextProviderExtensionsContext = createContext< + LoadedAndResolvedExtension[] +>([]); + +const EnhancedProvider: FC<{ + provider: ProviderComponent; + useValueHook: () => any; + children: ReactNode; +}> = ({ provider: Component, useValueHook, children }) => { + const value = useValueHook(); + return {children}; +}; + +const PF_BREAKPOINT_XL = 1200; + +/** Empty PatternFly Page shell shown while DetectContext is initializing. */ +export const PageSkeleton: FC<{ blame: string }> = ({ blame }) => ( + + + +
+ + + } + sidebar={ + = PF_BREAKPOINT_XL}> + + + } + > + + + + +); + +/** Wraps children in plugin-provided context providers resolved by DetectContext. */ +export const ContextProviderExtensionWrapper: FC<{ children: ReactNode }> = ({ children }) => { + const contextProviderExtensions = useContext(ContextProviderExtensionsContext); + return ( + }> + {contextProviderExtensions.reduce( + (acc, e) => ( + + {acc} + + ), + children, + )} + + ); +}; + +/** + * Bootstraps the console by running all detection and resolution hooks at the + * same component level so their async work executes in parallel: + * + * - Detect the active perspective (user prefs, URL param, or auto-detection) + * - Detect the active namespace (user prefs, URL, or K8s API fallback) + * - Detect the preferred language (user prefs, then apply via i18n) + * - Resolve all ReduxReducer and ContextProvider plugin extensions + * + * Once ready, provides the resolved values via PerspectiveContext, + * NamespaceContext, and ContextProviderExtensionsContext. + */ +export const DetectContext: FC<{ children: ReactNode }> = ({ children }) => { + const [ + activePerspective, + setActivePerspective, + perspectiveLoaded, + ] = useValuesForPerspectiveContext(); + const { namespace, setNamespace, loaded: namespaceLoaded } = useValuesForNamespaceContext(); + + const [preferredLanguage, , preferredLanguageLoaded] = usePreferredLanguage(); + useLanguage(preferredLanguage, preferredLanguageLoaded); + + const [reduxReducerExtensions, reducersResolved] = useResolvedExtensions( + isReduxReducer, + ); + const [contextProviderExtensions, providersResolved] = useResolvedExtensions( + isContextProvider, + ); + + const perspectiveExtensions = usePerspectives(); + const perspectiveParam = getPerspectiveURLParam(perspectiveExtensions); + const location = useLocation(); + + useEffect(() => { + if (perspectiveParam && perspectiveParam !== activePerspective) { + setActivePerspective(perspectiveParam, createPath(location)); + } + }, [perspectiveParam, activePerspective, setActivePerspective, location]); + + useEffect(() => { + if (reducersResolved) { + applyReduxExtensions(reduxReducerExtensions); + } + }, [reducersResolved, reduxReducerExtensions]); + + const needsPerspectiveDetection = perspectiveLoaded && !activePerspective; + const ready = + perspectiveLoaded && + !!activePerspective && + namespaceLoaded && + reducersResolved && + providersResolved && + preferredLanguageLoaded; + + if (!ready) { + const pending: string[] = []; + if (!perspectiveLoaded) pending.push('Perspective'); + if (needsPerspectiveDetection) pending.push('PerspectiveDetection'); + if (!namespaceLoaded) pending.push('Namespace'); + if (!reducersResolved) pending.push('Reducers'); + if (!providersResolved) pending.push('Providers'); + if (!preferredLanguageLoaded) pending.push('Language'); + + return ( + <> + {needsPerspectiveDetection && ( + + )} + + + ); + } + + return ( + + + + {children} + + + + ); +}; diff --git a/frontend/packages/console-app/src/components/detect-perspective/PerspectiveConfiguration.tsx b/frontend/packages/console-app/src/components/detect-context/PerspectiveConfiguration.tsx similarity index 100% rename from frontend/packages/console-app/src/components/detect-perspective/PerspectiveConfiguration.tsx rename to frontend/packages/console-app/src/components/detect-context/PerspectiveConfiguration.tsx diff --git a/frontend/packages/console-app/src/components/detect-perspective/PerspectiveDetector.tsx b/frontend/packages/console-app/src/components/detect-context/PerspectiveDetector.tsx similarity index 100% rename from frontend/packages/console-app/src/components/detect-perspective/PerspectiveDetector.tsx rename to frontend/packages/console-app/src/components/detect-context/PerspectiveDetector.tsx diff --git a/frontend/packages/console-app/src/components/detect-perspective/__tests__/DetectPerspective.spec.tsx b/frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx similarity index 65% rename from frontend/packages/console-app/src/components/detect-perspective/__tests__/DetectPerspective.spec.tsx rename to frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx index 3fff46721b4..96c867bd785 100644 --- a/frontend/packages/console-app/src/components/detect-perspective/__tests__/DetectPerspective.spec.tsx +++ b/frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; import { useLocation } from 'react-router'; import { usePerspectives } from '@console/shared/src/hooks/usePerspectives'; -import DetectPerspective from '../DetectPerspective'; +import { DetectContext } from '../DetectContext'; import { useValuesForPerspectiveContext } from '../useValuesForPerspectiveContext'; const MockApp = () =>

App

; @@ -15,19 +15,48 @@ jest.mock('../useValuesForPerspectiveContext', () => ({ useValuesForPerspectiveContext: jest.fn(), })); +jest.mock('../namespace', () => ({ + NamespaceContext: { Provider: ({ children }) => children, Consumer: () => null }, + useValuesForNamespaceContext: jest.fn().mockReturnValue({ + namespace: 'default', + setNamespace: jest.fn(), + loaded: true, + }), +})); + +jest.mock('../../user-preferences/language/usePreferredLanguage', () => ({ + usePreferredLanguage: jest.fn().mockReturnValue(['en', jest.fn(), true]), +})); + +jest.mock('../../user-preferences/language/useLanguage', () => ({ + useLanguage: jest.fn(), +})); + jest.mock('@console/shared/src/hooks/usePerspectives', () => ({ usePerspectives: jest.fn(), })); +jest.mock('@console/dynamic-plugin-sdk', () => ({ + PerspectiveContext: { Provider: ({ children }) => children, Consumer: () => null }, + useResolvedExtensions: jest.fn().mockReturnValue([[], true]), + isContextProvider: jest.fn(), + isReduxReducer: jest.fn(), +})); + +jest.mock('@console/internal/redux', () => ({ + applyReduxExtensions: jest.fn(), +})); + jest.mock('react-router', () => ({ useLocation: jest.fn(), + createPath: jest.fn((loc) => loc.pathname), })); const useValuesForPerspectiveContextMock = useValuesForPerspectiveContext as jest.Mock; const usePerspectivesMock = usePerspectives as jest.Mock; const useLocationMock = useLocation as jest.Mock; -describe('DetectPerspective', () => { +describe('DetectContext', () => { beforeEach(() => { useValuesForPerspectiveContextMock.mockClear(); usePerspectivesMock.mockClear(); @@ -44,9 +73,9 @@ describe('DetectPerspective', () => { ]); render( - + - , + , ); expect(screen.getByRole('heading', { name: 'App' })).toBeVisible(); @@ -61,9 +90,9 @@ describe('DetectPerspective', () => { ]); render( - + - , + , ); expect(screen.getByText('PerspectiveDetector')).toBeVisible(); diff --git a/frontend/packages/console-app/src/components/detect-perspective/__tests__/PerspectiveDetector.spec.tsx b/frontend/packages/console-app/src/components/detect-context/__tests__/PerspectiveDetector.spec.tsx similarity index 100% rename from frontend/packages/console-app/src/components/detect-perspective/__tests__/PerspectiveDetector.spec.tsx rename to frontend/packages/console-app/src/components/detect-context/__tests__/PerspectiveDetector.spec.tsx diff --git a/frontend/packages/console-app/src/components/detect-namespace/__tests__/checkNamespaceExists.spec.ts b/frontend/packages/console-app/src/components/detect-context/__tests__/checkNamespaceExists.spec.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-namespace/__tests__/checkNamespaceExists.spec.ts rename to frontend/packages/console-app/src/components/detect-context/__tests__/checkNamespaceExists.spec.ts diff --git a/frontend/packages/console-app/src/components/detect-namespace/__tests__/getValueForNamespace.spec.ts b/frontend/packages/console-app/src/components/detect-context/__tests__/getValueForNamespace.spec.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-namespace/__tests__/getValueForNamespace.spec.ts rename to frontend/packages/console-app/src/components/detect-context/__tests__/getValueForNamespace.spec.ts diff --git a/frontend/packages/console-app/src/components/detect-namespace/__tests__/namespace.spec.ts b/frontend/packages/console-app/src/components/detect-context/__tests__/namespace.spec.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-namespace/__tests__/namespace.spec.ts rename to frontend/packages/console-app/src/components/detect-context/__tests__/namespace.spec.ts diff --git a/frontend/packages/console-app/src/components/detect-perspective/__tests__/useValuesForPerspectiveContext.spec.ts b/frontend/packages/console-app/src/components/detect-context/__tests__/useValuesForPerspectiveContext.spec.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-perspective/__tests__/useValuesForPerspectiveContext.spec.ts rename to frontend/packages/console-app/src/components/detect-context/__tests__/useValuesForPerspectiveContext.spec.ts diff --git a/frontend/packages/console-app/src/components/detect-namespace/checkNamespaceExists.ts b/frontend/packages/console-app/src/components/detect-context/checkNamespaceExists.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-namespace/checkNamespaceExists.ts rename to frontend/packages/console-app/src/components/detect-context/checkNamespaceExists.ts diff --git a/frontend/packages/console-app/src/components/detect-namespace/getValueForNamespace.ts b/frontend/packages/console-app/src/components/detect-context/getValueForNamespace.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-namespace/getValueForNamespace.ts rename to frontend/packages/console-app/src/components/detect-context/getValueForNamespace.ts diff --git a/frontend/packages/console-app/src/components/detect-namespace/namespace.ts b/frontend/packages/console-app/src/components/detect-context/namespace.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-namespace/namespace.ts rename to frontend/packages/console-app/src/components/detect-context/namespace.ts diff --git a/frontend/packages/console-app/src/components/detect-namespace/useLastNamespace.ts b/frontend/packages/console-app/src/components/detect-context/useLastNamespace.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-namespace/useLastNamespace.ts rename to frontend/packages/console-app/src/components/detect-context/useLastNamespace.ts diff --git a/frontend/packages/console-app/src/components/detect-perspective/useLastPerspective.ts b/frontend/packages/console-app/src/components/detect-context/useLastPerspective.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-perspective/useLastPerspective.ts rename to frontend/packages/console-app/src/components/detect-context/useLastPerspective.ts diff --git a/frontend/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts b/frontend/packages/console-app/src/components/detect-context/useValuesForPerspectiveContext.ts similarity index 100% rename from frontend/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts rename to frontend/packages/console-app/src/components/detect-context/useValuesForPerspectiveContext.ts diff --git a/frontend/packages/console-app/src/components/detect-language/DetectLanguage.tsx b/frontend/packages/console-app/src/components/detect-language/DetectLanguage.tsx deleted file mode 100644 index 9cdd8ea2123..00000000000 --- a/frontend/packages/console-app/src/components/detect-language/DetectLanguage.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { memo } from 'react'; -import { useLanguage } from '../user-preferences/language/useLanguage'; -import { usePreferredLanguage } from '../user-preferences/language/usePreferredLanguage'; - -const DetectLanguage = memo(() => { - const [preferredLanguage, , preferredLanguageLoaded] = usePreferredLanguage(); - useLanguage(preferredLanguage, preferredLanguageLoaded); - return null; -}); - -export default DetectLanguage; diff --git a/frontend/packages/console-app/src/components/detect-namespace/DetectNamespace.tsx b/frontend/packages/console-app/src/components/detect-namespace/DetectNamespace.tsx deleted file mode 100644 index 59a6d4e0c3c..00000000000 --- a/frontend/packages/console-app/src/components/detect-namespace/DetectNamespace.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { FC, ReactNode } from 'react'; -import { LoadingBox } from '@console/shared/src/components/loading/LoadingBox'; -import { NamespaceContext, useValuesForNamespaceContext } from './namespace'; - -type DetectNamespaceProps = { - children: ReactNode; -}; - -const DetectNamespace: FC = ({ children }) => { - const { namespace, setNamespace, loaded } = useValuesForNamespaceContext(); - return loaded ? ( - - {children} - - ) : ( - - ); -}; - -export default DetectNamespace; diff --git a/frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx b/frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx deleted file mode 100644 index 94c1738d443..00000000000 --- a/frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import type { FC } from 'react'; -import { useEffect } from 'react'; -import { createPath, useLocation } from 'react-router'; -import type { Perspective } from '@console/dynamic-plugin-sdk'; -import { PerspectiveContext } from '@console/dynamic-plugin-sdk'; -import { LoadingBox } from '@console/shared/src/components/loading/LoadingBox'; -import { usePerspectives } from '@console/shared/src/hooks/usePerspectives'; -import PerspectiveDetector from './PerspectiveDetector'; -import { useValuesForPerspectiveContext } from './useValuesForPerspectiveContext'; - -type DetectPerspectiveProps = { - children: React.ReactNode; -}; - -const getPerspectiveURLParam = (perspectives: Perspective[]) => { - const perspectiveIDs = perspectives.map( - (nextPerspective: Perspective) => nextPerspective.properties.id, - ); - - const urlParams = new URLSearchParams(window.location.search); - const perspectiveParam = urlParams.get('perspective'); - return perspectiveParam && perspectiveIDs.includes(perspectiveParam) ? perspectiveParam : ''; -}; - -const DetectPerspective: FC = ({ children }) => { - const [activePerspective, setActivePerspective, loaded] = useValuesForPerspectiveContext(); - const perspectiveExtensions = usePerspectives(); - const perspectiveParam = getPerspectiveURLParam(perspectiveExtensions); - const location = useLocation(); - useEffect(() => { - if (perspectiveParam && perspectiveParam !== activePerspective) { - setActivePerspective(perspectiveParam, createPath(location)); - } - }, [perspectiveParam, activePerspective, setActivePerspective, location]); - - return loaded ? ( - activePerspective ? ( - - {children} - - ) : ( - - ) - ) : ( - - ); -}; - -export default DetectPerspective; diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts b/frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts index c75b25b2d34..5a44d8e2c0a 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts @@ -85,7 +85,7 @@ export const useDashboardResources: UseDashboardResources = require('@console/sh export const useURLPoll: UseURLPoll = require('@console/internal/components/utils/url-poll-hook') .useURLPoll; -export const useLastNamespace: UseLastNamespace = require('@console/app/src/components/detect-namespace/useLastNamespace') +export const useLastNamespace: UseLastNamespace = require('@console/app/src/components/detect-context/useLastNamespace') .useLastNamespace; export const ConsoleDataView: < diff --git a/frontend/packages/console-shared/src/hooks/useActiveNamespace.ts b/frontend/packages/console-shared/src/hooks/useActiveNamespace.ts index fb0c9787267..f3b423112f1 100644 --- a/frontend/packages/console-shared/src/hooks/useActiveNamespace.ts +++ b/frontend/packages/console-shared/src/hooks/useActiveNamespace.ts @@ -1,5 +1,5 @@ import { useContext } from 'react'; -import { NamespaceContext } from '@console/app/src/components/detect-namespace/namespace'; +import { NamespaceContext } from '@console/app/src/components/detect-context/namespace'; import type { UseActiveNamespace } from '@console/dynamic-plugin-sdk/src/extensions/console-types'; export const useActiveNamespace: UseActiveNamespace = () => { diff --git a/frontend/public/components/app.tsx b/frontend/public/components/app.tsx index d72515f51c3..7e6dcb7e1a9 100644 --- a/frontend/public/components/app.tsx +++ b/frontend/public/components/app.tsx @@ -10,7 +10,7 @@ import { Suspense, useMemo, } from 'react'; -import type { FC, Provider as ProviderComponent, ReactNode } from 'react'; +import type { FC } from 'react'; import { createRoot } from 'react-dom/client'; import { Helmet, HelmetProvider } from 'react-helmet-async'; import { linkify } from 'react-linkify'; @@ -19,9 +19,8 @@ import { useConsoleDispatch } from '@console/shared/src/hooks/useConsoleDispatch import { useConsoleSelector } from '@console/shared/src/hooks/useConsoleSelector'; import { mapExtensionToRoutes } from '@console/app/src/hooks/usePluginRoutes'; import { BrowserRouter, useParams, useLocation, Routes, Route } from 'react-router'; -import store, { applyReduxExtensions } from '../redux'; +import store from '../redux'; import { useTranslation } from 'react-i18next'; -import type { LoadedAndResolvedExtension } from '@openshift/dynamic-plugin-sdk'; import { PluginStoreProvider } from '@openshift/dynamic-plugin-sdk'; import { detectFeatures } from '../actions/features'; import { setFlag } from '../actions/flags'; @@ -39,21 +38,14 @@ import { receivedResources, startAPIDiscovery } from '../actions/k8s'; import { pluginStore } from '../plugins'; // cloud shell imports must come later than features import CloudShellDrawer from '@console/webterminal-plugin/src/components/cloud-shell/CloudShell'; -import DetectPerspective from '@console/app/src/components/detect-perspective/DetectPerspective'; -import DetectNamespace from '@console/app/src/components/detect-namespace/DetectNamespace'; -import DetectLanguage from '@console/app/src/components/detect-language/DetectLanguage'; +import { + ContextProviderExtensionWrapper, + DetectContext, + PageSkeleton, +} from '@console/app/src/components/detect-context/DetectContext'; import { FeatureFlagExtensionLoader } from '@console/app/src/components/flags/FeatureFlagExtensionLoader'; import { useExtensions } from '@console/plugin-sdk/src/api/useExtensions'; -import { - useResolvedExtensions, - isContextProvider, - isReduxReducer, - isStandaloneRoutePage, - getUser, - useActivePerspective, - ReduxReducer, - ContextProvider, -} from '@console/dynamic-plugin-sdk'; +import { isStandaloneRoutePage, getUser, useActivePerspective } from '@console/dynamic-plugin-sdk'; import { GuidedTour } from '@console/app/src/components/tour'; import { QuickStartDrawer } from '@console/app/src/components/quick-starts/QuickStartDrawer'; import { ModalProvider } from '@console/dynamic-plugin-sdk/src/app/modal-support/ModalProvider'; @@ -65,6 +57,7 @@ import { useDebounceCallback } from '@console/shared/src/hooks/useDebounceCallba import { LOGIN_ERROR_PATH } from '@console/internal/module/auth'; import { FLAGS } from '@console/shared/src/constants/common'; import { useFlag } from '@console/shared/src/hooks/useFlag'; +import { coFetch } from '@console/shared/src/utils/console-fetch'; import { addTestError } from '@console/shared/src/utils/test-errors'; import Lightspeed from '@console/app/src/components/lightspeed/Lightspeed'; import { ThemeProvider } from './ThemeProvider'; @@ -87,24 +80,21 @@ import { useCSPViolationDetector } from '@console/app/src/hooks/useCSPViolationD import { useNotificationPoller } from '@console/app/src/hooks/useNotificationPoller'; import { useImpersonateRefreshFeatures } from './useImpersonateRefreshFeatures'; +const root = createRoot(document.getElementById('app')!); +root.render(); + +// Trigger an early authenticated fetch so unauthenticated users are redirected +// to the login page immediately, before the app shell renders. coFetch's 401 +// interceptor calls authSvc.handle401() which handles the redirect. +coFetch(`${window.SERVER_FLAGS.basePath}api/kubernetes/api`).catch(() => {}); + initI18n(); // Disable linkify 'fuzzy links' across the app. // Only linkify url strings beginning with a proper protocol scheme. linkify.set({ fuzzyLink: false }); -const EnhancedProvider: FC<{ - provider: ProviderComponent; - useValueHook: () => any; - children: ReactNode; -}> = ({ provider: Component, useValueHook, children }) => { - const value = useValueHook(); - return {children}; -}; - -const App: FC<{ - contextProviderExtensions: LoadedAndResolvedExtension[]; -}> = ({ contextProviderExtensions }) => { +const App: FC = () => { const { t } = useTranslation(); const location = useLocation(); const params = useParams(); @@ -253,7 +243,7 @@ const App: FC<{ }; const content = ( - }> + }> @@ -312,49 +302,18 @@ const App: FC<{ ); return ( - + - - - - - }> - {contextProviderExtensions.reduce( - (children, e) => ( - - {children} - - ), - content, - )} - - - - - - - ); -}; - -const AppWithExtensions: FC = () => { - const [reduxReducerExtensions, reducersResolved] = useResolvedExtensions( - isReduxReducer, - ); - const [contextProviderExtensions, providersResolved] = useResolvedExtensions( - isContextProvider, + + + + {content} + + + ); - - if (reducersResolved && providersResolved) { - applyReduxExtensions(reduxReducerExtensions); - return ; - } - - return ; }; -const root = createRoot(document.getElementById('app')!); -root.render(); - const AppRouter: FC = () => { const standaloneRouteExtensions = useExtensions(isStandaloneRoutePage); @@ -382,7 +341,7 @@ const AppRouter: FC = () => { */} } /> {standaloneRoutes} - } /> + } /> ); diff --git a/frontend/public/style/_layout.scss b/frontend/public/style/_layout.scss index 52c03bf19e1..6af39f4533e 100644 --- a/frontend/public/style/_layout.scss +++ b/frontend/public/style/_layout.scss @@ -1,3 +1,5 @@ +@use './vars'; + html, body, #app, @@ -12,6 +14,11 @@ body, overflow: auto; } +.co-page-skeleton__masthead-spacer { + height: vars.$co-button-height; + visibility: hidden; +} + .co-p-has-sidebar { display: flex; flex: 1;