Skip to content

Commit

Permalink
fix: new duplicate connection behaviour for MC (COMPASS-8069) (#6008)
Browse files Browse the repository at this point in the history
  • Loading branch information
paula-stacho authored Jul 10, 2024
1 parent d0c2366 commit 5c7c95f
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function Connections({
cancelConnectionAttempt,
connect,
createNewConnection,
duplicateConnection,
legacyDuplicateConnection: duplicateConnection,
setActiveConnectionById,
removeAllRecentsConnections,
removeConnection,
Expand Down
64 changes: 49 additions & 15 deletions packages/compass-connections/src/stores/connections-store.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -574,13 +574,8 @@ describe('use-connections hook', function () {
});
});

describe('#duplicateConnection', function () {
let hookResult: RenderResult<ReturnType<typeof useConnections>>;

it('should duplicate a connection', async function () {
const loadAllSpy = sinon.spy(mockConnectionStorage, 'loadAll');
const saveSpy = sinon.spy(mockConnectionStorage, 'save');

describe('createDuplicateConnection', function () {
it('should create a connection duplicate and set it as the new active connection', async function () {
const { result } = renderHookWithContext(() =>
useConnections({
onConnected: noop,
Expand All @@ -592,19 +587,58 @@ describe('use-connections hook', function () {
expect(result.current.favoriteConnections.length).to.equal(2);
});

result.current.setActiveConnectionById('turtle');
result.current.duplicateConnection(result.current.favoriteConnections[0]);
const original = result.current.favoriteConnections[0];
result.current.createDuplicateConnection(original);

const duplicate = result.current.state.activeConnectionInfo;

expect(duplicate).to.haveOwnProperty('id');
expect(duplicate.id).not.to.equal(original.id);
expect(result.current.state.activeConnectionId).to.equal(duplicate.id);
delete original.id;
delete duplicate.id;
expect(duplicate).to.deep.equal({
...original,
favorite: {
...original.favorite,
name: `${original.favorite.name} (1)`,
},
});
});

it('should increment (number) appendix', async function () {
mockConnectionStorage = new InMemoryConnectionStorage([
mockConnections[0],
{
...mockConnections[0],
favorite: {
...mockConnections[0].favorite,
name: `${mockConnections[0].favorite.name} (1)`,
},
},
]);
const { result } = renderHookWithContext(() =>
useConnections({
onConnected: noop,
onConnectionFailed: noop,
onConnectionAttemptStarted: noop,
})
);
await waitFor(() => {
expect(loadAllSpy).to.have.been.called;
expect(saveSpy.callCount).to.equal(1);
expect(result.current.favoriteConnections.length).to.equal(2);
});

hookResult = result;
});
const original = result.current.favoriteConnections[0]; // copying the original
result.current.createDuplicateConnection(original);
const duplicate = result.current.state.activeConnectionInfo;
expect(duplicate.favorite.name).to.equal(`${original.favorite.name} (2)`);

it('should set the duplicated connection as current active', function () {
expect(hookResult.current.state.activeConnectionId).to.not.equal(null);
const copy = result.current.favoriteConnections[1]; // copying the copy
result.current.createDuplicateConnection(copy);
const duplicate2 = result.current.state.activeConnectionInfo;
expect(duplicate2.favorite.name).to.equal(
`${original.favorite.name} (2)`
);
});
});

Expand Down
43 changes: 40 additions & 3 deletions packages/compass-connections/src/stores/connections-store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,11 @@ export function useConnections({
connect: (connectionInfo: ConnectionInfo) => Promise<void>;
closeConnection: (connectionId: ConnectionInfo['id']) => Promise<void>;
createNewConnection: () => void;
createDuplicateConnection: (connectionInfo: ConnectionInfo) => void;
saveConnection: (connectionInfo: ConnectionInfo) => Promise<void>;
setActiveConnectionById: (newConnectionId: string) => void;
removeAllRecentsConnections: () => Promise<void>;
duplicateConnection: (connectionInfo: ConnectionInfo) => void;
legacyDuplicateConnection: (connectionInfo: ConnectionInfo) => void;
removeConnection: (connectionInfo: ConnectionInfo) => void;
} {
// TODO(COMPASS-7397): services should not be used directly in render method,
Expand Down Expand Up @@ -519,14 +520,24 @@ export function useConnections({
removeConnection(connectionInfo) {
void removeConnection(connectionInfo);
},
duplicateConnection(connectionInfo: ConnectionInfo) {
legacyDuplicateConnection(connectionInfo: ConnectionInfo) {
const findConnectionByFavoriteName = (name: string) =>
[...favoriteConnections, ...recentConnections].find(
(connection: ConnectionInfo) => connection.favorite?.name === name
);
const duplicate: ConnectionInfo = {
...cloneDeep(connectionInfo),
id: new UUID().toString(),
};

if (duplicate.favorite?.name) {
duplicate.favorite.name += ' (copy)';
const copyFormat = duplicate.favorite?.name.match(/(.*)\s\(([0-9])+\)/); // title (2) -> [title (2), title, 2]
const name = copyFormat ? copyFormat[1] : duplicate.favorite?.name;
let copyNumber = copyFormat ? parseInt(copyFormat[2]) : 1;
while (findConnectionByFavoriteName(`${name} (${copyNumber})`)) {
copyNumber++;
}
duplicate.favorite.name = `${name} (${copyNumber})`;
}

void saveConnectionInfo(duplicate).then(
Expand All @@ -541,6 +552,32 @@ export function useConnections({
}
);
},
createDuplicateConnection(connectionInfo: ConnectionInfo) {
const findConnectionByFavoriteName = (name: string) =>
[...favoriteConnections, ...recentConnections].find(
(connection: ConnectionInfo) => connection.favorite?.name === name
);

const duplicate: ConnectionInfo = {
...cloneDeep(connectionInfo),
id: new UUID().toString(),
};

if (duplicate.favorite?.name) {
const copyFormat = duplicate.favorite?.name.match(/(.*)\s\(([0-9])+\)/); // title (2) -> [title (2), title, 2]
const name = copyFormat ? copyFormat[1] : duplicate.favorite?.name;
let copyNumber = copyFormat ? parseInt(copyFormat[2]) : 1;
while (findConnectionByFavoriteName(`${name} (${copyNumber})`)) {
copyNumber++;
}
duplicate.favorite.name = `${name} (${copyNumber})`;
}

dispatch({
type: 'new-connection',
connectionInfo: duplicate,
});
},
async removeAllRecentsConnections() {
await Promise.all(
recentConnections.map((info) => deleteConnection(info))
Expand Down
6 changes: 3 additions & 3 deletions packages/compass-e2e-tests/tests/connection-form.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,14 +706,14 @@ describe('Connection form', function () {
Sidebar.DuplicateConnectionItem
);

// duplicating immediately opens the modal so you can edit it
// duplicating opens the modal, in multiple connections you have to save
if (TEST_MULTIPLE_CONNECTIONS) {
await browser.clickVisible(Selectors.ConnectionModalCloseButton);
await browser.clickVisible(Selectors.ConnectionModalSaveButton);
}

// delete the duplicate
await browser.selectConnectionMenuItem(
`${favoriteName} (copy)`,
`${favoriteName} (1)`,
Sidebar.RemoveConnectionItem
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function andSucceed(): PromiseFunction {
const savedFavoriteConnection: ConnectionInfo = {
id: '12345',
connectionOptions: {
connectionString: 'mongodb://localhost:27017',
connectionString: 'mongodb://localhost:12345/',
},
favorite: {
name: 'localhost',
Expand All @@ -75,7 +75,7 @@ const savedFavoriteConnection: ConnectionInfo = {
const savedRecentConnection: ConnectionInfo = {
id: '54321',
connectionOptions: {
connectionString: 'mongodb://localhost:27020',
connectionString: 'mongodb://localhost:27020/',
},
};

Expand Down Expand Up @@ -693,7 +693,7 @@ describe('Multiple Connections Sidebar Component', function () {
});
});

it('should duplicate connection when clicked on duplicate action', async function () {
it('should open a connection form when clicked on duplicate action', async function () {
const saveSpy = sinon.spy(connectionStorage, 'save');

const connectionItem = screen.getByTestId(
Expand All @@ -709,16 +709,18 @@ describe('Multiple Connections Sidebar Component', function () {

userEvent.click(screen.getByText('Duplicate'));

// Does not save the duplicate yet
await waitFor(() => {
expect(saveSpy).to.have.been.called;
expect(saveSpy).not.to.have.been.called;
});

await waitFor(() => {
// 3 connections and one database from the connected one
return expect(screen.getAllByRole('treeitem')).to.have.lengthOf(
4
);
});
// We see the connect button in the form modal
expect(screen.getByTestId('connect-button')).to.be.visible;

// Connection string is pre-filled with a duplicate
expect(screen.getByTestId('connectionString')).to.have.value(
savedFavoriteConnection.connectionOptions.connectionString
);
});

it('should disconnect and remove the connection when clicked on remove action', async function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ export function MultipleConnectionSidebar({
cancelConnectionAttempt,
removeConnection,
saveConnection,
duplicateConnection,
createNewConnection,
createDuplicateConnection,
state: { activeConnectionId, activeConnectionInfo, connectionErrorMessage },
} = useConnections();

Expand Down Expand Up @@ -394,10 +394,10 @@ export function MultipleConnectionSidebar({

const onDuplicateConnection = useCallback(
(info: ConnectionInfo) => {
duplicateConnection(info);
createDuplicateConnection(info);
setIsConnectionFormOpen(true);
},
[duplicateConnection, setIsConnectionFormOpen]
[setIsConnectionFormOpen, createDuplicateConnection]
);

const onToggleFavoriteConnectionInfo = useCallback(
Expand Down

0 comments on commit 5c7c95f

Please sign in to comment.