Skip to content

Commit 1656146

Browse files
chore(databases-collections): add UI for rename collection warning COMPASS-7664 (#5458)
1 parent 982347f commit 1656146

File tree

10 files changed

+209
-143
lines changed

10 files changed

+209
-143
lines changed

package-lock.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/compass-e2e-tests/tests/collection-rename.test.ts

Lines changed: 0 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import type { CompassBrowser } from '../helpers/compass-browser';
1111
import { createBlankCollection, dropDatabase } from '../helpers/insert-data';
1212
import * as Selectors from '../helpers/selectors';
1313

14-
import { setTimeout } from 'timers/promises';
15-
import { saveAggregationPipeline } from '../helpers/commands/save-aggregation-pipeline';
1614
import { setFeature } from '../helpers/commands';
1715
const initialName = 'numbers';
1816
const newName = 'renamed';
@@ -276,128 +274,4 @@ describe('Collection Rename Modal', () => {
276274
expect(await modal.collectionNameInput.getValue()).to.equal(initialName);
277275
});
278276
});
279-
280-
describe('saved aggregations', () => {
281-
beforeEach(
282-
'navigate to aggregations tab and save pipeline on test collection',
283-
async () => {
284-
// Some tests navigate away from the numbers collection aggregations tab
285-
await browser.navigateToCollectionTab(
286-
'rename-collection',
287-
'numbers',
288-
'Aggregations'
289-
);
290-
// Get us back to the empty stage every time. Also test the Create New
291-
// Pipeline flow while at it.
292-
await browser.clickVisible(Selectors.CreateNewPipelineButton);
293-
294-
await browser.clickVisible(Selectors.AddStageButton);
295-
await browser.$(Selectors.stageEditor(0)).waitForDisplayed();
296-
// sanity check to make sure there's only one stage
297-
const stageContainers = await browser.$$(Selectors.StageCard);
298-
expect(stageContainers).to.have.lengthOf(1);
299-
300-
await saveAggregationPipeline(browser, 'my-aggregation', [
301-
{ $match: `{ name: 'john' }` },
302-
]);
303-
}
304-
);
305-
306-
// functionality not implemented and tests failing
307-
it.skip('preserves a saved aggregation for a namespace when a collection is renamed', async () => {
308-
// open the rename collection modal
309-
await browser.hover(
310-
Selectors.sidebarCollection(databaseName, initialName)
311-
);
312-
await browser.clickVisible(Selectors.CollectionShowActionsButton);
313-
await browser.clickVisible(Selectors.RenameCollectionButton);
314-
await renameCollectionSuccessFlow(browser, newName);
315-
316-
// confirm the saved aggregation is still present for the newly renamed namespace
317-
await browser.navigateToCollectionTab(
318-
'rename-collection',
319-
newName,
320-
'Aggregations'
321-
);
322-
323-
await browser.waitForAnimations(
324-
Selectors.AggregationOpenSavedPipelinesButton
325-
);
326-
await browser.clickVisible(Selectors.AggregationOpenSavedPipelinesButton);
327-
await browser.waitForAnimations(
328-
Selectors.AggregationSavedPipelinesPopover
329-
);
330-
await browser
331-
.$(Selectors.AggregationSavedPipelineCard('my-aggregation'))
332-
.waitForDisplayed();
333-
});
334-
});
335-
336-
describe('saved queries', () => {
337-
beforeEach('navigate to documents tab and save a query', async () => {
338-
// set guide cue to not show up
339-
await browser.execute((key) => {
340-
localStorage.setItem(key, 'true');
341-
}, 'has_seen_stage_wizard_guide_cue');
342-
343-
const favoriteQueryName = 'list of numbers greater than 10 - query';
344-
345-
// Run a query
346-
await browser.navigateToCollectionTab(
347-
'rename-collection',
348-
'numbers',
349-
'Documents'
350-
);
351-
352-
await browser.runFindOperation('Documents', `{i: {$gt: 10}}`, {
353-
limit: '10',
354-
});
355-
await browser.clickVisible(Selectors.QueryBarHistoryButton);
356-
357-
// Wait for the popover to show
358-
const history = await browser.$(Selectors.QueryBarHistory);
359-
await history.waitForDisplayed();
360-
361-
// wait for the recent item to show.
362-
const recentCard = await browser.$(Selectors.QueryHistoryRecentItem);
363-
await recentCard.waitForDisplayed();
364-
365-
// Save the ran query
366-
await browser.hover(Selectors.QueryHistoryRecentItem);
367-
await browser.clickVisible(Selectors.QueryHistoryFavoriteAnItemButton);
368-
await browser.setValueVisible(
369-
Selectors.QueryHistoryFavoriteItemNameField,
370-
favoriteQueryName
371-
);
372-
await browser.clickVisible(Selectors.QueryHistorySaveFavoriteItemButton);
373-
});
374-
375-
// functionality not implemented and tests failing
376-
it.skip('preserves a saved query for a namespace when a collection is renamed', async () => {
377-
// open the rename collection modal
378-
await browser.hover(
379-
Selectors.sidebarCollection(databaseName, initialName)
380-
);
381-
await browser.clickVisible(Selectors.CollectionShowActionsButton);
382-
await browser.clickVisible(Selectors.RenameCollectionButton);
383-
await renameCollectionSuccessFlow(browser, newName);
384-
await browser.navigateToCollectionTab(
385-
'rename-collection',
386-
newName,
387-
'Documents'
388-
);
389-
390-
await browser.clickVisible(Selectors.QueryBarHistoryButton);
391-
392-
// Wait for the popover to show
393-
const history = await browser.$(Selectors.QueryBarHistory);
394-
await history.waitForDisplayed();
395-
396-
await browser.clickVisible(Selectors.QueryHistoryFavoritesButton);
397-
398-
await browser.$(Selectors.QueryHistoryFavoriteItem).waitForDisplayed();
399-
400-
await setTimeout(3000);
401-
});
402-
});
403277
});

