diff --git a/packages/compass-workspaces/src/components/workspace-tab-context-provider.tsx b/packages/compass-workspaces/src/components/workspace-tab-context-provider.tsx
new file mode 100644
index 00000000000..6a3a1d8dade
--- /dev/null
+++ b/packages/compass-workspaces/src/components/workspace-tab-context-provider.tsx
@@ -0,0 +1,138 @@
+import React, { useCallback, useEffect, useRef } from 'react';
+import {
+ getLocalAppRegistryForTab,
+ type WorkspaceTab,
+} from '../stores/workspaces';
+import { NamespaceProvider } from '@mongodb-js/compass-app-stores/provider';
+import { ConnectionInfoProvider } from '@mongodb-js/compass-connections/provider';
+import { rafraf } from '@mongodb-js/compass-components';
+import { useOnTabReplace } from './workspace-close-handler';
+import {
+ useTabState,
+ WorkspaceTabStateProvider,
+} from './workspace-tab-state-provider';
+import { AppRegistryProvider } from 'hadron-app-registry';
+
+function getInitialPropsForWorkspace(tab: WorkspaceTab) {
+ switch (tab.type) {
+ case 'Welcome':
+ case 'My Queries':
+ case 'Data Modeling':
+ case 'Performance':
+ case 'Databases':
+ return null;
+ case 'Shell':
+ return {
+ initialEvaluate: tab.initialEvaluate,
+ initialInput: tab.initialInput,
+ };
+ case 'Collections':
+ return { namespace: tab.namespace };
+ case 'Collection': {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { id, type, connectionId, ...collectionMetadata } = tab;
+ return { tabId: id, ...collectionMetadata };
+ }
+ }
+}
+
+const TabCloseHandler: React.FunctionComponent = ({ children }) => {
+ const mountedRef = useRef(false);
+ const [hasInteractedOnce, setHasInteractedOnce] = useTabState(
+ 'hasInteractedOnce',
+ false
+ );
+
+ useEffect(() => {
+ mountedRef.current = true;
+ return () => {
+ mountedRef.current = false;
+ };
+ });
+
+ const markAsInteracted = useCallback(() => {
+ // Make sure we don't count clicking on buttons that actually cause the
+ // workspace to change, like using breadcrumbs or clicking on an item in the
+ // Databases / Collections list. There are certain corner-cases this doesn't
+ // handle, but it's good enough to prevent most cases where users can lose
+ // content by accident
+ rafraf(() => {
+ if (mountedRef.current) {
+ setHasInteractedOnce(true);
+ }
+ });
+ }, [setHasInteractedOnce]);
+
+ useOnTabReplace(() => {
+ return !hasInteractedOnce;
+ });
+
+ return (
+ // We're not using these for actual user interactions, just to capture the
+ // interacted state
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions
+
+ {children}
+
+ );
+};
+
+const WorkspaceTabContextProvider: React.FunctionComponent<{
+ tab: WorkspaceTab;
+ sectionType: 'tab-content' | 'tab-title';
+ onNamespaceNotFound?: (
+ tab: Extract,
+ fallbackNamespace: string | null
+ ) => void;
+ children: React.JSX.Element;
+}> = ({ tab, onNamespaceNotFound, sectionType: type, children }) => {
+ const initialProps = getInitialPropsForWorkspace(tab);
+
+ if (initialProps) {
+ children = React.cloneElement(children, initialProps);
+ }
+
+ if ('namespace' in tab) {
+ children = (
+ {
+ onNamespaceNotFound?.(tab, ns);
+ }}
+ >
+ {children}
+
+ );
+ }
+
+ if ('connectionId' in tab) {
+ children = (
+
+ {children}
+
+ );
+ }
+
+ if (type === 'tab-content') {
+ children = {children};
+ }
+
+ return (
+
+
+ {children}
+
+
+ );
+};
+
+export { WorkspaceTabContextProvider };
diff --git a/packages/compass-workspaces/src/components/workspaces-provider.tsx b/packages/compass-workspaces/src/components/workspaces-provider.tsx
index 38b3236bad4..7063bf06f65 100644
--- a/packages/compass-workspaces/src/components/workspaces-provider.tsx
+++ b/packages/compass-workspaces/src/components/workspaces-provider.tsx
@@ -30,7 +30,10 @@ export const useWorkspacePlugins = () => {
hasWorkspacePlugin: (name: T) => {
return workspaces.some((ws) => ws.name === name);
},
- getWorkspacePluginByName: (name: T) => {
+ getWorkspacePluginByName: (name?: T) => {
+ if (!name) {
+ return null;
+ }
const plugin = workspaces.find((ws) => ws.name === name);
if (!plugin) {
throw new Error(
diff --git a/packages/compass-workspaces/src/components/workspaces.tsx b/packages/compass-workspaces/src/components/workspaces.tsx
index b894b0fb6e0..ad873735703 100644
--- a/packages/compass-workspaces/src/components/workspaces.tsx
+++ b/packages/compass-workspaces/src/components/workspaces.tsx
@@ -1,12 +1,10 @@
-import React, { useCallback, useEffect, useMemo, useRef } from 'react';
-import { AppRegistryProvider } from 'hadron-app-registry';
+import React, { useCallback, useMemo } from 'react';
import {
ErrorBoundary,
MongoDBLogoMark,
WorkspaceTabs,
css,
palette,
- rafraf,
spacing,
useDarkMode,
} from '@mongodb-js/compass-components';
@@ -20,7 +18,6 @@ import type {
import {
closeTab,
getActiveTab,
- getLocalAppRegistryForTab,
moveTab,
openFallbackWorkspace,
openTabFromCurrent,
@@ -32,17 +29,9 @@ import { useWorkspacePlugins } from './workspaces-provider';
import toNS from 'mongodb-ns';
import { useLogger } from '@mongodb-js/compass-logging/provider';
import { connect } from '../stores/context';
-import {
- WorkspaceTabStateProvider,
- useTabState,
-} from './workspace-tab-state-provider';
-import { useOnTabReplace } from './workspace-close-handler';
-import { NamespaceProvider } from '@mongodb-js/compass-app-stores/provider';
-import {
- ConnectionInfoProvider,
- useTabConnectionTheme,
-} from '@mongodb-js/compass-connections/provider';
+import { useTabConnectionTheme } from '@mongodb-js/compass-connections/provider';
import { useConnectionsListRef } from '@mongodb-js/compass-connections/provider';
+import { WorkspaceTabContextProvider } from './workspace-tab-context-provider';
type Tooltip = [string, string][];
@@ -64,51 +53,6 @@ const EmptyWorkspaceContent = () => {
);
};
-const ActiveTabCloseHandler: React.FunctionComponent = ({ children }) => {
- const mountedRef = useRef(false);
- const [hasInteractedOnce, setHasInteractedOnce] = useTabState(
- 'hasInteractedOnce',
- false
- );
-
- useEffect(() => {
- mountedRef.current = true;
- return () => {
- mountedRef.current = false;
- };
- });
-
- const markAsInteracted = useCallback(() => {
- // Make sure we don't count clicking on buttons that actually cause the
- // workspace to change, like using breadcrumbs or clicking on an item in the
- // Databases / Collections list. There are certain corner-cases this doesn't
- // handle, but it's good enough to prevent most cases where users can lose
- // content by accident
- rafraf(() => {
- if (mountedRef.current) {
- setHasInteractedOnce(true);
- }
- });
- }, [setHasInteractedOnce]);
-
- useOnTabReplace(() => {
- return !hasInteractedOnce;
- });
-
- return (
- // We're not using these for actual user interactions, just to capture the
- // interacted state
- // eslint-disable-next-line jsx-a11y/no-static-element-interactions
-
- {children}
-
- );
-};
-
const workspacesContainerStyles = css({
display: 'grid',
width: '100%',
@@ -309,71 +253,7 @@ const CompassWorkspaces: React.FunctionComponent = ({
}, [tabs, collectionInfo, databaseInfo, getThemeOf, getConnectionById]);
const activeTabIndex = tabs.findIndex((tab) => tab === activeTab);
-
- const activeWorkspaceElement = useMemo(() => {
- switch (activeTab?.type) {
- case 'Welcome':
- case 'My Queries':
- case 'Data Modeling': {
- const Component = getWorkspacePluginByName(activeTab.type);
- return ;
- }
- case 'Shell': {
- const Component = getWorkspacePluginByName(activeTab.type);
- return (
-
-
-
- );
- }
- case 'Performance':
- case 'Databases': {
- const Component = getWorkspacePluginByName(activeTab.type);
- return (
-
-
-
- );
- }
- case 'Collections': {
- const Component = getWorkspacePluginByName(activeTab.type);
- return (
-
- {
- onNamespaceNotFound(activeTab, ns);
- }}
- >
-
-
-
- );
- }
- case 'Collection': {
- const Component = getWorkspacePluginByName(activeTab.type);
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const { id, type, connectionId, ...collectionMetadata } = activeTab;
- return (
-
- {
- onNamespaceNotFound(activeTab, ns);
- }}
- >
-
-
-
- );
- }
- default:
- return null;
- }
- }, [activeTab, getWorkspacePluginByName, onNamespaceNotFound]);
+ const WorkspaceComponent = getWorkspacePluginByName(activeTab?.type);
const onCreateNewTab = useCallback(() => {
onCreateTab(openOnEmptyWorkspace);
@@ -397,31 +277,26 @@ const CompassWorkspaces: React.FunctionComponent = ({
>
- {activeTab && activeWorkspaceElement ? (
-
- {
+ log.error(
+ mongoLogId(1_001_000_277),
+ 'Workspace',
+ 'Rendering workspace tab failed',
+ { name: activeTab.type, error: error.message, errorInfo }
+ );
+ }}
+ >
+
-
- {
- log.error(
- mongoLogId(1_001_000_277),
- 'Workspace',
- 'Rendering workspace tab failed',
- { name: activeTab.type, error: error.message, errorInfo }
- );
- }}
- >
- {activeWorkspaceElement}
-
-
-
-
+
+
+
) : (
)}