diff --git a/apps/admin-x-demo/src/App.tsx b/apps/admin-x-demo/src/App.tsx index d5f34e0eec..b39172f679 100644 --- a/apps/admin-x-demo/src/App.tsx +++ b/apps/admin-x-demo/src/App.tsx @@ -1,6 +1,7 @@ import MainContent from './MainContent'; import {DesignSystemApp, DesignSystemAppProps} from '@tryghost/admin-x-design-system'; import {FrameworkProvider, TopLevelFrameworkProps} from '@tryghost/admin-x-framework'; +import {RoutingProvider} from '@tryghost/admin-x-framework/routing'; interface AppProps { framework: TopLevelFrameworkProps; @@ -16,10 +17,12 @@ const modals = { const App: React.FC = ({framework, designSystem}) => { return ( - - - - + + + + + + ); }; diff --git a/apps/admin-x-framework/src/providers/FrameworkProvider.tsx b/apps/admin-x-framework/src/providers/FrameworkProvider.tsx index b94292ab37..d56615813a 100644 --- a/apps/admin-x-framework/src/providers/FrameworkProvider.tsx +++ b/apps/admin-x-framework/src/providers/FrameworkProvider.tsx @@ -2,13 +2,11 @@ import {ErrorBoundary as SentryErrorBoundary} from '@sentry/react'; import {QueryClientProvider} from '@tanstack/react-query'; import {ReactNode, createContext, useContext} from 'react'; import queryClient from '../utils/queryClient'; -import RoutingProvider, {RoutingProviderProps} from './RoutingProvider'; +import {ExternalLink} from './RoutingProvider'; export interface FrameworkProviderProps { - basePath: string; ghostVersion: string; - externalNavigate: RoutingProviderProps['externalNavigate']; - modals?: RoutingProviderProps['modals']; + externalNavigate: (link: ExternalLink) => void; unsplashConfig: { Authorization: string; 'Accept-Version': string; @@ -24,13 +22,13 @@ export interface FrameworkProviderProps { children: ReactNode; } -// children, basePath and modals should be provided by each app, while others are passed in from Ember -export type TopLevelFrameworkProps = Omit; +export type TopLevelFrameworkProps = Omit; -export type FrameworkContextType = Omit; +export type FrameworkContextType = Omit; const FrameworkContext = createContext({ ghostVersion: '', + externalNavigate: () => {}, unsplashConfig: { Authorization: '', 'Accept-Version': '', @@ -44,14 +42,12 @@ const FrameworkContext = createContext({ onDelete: () => {} }); -function FrameworkProvider({externalNavigate, basePath, modals, children, ...props}: FrameworkProviderProps) { +function FrameworkProvider({children, ...props}: FrameworkProviderProps) { return ( - - {children} - + {children} diff --git a/apps/admin-x-framework/src/providers/RoutingProvider.tsx b/apps/admin-x-framework/src/providers/RoutingProvider.tsx index ff652dcdfe..9a9cd1b303 100644 --- a/apps/admin-x-framework/src/providers/RoutingProvider.tsx +++ b/apps/admin-x-framework/src/providers/RoutingProvider.tsx @@ -1,5 +1,6 @@ import NiceModal, {NiceModalHocProps} from '@ebay/nice-modal-react'; import React, {createContext, useCallback, useContext, useEffect, useState} from 'react'; +import {useFramework} from './FrameworkProvider'; export type RouteParams = Record @@ -92,12 +93,12 @@ const matchRoute = (pathname: string, routeDefinition: string) => { export interface RoutingProviderProps { basePath: string; - externalNavigate: (link: ExternalLink) => void; modals?: {paths: Record, load: () => Promise} children: React.ReactNode; } -const RoutingProvider: React.FC = ({basePath, externalNavigate, modals, children}) => { +const RoutingProvider: React.FC = ({basePath, modals, children}) => { + const {externalNavigate} = useFramework(); const [route, setRoute] = useState(undefined); const [loadingModal, setLoadingModal] = useState(false); const [eventTarget] = useState(new EventTarget()); diff --git a/apps/admin-x-framework/src/routing.ts b/apps/admin-x-framework/src/routing.ts index fdcf78e26e..44e35c28ec 100644 --- a/apps/admin-x-framework/src/routing.ts +++ b/apps/admin-x-framework/src/routing.ts @@ -1,3 +1,3 @@ -export {useRouteChangeCallback, useRouting} from './providers/RoutingProvider'; +export {default as RoutingProvider, useRouteChangeCallback, useRouting} from './providers/RoutingProvider'; export type {ExternalLink, InternalLink, ModalComponent, RoutingModalProps} from './providers/RoutingProvider'; diff --git a/apps/admin-x-settings/src/App.tsx b/apps/admin-x-settings/src/App.tsx index 1a7db264c9..c6590c9882 100644 --- a/apps/admin-x-settings/src/App.tsx +++ b/apps/admin-x-settings/src/App.tsx @@ -3,6 +3,7 @@ import SettingsAppProvider, {OfficialTheme, UpgradeStatusType} from './component import SettingsRouter, {loadModals, modalPaths} from './components/providers/SettingsRouter'; import {DesignSystemApp, DesignSystemAppProps} from '@tryghost/admin-x-design-system'; import {FrameworkProvider, TopLevelFrameworkProps} from '@tryghost/admin-x-framework'; +import {RoutingProvider} from '@tryghost/admin-x-framework/routing'; import {ZapierTemplate} from './components/settings/advanced/integrations/ZapierModal'; interface AppProps { @@ -15,12 +16,14 @@ interface AppProps { function App({framework, designSystem, officialThemes, zapierTemplates, upgradeStatus}: AppProps) { return ( - + - - - - + + + + + + ); diff --git a/apps/admin-x-settings/test/acceptance/routing.test.ts b/apps/admin-x-settings/test/acceptance/routing.test.ts new file mode 100644 index 0000000000..fe680c5849 --- /dev/null +++ b/apps/admin-x-settings/test/acceptance/routing.test.ts @@ -0,0 +1,23 @@ +import {expect, test} from '@playwright/test'; +import {globalDataRequests, mockApi} from '../utils/acceptance'; + +test.describe('Routing', async () => { + test('Reopens the opened modal when refreshing the page', async ({page}) => { + await mockApi({page, requests: globalDataRequests}); + + await page.goto('/'); + + const section = page.getByTestId('portal'); + await section.getByRole('button', {name: 'Customize'}).click(); + + await page.waitForSelector('[data-testid="portal-modal"]'); + + expect(page.url()).toMatch(/\/portal\/edit$/); + + await page.reload(); + + await page.waitForSelector('[data-testid="portal-modal"]'); + + expect(page.url()).toMatch(/\/portal\/edit$/); + }); +});