Skip to content

Commit 3c42247

Browse files
committed
Merge branch 'gagik/context-menu-compass-ui' of github.com:mongodb-js/compass into gagik/collection-tab
2 parents 0236593 + 4ad7231 commit 3c42247

File tree

48 files changed

+930
-489
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+930
-489
lines changed
File renamed without changes.

THIRD-PARTY-NOTICES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
The following third-party software is used by and included in **Mongodb Compass**.
2-
This document was automatically generated on Tue Jun 17 2025.
2+
This document was automatically generated on Wed Jun 18 2025.
33

44
## List of dependencies
55

docs/tracking-plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
> the tracking plan for the specific Compass version you can use the following
77
> URL: `https://github.com/mongodb-js/compass/blob/<compass version>/docs/tracking-plan.md`
88
9-
Generated on Tue, Jun 17, 2025
9+
Generated on Wed, Jun 18, 2025
1010

1111
## Table of Contents
1212

packages/compass-aggregations/src/components/stage-preview/stage-preview-header.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import React from 'react';
22
import { connect } from 'react-redux';
3-
import { Body, Link, Tooltip, css } from '@mongodb-js/compass-components';
3+
import { Body, Link, Tooltip } from '@mongodb-js/compass-components';
44
import type { RootState } from '../../modules';
55
import { getStageInfo } from '../../utils/stage';
66
import type { StoreStage } from '../../modules/pipeline-builder/stage-editor';
77

