Skip to content

Commit 5a27582

Browse files
feat(databases-collections-list): adds refresh CTA on database and collection list view - COMPASS-6431 (#4122)
1 parent a8732fd commit 5a27582

File tree

12 files changed

+130
-10
lines changed

12 files changed

+130
-10
lines changed

packages/compass-app-stores/src/stores/instance-store.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,32 @@ store.onActivated = (appRegistry) => {
243243
store.refreshInstance(appRegistry);
244244
});
245245

246+
// Event emitted when the Databases grid needs to be refreshed
247+
// We additionally refresh the list of collections as well
248+
// since there is the side navigation which could be in expanded mode
249+
appRegistry.on('refresh-databases', async() => {
250+
const { instance, dataService } = store.getState();
251+
await instance.fetchDatabases({ dataService, force: true });
252+
await Promise.allSettled(
253+
instance.databases.map((db) => db.fetchCollections({ dataService, force: true }))
254+
);
255+
});
256+
257+
// Event emitted when the Collections grid needs to be refreshed
258+
// with new collections or collection info for existing ones.
259+
appRegistry.on('refresh-collections', async({ ns }) => {
260+
const { instance, dataService } = store.getState();
261+
const { database } = toNS(ns);
262+
if (!instance.databases.get(database)) {
263+
await instance.fetchDatabases({ dataService, force: true });
264+
}
265+
266+
const db = instance.databases.get(database);
267+
if (db) {
268+
await db.fetchCollections({ dataService, fetchInfo: true, force: true });
269+
}
270+
});
271+
246272
appRegistry.on('agg-pipeline-out-executed', () => {
247273
store.refreshInstance(appRegistry);
248274
});

packages/compass-e2e-tests/helpers/selectors.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export const SidebarActionClusterInfo =
227227
export const SidebarCreateDatabaseButton =
228228
'[data-testid="sidebar-navigation-item-actions-open-create-database-action"]';
229229
export const SidebarRefreshDatabasesButton =
230-
'[data-testid="sidebar-navigation-item-actions-refresh-data-action"]';
230+
'[data-testid="sidebar-navigation-item-actions-refresh-databases-action"]';
231231
export const CollectionShowActionsButton =
232232
'[data-testid="sidebar-collection-item-actions-show-actions"]';
233233
export const DropDatabaseButton = '[data-action="drop-database"]';
@@ -378,6 +378,8 @@ export const InstanceTab = '.test-tab-nav-bar-tab';
378378
export const DatabasesTable = '[data-testid="database-grid"]';
379379
export const InstanceCreateDatabaseButton =
380380
'[data-testid="database-grid"] [data-testid="create-controls"] button';
381+
export const InstanceRefreshDatabaseButton =
382+
'[data-testid="database-grid"] [data-testid="refresh-controls"] button';
381383
export const DatabaseCard = '[data-testid="database-grid-item"]';
382384
// assume that there's only one hovered card at a time and that the first and only button is the drop button
383385
export const DatabaseCardDrop =
@@ -413,6 +415,8 @@ export const DatabaseTab = '.test-tab-nav-bar-tab';
413415
export const CollectionsGrid = '[data-testid="collection-grid"]';
414416
export const DatabaseCreateCollectionButton =
415417
'[data-testid="collection-grid"] [data-testid="create-controls"] button';
418+
export const DatabaseRefreshCollectionButton =
419+
'[data-testid="collection-grid"] [data-testid="refresh-controls"] button';
416420
export const CollectionCard = '[data-testid="collection-grid-item"]';
417421
// assume that there's only one hovered card at a time and that the first and only button is the drop button
418422
export const CollectionCardDrop =

packages/compass-e2e-tests/tests/database-collections-tab.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,23 @@ describe('Database collections tab', function () {
336336
await typeElement.waitForDisplayed();
337337
expect(await typeElement.getText()).to.equal('CLUSTERED');
338338
});
339+
340+
it('can refresh the list of collections using refresh controls', async function () {
341+
const db = `test`;
342+
const coll = `zcoll-${Date.now()}`;
343+
// Create the collection and refresh
344+
await browser.shellEval(`use ${db};`);
345+
await browser.shellEval(`db.createCollection('${coll}');`);
346+
await browser.navigateToDatabaseTab(db, 'Collections');
347+
await browser.clickVisible(Selectors.DatabaseRefreshCollectionButton);
348+
349+
const collSelector = Selectors.collectionCard(db, coll);
350+
await browser.scrollToVirtualItem(
351+
Selectors.CollectionsGrid,
352+
collSelector,
353+
'grid'
354+
);
355+
const coll2Card = await browser.$(collSelector);
356+
await coll2Card.waitForDisplayed();
357+
});
339358
});

