diff --git a/packages/compass-web/src/entrypoint.tsx b/packages/compass-web/src/entrypoint.tsx index 076b5de17f2..8d73b0fa617 100644 --- a/packages/compass-web/src/entrypoint.tsx +++ b/packages/compass-web/src/entrypoint.tsx @@ -183,7 +183,9 @@ const WithStorageProviders = createServiceProvider( type CompassWorkspaceProps = Pick< React.ComponentProps, - 'initialWorkspaceTabs' | 'onActiveWorkspaceTabChange' + | 'initialWorkspaceTabs' + | 'onActiveWorkspaceTabChange' + | 'onBeforeUnloadCallbackRequest' > & Pick< React.ComponentProps, @@ -226,17 +228,18 @@ export type CompassWebProps = { * `initialAutoconnectId` */ initialWorkspace?: OpenWorkspaceOptions; + /** * Callback prop called when current active workspace changes. Can be used to * communicate current workspace back to the parent component for example to * sync router with the current active workspace */ - onActiveWorkspaceTabChange( + onActiveWorkspaceTabChange: ( ws: WS | null, collectionInfo: WS extends { type: 'Collection' } ? CollectionTabInfo | null : never - ): void; + ) => void; /** * Set of initial preferences to override default values @@ -268,12 +271,20 @@ export type CompassWebProps = { * Callback prop called when connections fail to load */ onFailToLoadConnections: (err: Error) => void; + + /** + * Callback that will get passed another callback function that, when called, + * would return back true or false depending on whether or not tabs can be + * safely closed without losing any important unsaved changes + */ + onBeforeUnloadCallbackRequest?: (canCloseCallback: () => boolean) => void; }; function CompassWorkspace({ initialWorkspaceTabs, onActiveWorkspaceTabChange, onOpenConnectViaModal, + onBeforeUnloadCallbackRequest, }: CompassWorkspaceProps) { return ( { const appRegistry = useRef(new AppRegistry()); const logger = useCompassWebLogger({ @@ -548,6 +561,9 @@ const CompassWeb = ({ onOpenConnectViaModal={ onOpenConnectViaModal } + onBeforeUnloadCallbackRequest={ + onBeforeUnloadCallbackRequest + } > diff --git a/packages/compass-workspaces/src/components/index.tsx b/packages/compass-workspaces/src/components/index.tsx index 59bb70e02b3..12c0a5f856b 100644 --- a/packages/compass-workspaces/src/components/index.tsx +++ b/packages/compass-workspaces/src/components/index.tsx @@ -27,12 +27,12 @@ type WorkspacesWithSidebarProps = { * @param ws current active workspace * @param collectionInfo active workspaces collection info */ - onActiveWorkspaceTabChange( + onActiveWorkspaceTabChange: ( ws: WS | null, collectionInfo: WS extends { type: 'Collection' } ? CollectionTabInfo | null : never - ): void; + ) => void; /** * Initial workspace tab to show (by default no tabs will be shown initially) */ @@ -54,6 +54,12 @@ type WorkspacesWithSidebarProps = { * actions from service locator context */ renderModals?: () => React.ReactElement | null; + /** + * Callback that will get passed another callback function that, when called, + * would return back true or false depending on whether or not tabs can be + * safely closed without losing any important unsaved changes + */ + onBeforeUnloadCallbackRequest?: (canCloseCallback: () => boolean) => void; }; const containerLightThemeStyles = css({ diff --git a/packages/compass-workspaces/src/index.ts b/packages/compass-workspaces/src/index.ts index b0126401b9e..6a3dccbd716 100644 --- a/packages/compass-workspaces/src/index.ts +++ b/packages/compass-workspaces/src/index.ts @@ -16,6 +16,7 @@ import workspacesReducer, { connectionDisconnected, updateDatabaseInfo, updateCollectionInfo, + beforeUnloading, } from './stores/workspaces'; import Workspaces from './components'; import { applyMiddleware, createStore } from 'redux'; @@ -75,7 +76,11 @@ export function configureStore( export function activateWorkspacePlugin( { initialWorkspaceTabs, - }: { initialWorkspaceTabs?: OpenWorkspaceOptions[] | null }, + onBeforeUnloadCallbackRequest, + }: { + initialWorkspaceTabs?: OpenWorkspaceOptions[] | null; + onBeforeUnloadCallbackRequest?: (canCloseCallback: () => boolean) => void; + }, { globalAppRegistry, instancesManager, @@ -203,20 +208,9 @@ export function activateWorkspacePlugin( } }); - // TODO(COMPASS-8033): activate this code and account for it in e2e tests and - // electron environment - // function onBeforeUnload(evt: BeforeUnloadEvent) { - // const canUnload = store.getState().tabs.every((tab) => { - // return canCloseTab(tab); - // }); - // if (!canUnload) { - // evt.preventDefault(); - // } - // } - // window.addEventListener('beforeunload', onBeforeUnload); - // addCleanup(() => { - // window.removeEventListener('beforeunload', onBeforeUnload); - // }); + onBeforeUnloadCallbackRequest?.(() => { + return store.dispatch(beforeUnloading()); + }); return { store, diff --git a/packages/compass-workspaces/src/stores/workspaces.ts b/packages/compass-workspaces/src/stores/workspaces.ts index 3219cb8ed43..6367f9f2c34 100644 --- a/packages/compass-workspaces/src/stores/workspaces.ts +++ b/packages/compass-workspaces/src/stores/workspaces.ts @@ -1045,4 +1045,12 @@ export const openFallbackWorkspace = ( }; }; +export const beforeUnloading = (): WorkspacesThunkAction => { + return (_dispatch, getState) => { + return getState().tabs.every((tab) => { + return canCloseTab(tab); + }); + }; +}; + export default reducer;