8-
const toolbarTextStyles = css({
9-
whiteSpace: 'nowrap',
10-
overflow: 'hidden',
11-
textOverflow: 'ellipsis',
12-
});
13-
148
const OperatorLink: React.FunctionComponent<{
159
stageOperator: string;
1610
description?: string;
@@ -56,7 +50,7 @@ function StagePreviewHeader({
5650
return null;
5751
}
5852
return (
59-
<Body className={toolbarTextStyles}>
53+
<Body>
6054
{destination ? (
6155
`Documents will be saved to ${destination}.`
6256
) : (
Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from 'react';
12
import CollectionTab from './components/collection-tab';
23
import { activatePlugin as activateCollectionTabPlugin } from './stores/collection-tab';
34
import { registerHadronPlugin } from 'hadron-app-registry';
@@ -7,27 +8,32 @@ import {
78
type DataService,
89
} from '@mongodb-js/compass-connections/provider';
910
import { collectionModelLocator } from '@mongodb-js/compass-app-stores/provider';
10-
import type { WorkspaceComponent } from '@mongodb-js/compass-workspaces';
11+
import type { WorkspacePlugin } from '@mongodb-js/compass-workspaces';
1112
import { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provider';
13+
import {
14+
CollectionWorkspaceTitle,
15+
CollectionPluginTitleComponent,
16+
} from './plugin-tab-title';
1217

13-
export const CollectionTabPlugin = registerHadronPlugin(
14-
{
15-
name: 'CollectionTab',
16-
component: CollectionTab,
17-
activate: activateCollectionTabPlugin,
18-
},
19-
{
20-
dataService: dataServiceLocator as DataServiceLocator<keyof DataService>,
21-
collection: collectionModelLocator,
22-
workspaces: workspacesServiceLocator,
23-
}
24-
);
25-
26-
export const WorkspaceTab: WorkspaceComponent<'Collection'> = {
27-
name: 'Collection' as const,
28-
component: CollectionTabPlugin,
18+
export const WorkspaceTab: WorkspacePlugin<typeof CollectionWorkspaceTitle> = {
19+
name: CollectionWorkspaceTitle,
20+
provider: registerHadronPlugin(
21+
{
22+
name: CollectionWorkspaceTitle,
23+
component: function CollectionProvider({ children }) {
24+
return React.createElement(React.Fragment, null, children);
25+
},
26+
activate: activateCollectionTabPlugin,
27+
},
28+
{
29+
dataService: dataServiceLocator as DataServiceLocator<keyof DataService>,
30+
collection: collectionModelLocator,
31+
workspaces: workspacesServiceLocator,
32+
}
33+
),
34+
content: CollectionTab,
35+
header: CollectionPluginTitleComponent,
2936
};
3037

31-
export default CollectionTabPlugin;
3238
export type { CollectionTabPluginMetadata } from './modules/collection-tab';
3339
export { CollectionTabsProvider } from './components/collection-tab-provider';
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import React from 'react';
2+
import { connect } from 'react-redux';
3+
import toNS from 'mongodb-ns';
4+
import {
5+
useConnectionInfo,
6+
useConnectionsListRef,
7+
useTabConnectionTheme,
8+
} from '@mongodb-js/compass-connections/provider';
9+
import {
10+
WorkspaceTab,
11+
type WorkspaceTabCoreProps,
12+
} from '@mongodb-js/compass-components';
13+
import type { WorkspacePluginProps } from '@mongodb-js/compass-workspaces';
14+
15+
import { type CollectionState } from './modules/collection-tab';
16+
17+
export const CollectionWorkspaceTitle = 'Collection' as const;
18+
19+
type PluginTitleProps = {
20+
isTimeSeries?: boolean;
21+
isReadonly?: boolean;
22+
sourceName?: string | null;
23+
} & WorkspaceTabCoreProps &
24+
WorkspacePluginProps<typeof CollectionWorkspaceTitle>;
25+
26+
function _PluginTitle({
27+
editViewName,
28+
isNonExistent,
29+
isReadonly,
30+
isTimeSeries,
31+
sourceName,
32+
namespace,
33+
...tabProps
34+
}: PluginTitleProps) {
35+
const { getThemeOf } = useTabConnectionTheme();
36+
const { getConnectionById } = useConnectionsListRef();
37+
const { id: connectionId } = useConnectionInfo();
38+
39+
const { database, collection, ns } = toNS(namespace);
40+
const connectionName = getConnectionById(connectionId)?.title || '';
41+
const collectionType = isTimeSeries
42+
? 'timeseries'
43+
: isReadonly
44+
? 'view'
45+
: 'collection';
46+
// Similar to what we have in the collection breadcrumbs.
47+
const tooltip: [string, string][] = [
48+
['Connection', connectionName || ''],
49+
['Database', database],
50+
];
51+
if (sourceName) {
52+
tooltip.push(['View', collection]);
53+
tooltip.push(['Derived from', toNS(sourceName).collection]);
54+
} else if (editViewName) {
55+
tooltip.push(['View', toNS(editViewName).collection]);
56+
tooltip.push(['Derived from', collection]);
57+
} else {
58+
tooltip.push(['Collection', collection]);
59+
}
60+
61+
return (
62+
<WorkspaceTab
63+
{...tabProps}
64+
connectionName={connectionName}
65+
type={CollectionWorkspaceTitle}
66+
title={collection}
67+
tooltip={tooltip}
68+
iconGlyph={
69+
collectionType === 'view'
70+
? 'Visibility'
71+
: collectionType === 'timeseries'
72+
? 'TimeSeries'
73+
: isNonExistent
74+
? 'EmptyFolder'
75+
: 'Folder'
76+
}
77+
data-namespace={ns}
78+
tabTheme={getThemeOf(connectionId)}
79+
isNonExistent={isNonExistent}
80+
/>
81+
);
82+
}
83+
84+
export const CollectionPluginTitleComponent = connect(
85+
(state: CollectionState) => ({
86+
isTimeSeries: state.metadata?.isTimeSeries,
87+
isReadonly: state.metadata?.isReadonly,
88+
sourceName: state.metadata?.sourceName,
89+
})
90+
)(_PluginTitle);

packages/compass-components/src/components/workspace-tabs/tab.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { spacing } from '@leafygreen-ui/tokens';
55
import type { GlyphName } from '@leafygreen-ui/icon';
66
import { useSortable } from '@dnd-kit/sortable';
77
import { CSS as cssDndKit } from '@dnd-kit/utilities';
8+
import { useId } from '@react-aria/utils';
89
import { useDarkMode } from '../../hooks/use-theme';
910
import { Icon, IconButton } from '../leafygreen';
1011
import { mergeProps } from '../../utils/merge-props';
@@ -149,6 +150,10 @@ const draggingTabStyles = css({
149150
cursor: 'grabbing !important',
150151
});
151152

153+
const nonExistentStyles = css({
154+
color: palette.gray.base,
155+
});
156+
152157
const tabIconStyles = css({
153158
color: 'currentColor',
154159
marginLeft: spacing[300],
@@ -185,25 +190,34 @@ const workspaceTabTooltipStyles = css({
185190
textWrap: 'wrap',
186191
});
187192

188-
type TabProps = {
193+
// The plugins provide these essential props use to render the tab.
194+
// The workspace-tabs component provides the other parts of TabProps.
195+
export type WorkspaceTabPluginProps = {
189196
connectionName?: string;
190197
type: string;
191-
title: string;
198+
title: React.ReactNode;
199+
isNonExistent?: boolean;
200+
iconGlyph: GlyphName | 'Logo' | 'Server';
201+
tooltip?: [string, string][];
202+
tabTheme?: Partial<TabTheme>;
203+
};
204+
205+
export type WorkspaceTabCoreProps = {
192206
isSelected: boolean;
193207
isDragging: boolean;
194208
onSelect: () => void;
195209
onClose: () => void;
196-
iconGlyph: GlyphName | 'Logo' | 'Server';
197210
tabContentId: string;
198-
tooltip?: [string, string][];
199-
tabTheme?: Partial<TabTheme>;
200211
};
201212

213+
type TabProps = WorkspaceTabCoreProps & WorkspaceTabPluginProps;
214+
202215
function Tab({
203216
connectionName,
204217
type,
205218
title,
206219
tooltip,
220+
isNonExistent,
207221
isSelected,
208222
isDragging,
209223
onSelect,
@@ -213,7 +227,7 @@ function Tab({
213227
tabTheme,
214228
className: tabClassName,
215229
...props
216-
}: TabProps & React.HTMLProps<HTMLDivElement>) {
230+
}: TabProps & Omit<React.HTMLProps<HTMLDivElement>, 'title'>) {
217231
const darkMode = useDarkMode();
218232
const defaultActionProps = useDefaultAction(onSelect);
219233
const { listeners, setNodeRef, transform, transition } = useSortable({
@@ -240,6 +254,8 @@ function Tab({
240254
cursor: 'grabbing !important',
241255
};
242256

257+
const tabId = useId();
258+
243259
return (
244260
<Tooltip
245261
enabled={!!tooltip}
@@ -254,6 +270,7 @@ function Tab({
254270
className={cx(
255271
tabStyles,
256272
themeClass,
273+
isNonExistent && nonExistentStyles,
257274
isSelected && selectedTabStyles,
258275
isSelected && tabTheme && selectedThemedTabStyles,
259276
isDragging && draggingTabStyles,
@@ -267,6 +284,7 @@ function Tab({
267284
data-testid="workspace-tab-button"
268285
data-connection-name={connectionName}
269286
data-type={type}
287+
id={tabId}
270288
{...tabProps}
271289
>
272290
{iconGlyph === 'Logo' && (

packages/compass-components/src/components/workspace-tabs/workspace-tabs.spec.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,23 @@ import { expect } from 'chai';
99
import sinon from 'sinon';
1010

1111
import { WorkspaceTabs } from './workspace-tabs';
12-
import type { TabProps } from './workspace-tabs';
12+
import { Tab, type WorkspaceTabCoreProps } from './tab';
1313

14-
function mockTab(tabId: number): TabProps {
14+
function mockTab(tabId: number): {
15+
id: string;
16+
renderTab: (tabProps: WorkspaceTabCoreProps) => ReturnType<typeof Tab>;
17+
} {
1518
return {
16-
type: 'Documents',
17-
title: `mock-tab-${tabId}`,
1819
id: `${tabId}-content`,
19-
iconGlyph: 'Folder',
20+
renderTab: (tabProps: WorkspaceTabCoreProps) => (
21+
<Tab
22+
{...tabProps}
23+
type="Documents"
24+
title={`mock-tab-${tabId}`}
25+
id={`${tabId}-content`}
26+
iconGlyph="Folder"
27+
/>
28+
),
2029
};
2130
}
2231

0 commit comments

Comments
 (0)