Skip to content

Commit 1ad5118

Browse files
authored
chore: add connection name to breadcrumbs COMPASS-7684 (#5730)
* chore: add connection title * chore: fix tests * chore: fix package.json * chore: add missing breadcrumbs * chore: add test to new breadcrumb behaviour * chore: add missing dep * chore: fix package.json
1 parent bfc0471 commit 1ad5118

File tree

7 files changed

+170
-82
lines changed

7 files changed

+170
-82
lines changed

packages/compass-collection/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@mongodb-js/compass-app-stores": "^7.11.0",
5252
"@mongodb-js/compass-components": "^1.23.0",
5353
"@mongodb-js/compass-connections": "^1.26.0",
54+
"@mongodb-js/connection-info": "^0.2.0",
5455
"@mongodb-js/compass-logging": "^1.2.15",
5556
"@mongodb-js/compass-workspaces": "^0.6.0",
5657
"compass-preferences-model": "^2.19.0",

packages/compass-collection/src/components/collection-header/collection-header.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ describe('CollectionHeader [Component]', function () {
188188
crumbs.push(item.textContent);
189189
});
190190
expect(crumbs.filter(Boolean).join('.').toLowerCase()).to.equal(
191-
items.join('.').toLowerCase()
191+
`localhost:27020.${items.join('.').toLowerCase()}`
192192
);
193193
}
194194

packages/compass-collection/src/components/collection-header/collection-header.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { CollectionBadge } from './badges';
1919
import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider';
2020
import { connect } from 'react-redux';
2121
import { useConnectionInfo } from '@mongodb-js/compass-connections/provider';
22+
import { getConnectionTitle } from '@mongodb-js/connection-info';
2223