packages/databases-collections/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"@mongodb-js/compass-logging": "^1.2.12",
5454
"@mongodb-js/compass-workspaces": "^0.4.4",
5555
"@mongodb-js/databases-collections-list": "^1.22.4",
56+
"@mongodb-js/my-queries-storage": "^0.4.3",
5657
"compass-preferences-model": "^2.17.4",
5758
"hadron-app-registry": "^9.1.6",
5859
"mongodb-data-service": "^22.17.4",
@@ -94,6 +95,7 @@
9495
"@mongodb-js/compass-logging": "^1.2.12",
9596
"@mongodb-js/compass-workspaces": "^0.4.4",
9697
"@mongodb-js/databases-collections-list": "^1.22.4",
98+
"@mongodb-js/my-queries-storage": "^0.4.3",
9799
"compass-preferences-model": "^2.17.4",
98100
"hadron-app-registry": "^9.1.6",
99101
"mongodb-data-service": "^22.17.4"

packages/databases-collections/src/components/rename-collection-modal/rename-collection-modal.spec.tsx

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import React from 'react';
22
import Sinon from 'sinon';
33
import { expect } from 'chai';
4-
import { render, screen, cleanup, fireEvent } from '@testing-library/react';
4+
import {
5+
render,
6+
screen,
7+
cleanup,
8+
fireEvent,
9+
waitFor,
10+
} from '@testing-library/react';
511

612
import { RenameCollectionPlugin } from '../..';
713
import AppRegistry from 'hadron-app-registry';
814