packages/compass-e2e-tests/tests/instance-databases-tab.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,28 @@ describe('Instance databases tab', function () {
133133
const tabSelectedSelector = Selectors.instanceTab('Databases', true);
134134
await browser.$(tabSelectedSelector).waitForDisplayed();
135135
});
136+
137+
it('can refresh the list of databases using refresh controls', async function () {
138+
const db = 'my-instance-database';
139+
const coll = 'my-collection';
140+
// Create the database and refresh
141+
await browser.shellEval(`use ${db};`);
142+
await browser.shellEval(`db.createCollection('${coll}');`);
143+
await browser.navigateToInstanceTab('Databases');
144+
await browser.clickVisible(Selectors.InstanceRefreshDatabaseButton);
145+
146+
const dbSelector = Selectors.databaseCard(db);
147+
await browser.scrollToVirtualItem(
148+
Selectors.DatabasesTable,
149+
dbSelector,
150+
'grid'
151+
);
152+
const dbCard = await browser.$(dbSelector);
153+
await dbCard.waitForDisplayed();
154+
155+
// Drop it and refresh again
156+
await browser.shellEval(`db.dropDatabase();`);
157+
await browser.clickVisible(Selectors.InstanceRefreshDatabaseButton);
158+
await dbCard.waitForExist({ reverse: true });
159+
});
136160
});

packages/compass-sidebar/src/components/navigation-items.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import SidebarDatabasesNavigation from './sidebar-databases-navigation';
2020

2121
import { changeFilterRegex } from '../modules/databases';
2222

23-
type DatabasesActions = 'open-create-database' | 'refresh-data';
23+
type DatabasesActions = 'open-create-database' | 'refresh-databases';
2424