2324
const collectionHeaderStyles = css({
2425
padding: spacing[3],
@@ -98,13 +99,21 @@ export const CollectionHeader: React.FunctionComponent<
9899
}) => {
99100
const darkMode = useDarkMode();
100101
const showInsights = usePreference('showInsights');
101-
const { openCollectionWorkspace, openCollectionsWorkspace } =
102-
useOpenWorkspace();
103-
const { id: connectionId } = useConnectionInfo();
102+
const {
103+
openCollectionWorkspace,
104+
openCollectionsWorkspace,
105+
openDatabasesWorkspace,
106+
} = useOpenWorkspace();
107+
const connectionInfo = useConnectionInfo();
108+
const connectionId = connectionInfo.id;
109+
const connectionName = getConnectionTitle(connectionInfo);
104110

105111
const breadcrumbItems = useMemo(() => {
106112
return [
107-
// TODO (COMPASS-7684): add connection name
113+
{
114+
name: connectionName,
115+
onClick: () => openDatabasesWorkspace(connectionId),
116+
},
108117
{
109118
name: toNS(namespace).database,
110119
onClick: () =>
@@ -128,11 +137,13 @@ export const CollectionHeader: React.FunctionComponent<
128137
].filter(Boolean) as BreadcrumbItem[];
129138
}, [
130139
connectionId,
140+
connectionName,
131141
namespace,
132142
sourceName,
133143
editViewName,
134144
openCollectionsWorkspace,
135145
openCollectionWorkspace,
146+
openDatabasesWorkspace,
136147
]);
137148

138149
const insights =

packages/databases-collections-list/src/collections.tsx

Lines changed: 119 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
/* eslint-disable react/prop-types */
2-
import React from 'react';
3-
import { spacing } from '@mongodb-js/compass-components';
2+
import React, { useMemo } from 'react';
3+
import {
4+
type BreadcrumbItem,
5+
Breadcrumbs,
6+
css,
7+
spacing,
8+
} from '@mongodb-js/compass-components';
49
import { compactBytes, compactNumber } from './format';
510
import type { BadgeProp } from './namespace-card';
611
import { NamespaceItemCard } from './namespace-card';
@@ -74,97 +79,136 @@ function collectionPropertyToBadge({
7479
}
7580
}
7681

82+
const pageContainerStyles = css({
83+
height: 'auto',
84+
width: '100%',
85+
display: 'flex',
86+
flexDirection: 'column',
87+
});
88+
89+
const breadcrumbStyles = css({
90+
paddingLeft: spacing[3],
91+
paddingTop: spacing[3],
92+
paddingBottom: spacing[2],
93+
});
94+
7795
const CollectionsList: React.FunctionComponent<{
7896
connectionId: string;
97+
connectionTitle: string;
98+
databaseName: string;
7999
collections: Collection[];
80100
onCollectionClick(id: string): void;
101+
onClickConnectionBreadcrumb(connectionId: string): void;
81102
onDeleteCollectionClick?: (connectionId: string, id: string) => void;
82103
onCreateCollectionClick?: () => void;
83104
onRefreshClick?: () => void;
84105
}> = ({
85106
connectionId,
107+
connectionTitle,
108+
databaseName,
86109
collections,
110+
onClickConnectionBreadcrumb,
87111
onCollectionClick,
88112
onCreateCollectionClick,
89113
onDeleteCollectionClick,
90114
onRefreshClick,
91115
}) => {
116+
const breadcrumbItems = useMemo(() => {
117+
return [
118+
{
119+
name: connectionTitle,
120+
onClick: () => onClickConnectionBreadcrumb(connectionId),
121+
},
122+
{
123+
name: databaseName,
124+
},
125+
] as BreadcrumbItem[];
126+
}, [
127+
connectionId,
128+
connectionTitle,
129+
databaseName,
130+
onClickConnectionBreadcrumb,
131+
]);
132+
92133
return (
93-
<ItemsGrid
94-
items={collections}
95-
itemType="collection"
96-
itemGridWidth={COLLECTION_CARD_WIDTH}
97-
itemGridHeight={COLLECTION_CARD_HEIGHT}
98-
itemListHeight={COLLECTION_CARD_LIST_HEIGHT}
99-
sortBy={[
100-
{ name: 'name', label: 'Collection Name' },
101-
{ name: 'document_count', label: 'Documents' },
102-
{ name: 'avg_document_size', label: 'Avg. document size' },
103-
{ name: 'storage_size', label: 'Storage size' },
104-
{ name: 'index_count', label: 'Indexes' },
105-
{ name: 'index_size', label: 'Total index size' },
106-
]}
107-
onItemClick={onCollectionClick}
108-
onDeleteItemClick={(ns) => onDeleteCollectionClick?.(connectionId, ns)}
109-
onCreateItemClick={onCreateCollectionClick}
110-
onRefreshClick={onRefreshClick}
111-
renderItem={({
112-
item: coll,
113-
onItemClick,
114-
onDeleteItemClick,
115-
...props
116-
}) => {
117-
const data =
118-
coll.type === 'view'
119-
? [{ label: 'View on', value: coll.source?.name }]
120-
: [
121-
{
122-
label: 'Storage size',
123-
value: compactBytes(
124-
coll.storage_size - coll.free_storage_size
125-
),
126-
hint: `Uncompressed data size: ${compactBytes(
127-
coll.document_size
128-
)}`,
129-
},
130-
{
131-
label: 'Documents',
132-
value: compactNumber(coll.document_count),
133-
},
134-
{
135-
label: 'Avg. document size',
136-
value: compactBytes(coll.avg_document_size),
137-
},
138-
{
139-
label: 'Indexes',
140-
value: compactNumber(coll.index_count),
141-
},
142-
{
143-
label: 'Total index size',
144-
value: compactBytes(coll.index_size),
145-
},
146-
];
134+
<div className={pageContainerStyles}>
135+
<Breadcrumbs className={breadcrumbStyles} items={breadcrumbItems} />
136+
<ItemsGrid
137+
items={collections}
138+
itemType="collection"
139+
itemGridWidth={COLLECTION_CARD_WIDTH}
140+
itemGridHeight={COLLECTION_CARD_HEIGHT}
141+
itemListHeight={COLLECTION_CARD_LIST_HEIGHT}
142+
sortBy={[
143+
{ name: 'name', label: 'Collection Name' },
144+
{ name: 'document_count', label: 'Documents' },
145+
{ name: 'avg_document_size', label: 'Avg. document size' },
146+
{ name: 'storage_size', label: 'Storage size' },
147+
{ name: 'index_count', label: 'Indexes' },
148+
{ name: 'index_size', label: 'Total index size' },
149+
]}
150+
onItemClick={onCollectionClick}
151+
onDeleteItemClick={(ns) => onDeleteCollectionClick?.(connectionId, ns)}
152+
onCreateItemClick={onCreateCollectionClick}
153+
onRefreshClick={onRefreshClick}
154+
renderItem={({
155+
item: coll,
156+
onItemClick,
157+
onDeleteItemClick,
158+
...props
159+
}) => {
160+
const data =
161+
coll.type === 'view'
162+
? [{ label: 'View on', value: coll.source?.name }]
163+
: [
164+
{
165+
label: 'Storage size',
166+
value: compactBytes(
167+
coll.storage_size - coll.free_storage_size
168+
),
169+
hint: `Uncompressed data size: ${compactBytes(
170+
coll.document_size
171+
)}`,
172+
},
173+
{
174+
label: 'Documents',
175+
value: compactNumber(coll.document_count),
176+
},
177+
{
178+
label: 'Avg. document size',
179+
value: compactBytes(coll.avg_document_size),
180+
},
181+
{
182+
label: 'Indexes',
183+
value: compactNumber(coll.index_count),
184+
},
185+
{
186+
label: 'Total index size',
187+
value: compactBytes(coll.index_size),
188+
},
189+
];
147190

148-
const badges = coll.properties.map((prop) => {
149-
return collectionPropertyToBadge(prop);
150-
});
191+
const badges = coll.properties.map((prop) => {
192+
return collectionPropertyToBadge(prop);
193+
});
151194

152-
return (
153-
<NamespaceItemCard
154-
id={coll._id}
155-
key={coll._id}
156-
name={coll.name}
157-
type="collection"
158-
status={coll.status}
159-
data={data}
160-
badges={badges}
161-
onItemClick={onItemClick}
162-
onItemDeleteClick={onDeleteItemClick}
163-
{...props}
164-
></NamespaceItemCard>
165-
);
166-
}}
167-
></ItemsGrid>
195+
return (
196+
<NamespaceItemCard
197+
id={coll._id}
198+
key={coll._id}
199+
name={coll.name}
200+
type="collection"
201+
status={coll.status}
202+
data={data}
203+
badges={badges}
204+
onItemClick={onItemClick}
205+
onItemDeleteClick={onDeleteItemClick}
206+
{...props}
207+
></NamespaceItemCard>
208+
);
209+
}}
210+
></ItemsGrid>
211+
</div>
168212
);
169213
};
170214

packages/databases-collections-list/src/index.spec.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ describe('databases and collections list', function () {
8282

8383
render(
8484
<CollectionsList
85+
connectionTitle="My Connection"
86+
connectionId="1"
87+
databaseName="My Database"
8588
collections={colls}
8689
onCollectionClick={clickSpy}
8790
></CollectionsList>
@@ -99,5 +102,25 @@ describe('databases and collections list', function () {
99102

100103
expect(clickSpy).to.be.calledWith('bar.bar');
101104
});
105+
106+
it('should notify when the connection name is clicked', function () {
107+
const clickSpy = Sinon.spy();
108+
const connectionClickSpy = Sinon.spy();
109+
110+
render(
111+
<CollectionsList
112+
connectionTitle="My Connection"
113+
connectionId="1"
114+
databaseName="My Database"
115+
collections={colls}
116+
onClickConnectionBreadcrumb={connectionClickSpy}
117+
onCollectionClick={clickSpy}
118+
></CollectionsList>
119+
);
120+
121+
userEvent.click(screen.getByText('My Connection'));
122+
123+
expect(connectionClickSpy).to.be.calledWith('1');
124+
});
102125
});
103126
});

packages/databases-collections/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"@mongodb-js/compass-components": "^1.23.0",
6565
"@mongodb-js/compass-connections": "^1.26.0",
6666
"@mongodb-js/compass-editor": "^0.22.0",
67+
"@mongodb-js/connection-info": "^0.2.0",
6768
"@mongodb-js/compass-logging": "^1.2.15",
6869
"@mongodb-js/compass-workspaces": "^0.6.0",
6970
"@mongodb-js/databases-collections-list": "^1.24.0",

packages/databases-collections/src/components/collections.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type Collection from 'mongodb-collection-model';
1818
import toNS from 'mongodb-ns';
1919
import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider';
2020
import { useConnectionInfo } from '@mongodb-js/compass-connections/provider';
21+
import { getConnectionTitle } from '@mongodb-js/connection-info';
2122

2223
const ERROR_WARNING = 'An error occurred while loading collections';
2324

@@ -46,8 +47,12 @@ const Collections: React.FunctionComponent<CollectionsListProps> = ({
4647
onCreateCollectionClick: _onCreateCollectionClick,
4748
onRefreshClick,
4849
}) => {
49-
const { id: connectionId } = useConnectionInfo();
50-
const { openCollectionWorkspace } = useOpenWorkspace();
50+
const connectionInfo = useConnectionInfo();
51+
const { id: connectionId } = connectionInfo;
52+
const { openDatabasesWorkspace, openCollectionWorkspace } =
53+
useOpenWorkspace();
54+
55+
const parsedNS = toNS(namespace);
5156

5257
useTrackOnChange(
5358
'COMPASS-COLLECTIONS-UI',
@@ -85,6 +90,9 @@ const Collections: React.FunctionComponent<CollectionsListProps> = ({
8590
<CollectionsList
8691
connectionId={connectionId}
8792
collections={collections}
93+
connectionTitle={getConnectionTitle(connectionInfo)}
94+
databaseName={parsedNS.database}
95+
onClickConnectionBreadcrumb={openDatabasesWorkspace}
8896
{...actions}
8997
/>
9098
);

0 commit comments

Comments
 (0)