9-
describe('CreateCollectionModal [Component]', function () {
15+
describe('RenameCollectionModal [Component]', function () {
1016
const sandbox = Sinon.createSandbox();
1117
const appRegistry = sandbox.spy(new AppRegistry());
1218
const dataService = {
@@ -21,18 +27,30 @@ describe('CreateCollectionModal [Component]', function () {
2127
},
2228
},
2329
};
30+
const favoriteQueries = {
31+
getStorage: () => ({
32+
loadAll: sandbox.stub().resolves([]),
33+
}),
34+
};
35+
const pipelineStorage = {
36+
loadAll: sandbox.stub().resolves([]),
37+
};
2438
context('when the modal is visible', function () {
25-
beforeEach(function () {
39+
beforeEach(async function () {
2640
const Plugin = RenameCollectionPlugin.withMockServices({
2741
globalAppRegistry: appRegistry,
2842
dataService,
2943
instance: instanceModel as any,
44+
queryStorage: favoriteQueries as any,
45+
pipelineStorage: pipelineStorage as any,
3046
});
3147
render(<Plugin> </Plugin>);
3248
appRegistry.emit('open-rename-collection', {
3349
database: 'foo',
3450
collection: 'bar',
3551
});
52+
53+
await waitFor(() => screen.getByText('Rename collection'));
3654
});
3755

3856
afterEach(function () {
@@ -109,6 +127,62 @@ describe('CreateCollectionModal [Component]', function () {
109127
const submitButton = screen.getByTestId('submit-button');
110128
expect(submitButton.textContent).to.equal('Yes, rename collection');
111129
});
130+
131+
it('displays the "unsaved queries / aggregations" may be lost warning', function () {
132+
const renameCollectionWarningBanner = screen.getByTestId(
133+
'rename-collection-modal-warning'
134+
);
135+
expect(renameCollectionWarningBanner.textContent).to.include(
136+
'Renaming collection will result in loss of any unsaved queries, filters or aggregation pipeline.'
137+
);
138+
});
139+
140+
describe('when the user has no saved aggregations or queries for the old namespace', function () {
141+
it('does not display the saved queries and aggregations warning', () => {
142+
const renameCollectionWarningBanner = screen.getByTestId(
143+
'rename-collection-modal-warning'
144+
);
145+
expect(renameCollectionWarningBanner.textContent).not.to.include(
146+
'Additionally, any saved queries or aggregations targeting this collection will need to be remapped to the new namespace.'
147+
);
148+
});
149+
});
150+
151+
describe('when the user has saved aggregations or queries for the old namespace', function () {
152+
beforeEach(async function () {
153+
cleanup();
154+
pipelineStorage.loadAll.resolves([{ namespace: 'foo.bar' }]);
155+
const Plugin = RenameCollectionPlugin.withMockServices({
156+
globalAppRegistry: appRegistry,
157+
dataService,
158+
instance: instanceModel as any,
159+
queryStorage: favoriteQueries as any,
160+
pipelineStorage: pipelineStorage as any,
161+
});
162+
render(<Plugin> </Plugin>);
163+
appRegistry.emit('open-rename-collection', {
164+
database: 'foo',
165+
collection: 'bar',
166+
});
167+
168+
await waitFor(() => screen.getByText('Rename collection'));
169+
170+
const submitButton = screen.getByTestId('submit-button');
171+
const input = screen.getByTestId('rename-collection-name-input');
172+
fireEvent.change(input, { target: { value: 'baz' } });
173+
fireEvent.click(submitButton);
174+
175+
expect(screen.getByTestId('rename-collection-modal')).to.exist;
176+
});
177+
it('does not display the saved queries and aggregations warning', () => {
178+
const renameCollectionWarningBanner = screen.getByTestId(
179+
'rename-collection-modal-warning'
180+
);
181+
expect(renameCollectionWarningBanner.textContent).to.include(
182+
'Additionally, any saved queries or aggregations targeting this collection will need to be remapped to the new namespace.'
183+
);
184+
});
185+
});
112186
});
113187
});
114188
});

packages/databases-collections/src/components/rename-collection-modal/rename-collection-modal.tsx

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface RenameCollectionModalProps {
2424
initialCollectionName: string;
2525
collections: { name: string }[];
2626
isRunning: boolean;
27+
areSavedQueriesAndAggregationsImpacted: boolean;
2728
hideModal: () => void;
2829
renameCollection: (newCollectionName: string) => void;
2930
clearError: () => void;
@@ -37,11 +38,42 @@ const progressContainerStyles = css({
3738

3839
type ModalState = 'input-form' | 'confirmation-screen';
3940

41+
const bannerTextStyles = css({
42+
marginTop: 0,
43+
marginBottom: 0,
44+
'&:not(:last-child)': {
45+
marginBottom: spacing[2],
46+
},
47+
});
48+
function ConfirmationModalContent({
49+
areSavedQueriesAndAggregationsImpacted,
50+
}: {
51+
areSavedQueriesAndAggregationsImpacted: boolean;
52+
}) {
53+
return (
54+
<Banner variant="warning" data-testid="rename-collection-modal-warning">
55+
<p className={bannerTextStyles}>
56+
Renaming collection will result in loss of any unsaved queries, filters
57+
or aggregation pipeline.
58+
</p>
59+
{areSavedQueriesAndAggregationsImpacted && (
60+
<p className={bannerTextStyles}>
61+
<b>
62+
Additionally, any saved queries or aggregations targeting this
63+
collection will need to be remapped to the new namespace.
64+
</b>
65+
</p>
66+
)}
67+
</Banner>
68+
);
69+
}
70+
4071
function RenameCollectionModal({
4172
isVisible,
4273
error,
4374
initialCollectionName,
4475
collections,
76+
areSavedQueriesAndAggregationsImpacted,
4577
isRunning,
4678
hideModal,
4779
renameCollection,
@@ -147,10 +179,11 @@ function RenameCollectionModal({
147179
</Banner>
148180
)}
149181
{modalState === 'confirmation-screen' && (
150-
<Banner variant="info" data-testid="rename-collection-modal-warning">
151-
Renaming collection will result in loss of any unsaved queries,
152-
filters or aggregation pipeline
153-
</Banner>
182+
<ConfirmationModalContent
183+
areSavedQueriesAndAggregationsImpacted={
184+
areSavedQueriesAndAggregationsImpacted
185+
}
186+
/>
154187
)}
155188
{isRunning && (
156189
<Body className={progressContainerStyles}>

packages/databases-collections/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import MappedRenameCollectionModal from './components/rename-collection-modal/re
1717
import { activateRenameCollectionPlugin } from './stores/rename-collection';
1818
import type { WorkspaceComponent } from '@mongodb-js/compass-workspaces';
1919
import { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provider';
20+
import {
21+
favoriteQueryStorageAccessLocator,
22+
pipelineStorageLocator,
23+
} from '@mongodb-js/my-queries-storage/provider';
2024

2125
export const CollectionsWorkspaceTab: WorkspaceComponent<'Collections'> = {
2226
name: 'Collections' as const,
@@ -68,5 +72,7 @@ export const RenameCollectionPlugin = registerHadronPlugin(
6872
dataService:
6973
dataServiceLocator as typeof dataServiceLocator<'renameCollection'>,
7074
instance: mongoDBInstanceLocator,
75+
queryStorage: favoriteQueryStorageAccessLocator,
76+
pipelineStorage: pipelineStorageLocator,
7177
}
7278
);

0 commit comments

Comments
 (0)