2525
const navigationItem = css({
2626
cursor: 'pointer',
@@ -190,7 +190,7 @@ export function NavigationItems({
190190
const databasesActions = useMemo(() => {
191191
const actions: ItemAction<DatabasesActions>[] = [
192192
{
193-
action: 'refresh-data',
193+
action: 'refresh-databases',
194194
label: 'Refresh databases',
195195
icon: 'Refresh',
196196
},

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,14 @@ const CollectionsList: React.FunctionComponent<{
8181
onCollectionClick(id: string): void;
8282
onDeleteCollectionClick?: (id: string) => void;
8383
onCreateCollectionClick?: () => void;
84+
onRefreshClick?: () => void;
8485
}> = ({
8586
isEditable,
8687
collections,
8788
onCollectionClick,
8889
onCreateCollectionClick,
8990
onDeleteCollectionClick,
91+
onRefreshClick,
9092
}) => {
9193
return (
9294
<ItemsGrid
@@ -107,6 +109,7 @@ const CollectionsList: React.FunctionComponent<{
107109
onItemClick={onCollectionClick}
108110
onDeleteItemClick={onDeleteCollectionClick}
109111
onCreateItemClick={onCreateCollectionClick}
112+
onRefreshClick={onRefreshClick}
110113
renderItem={({
111114
item: coll,
112115
onItemClick,

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ const DatabasesList: React.FunctionComponent<{
2727
onDatabaseClick(id: string): void;
2828
onDeleteDatabaseClick?: (id: string) => void;
2929
onCreateDatabaseClick?: () => void;
30+
onRefreshClick?: () => void;
3031
}> = ({
3132
isEditable,
3233
databases,
3334
onDatabaseClick,
3435
onCreateDatabaseClick,
3536
onDeleteDatabaseClick,
37+
onRefreshClick,
3638
}) => {
3739
return (
3840
<ItemsGrid
@@ -51,6 +53,7 @@ const DatabasesList: React.FunctionComponent<{
5153
onItemClick={onDatabaseClick}
5254
onDeleteItemClick={onDeleteDatabaseClick}
5355
onCreateItemClick={onCreateDatabaseClick}
56+
onRefreshClick={onRefreshClick}
5457
renderItem={({
5558
item: db,
5659
onItemClick,

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { NamespaceItemCardProps } from './namespace-card';
1313
import { useViewTypeControls } from './use-view-type';
1414
import type { ViewType } from './use-view-type';
1515
import { useCreateControls } from './use-create';
16+
import { useRefreshControls } from './use-refresh';
1617

1718
const { track } = createLoggerAndTelemetry(
1819
'COMPASS-DATABASES-COLLECTIONS-LIST-UI'
@@ -43,7 +44,7 @@ const container = css({
4344
const controls = css({
4445
display: 'flex',
4546
padding: spacing[3],
46-
gap: spacing[3],
47+
gap: spacing[2],
4748
flex: 'none',
4849
});
4950

@@ -86,6 +87,7 @@ type ItemsGridProps<T> = {
8687
onItemClick(id: string): void;
8788
onDeleteItemClick?: (id: string) => void;
8889
onCreateItemClick?: () => void;
90+
onRefreshClick?: () => void;
8991
renderItem: RenderItem<T>;
9092
};
9193

@@ -102,16 +104,18 @@ const pushRight = css({
102104
// part of the list header and scroll up when the list is scrolled
103105
const ControlsContext = React.createContext<{
104106
createControls: React.ReactElement | null;
107+
refreshControls: React.ReactElement | null;
105108
viewTypeControls: React.ReactElement | null;
106109
sortControls: React.ReactElement | null;
107110
}>({
108111
createControls: null,
112+
refreshControls: null,
109113
viewTypeControls: null,
110114
sortControls: null,
111115
});
112116

113117
const GridControls = () => {
114-
const { createControls, viewTypeControls, sortControls } =
118+
const { createControls, refreshControls, viewTypeControls, sortControls } =
115119
useContext(ControlsContext);
116120

117121
return (
@@ -121,8 +125,13 @@ const GridControls = () => {
121125
{createControls}
122126
</div>
123127
)}
124-
<div className={control}>{viewTypeControls}</div>
125-
<div className={cx(control, pushRight)}>{sortControls}</div>
128+
{refreshControls && (
129+
<div className={control} data-testid="refresh-controls">
130+
{refreshControls}
131+
</div>
132+
)}
133+
<div className={cx(control, pushRight)}>{viewTypeControls}</div>
134+
<div className={control}>{sortControls}</div>
126135
</>
127136
);
128137
};
@@ -139,6 +148,7 @@ export const ItemsGrid = <T extends Item>({
139148
onItemClick,
140149
onDeleteItemClick,
141150
onCreateItemClick,
151+
onRefreshClick,
142152
renderItem: _renderItem,
143153
}: ItemsGridProps<T>): React.ReactElement => {
144154
const onViewTypeChange = useCallback(
@@ -152,6 +162,7 @@ export const ItemsGrid = <T extends Item>({
152162
itemType,
153163
onCreateItemClick
154164
);
165+
const refreshControls = useRefreshControls(onRefreshClick);
155166
const [sortControls, sortState] = useSortControls(sortBy);
156167
const [viewTypeControls, viewType] = useViewTypeControls({
157168
onChange: onViewTypeChange,
@@ -182,6 +193,7 @@ export const ItemsGrid = <T extends Item>({
182193
<ControlsContext.Provider
183194
value={{
184195
createControls,
196+
refreshControls,
185197
sortControls: shouldShowControls ? sortControls : null,
186198
viewTypeControls: shouldShowControls ? viewTypeControls : null,
187199
}}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { Button } from '@mongodb-js/compass-components';
2+
import { Button, Icon } from '@mongodb-js/compass-components';
33
import { createButton } from './items-grid';
44

55
export type ItemType = 'database' | 'collection';
@@ -16,6 +16,7 @@ export function useCreateControls(
1616
return (
1717
<Button
1818
variant="primary"
19+
leftGlyph={<Icon role="presentation" glyph="Plus" />}
1920
onClick={() => {
2021
onCreateClick();
2122
}}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import { Button, Icon } from '@mongodb-js/compass-components';
3+
4+
export function useRefreshControls(
5+
onRefreshClick?: () => void
6+
): React.ReactElement | null {
7+
if (!onRefreshClick) {
8+
return null;
9+
}
10+
11+
return (
12+
<Button
13+
variant="primaryOutline"
14+
leftGlyph={<Icon role="presentation" glyph="Refresh" />}
15+
onClick={() => {
16+
onRefreshClick();
17+
}}
18+
>
19+
Refresh
20+
</Button>
21+
);
22+
}

0 commit comments

Comments
 (0)