diff --git a/packages/compass-components/src/components/file-picker-dialog.spec.tsx b/packages/compass-components/src/components/file-picker-dialog.spec.tsx index 8a957895d89..02942842d19 100644 --- a/packages/compass-components/src/components/file-picker-dialog.spec.tsx +++ b/packages/compass-components/src/components/file-picker-dialog.spec.tsx @@ -565,6 +565,26 @@ describe('FileInput', function () { expect(listener).to.been.calledOnceWith([]); }); + it('calls the listener with an empty array if the dialog rejects', async function () { + const { fakeElectron, fakeWebUtils } = createFakeElectron(); + + const backend = createElectronFileInputBackend( + fakeElectron, + fakeWebUtils + )(); + const listener = sinon.stub(); + backend.onFilesChosen(listener); + + fakeElectron.dialog.showOpenDialog.rejects(new Error('dialog failed')); + backend.openFileChooser({ + mode: 'open', + multi: false, + }); + expect(listener).to.not.have.been.called; + await tick(); + expect(listener).to.been.calledOnceWith([]); + }); + it('handles autoOpen:true', async function () { const { fakeElectron, fakeWebUtils } = createFakeElectron(); const backend = createElectronFileInputBackend( diff --git a/packages/compass-components/src/components/file-picker-dialog.tsx b/packages/compass-components/src/components/file-picker-dialog.tsx index 1cefeeb7272..1753353acba 100644 --- a/packages/compass-components/src/components/file-picker-dialog.tsx +++ b/packages/compass-components/src/components/file-picker-dialog.tsx @@ -300,7 +300,7 @@ export function createElectronFileInputBackend( for (const listener of listeners) listener(files); }) .catch(() => { - /* ignore */ + for (const listener of listeners) listener([]); }); }, onFilesChosen(listener) { diff --git a/packages/compass-crud/src/stores/crud-store.ts b/packages/compass-crud/src/stores/crud-store.ts index 895f0e95350..ed67c138779 100644 --- a/packages/compass-crud/src/stores/crud-store.ts +++ b/packages/compass-crud/src/stores/crud-store.ts @@ -1266,10 +1266,12 @@ class CrudStoreImpl * Open an import file dialog from compass-import-export-plugin. * Emits a global app registry event the plugin listens to. */ - openImportFileDialog() { + openImportFileDialog( + origin: 'empty-state' | 'crud-toolbar' = 'empty-state' + ) { this.connectionScopedAppRegistry.emit('open-import', { namespace: this.state.ns, - origin: 'empty-state', + origin, }); } diff --git a/packages/compass-import-export/src/components/import-modal.tsx b/packages/compass-import-export/src/components/import-modal.tsx index 5321b28cc0d..e9f4d4db814 100644 --- a/packages/compass-import-export/src/components/import-modal.tsx +++ b/packages/compass-import-export/src/components/import-modal.tsx @@ -75,6 +75,7 @@ const dataTypesLinkStyles = css({ type ImportModalProps = { isOpen: boolean; + openId: number; ns: string; startImport: () => void; cancelImport: () => void; @@ -115,6 +116,7 @@ type ImportModalProps = { function ImportModal({ isOpen, + openId, ns, startImport, cancelImport, @@ -171,11 +173,12 @@ function ImportModal({ if (isOpen && !fileName && errors.length === 0) { // Show the file input when we don't have a file to import yet. + // Use openId as key to force remounting when import is re-opened, + // ensuring autoOpen triggers the file dialog each time. return ( - // Don't actually show it on the screen, just render it to trigger - // autoOpen
({ ns: state.import.namespace, isOpen: state.import.isOpen, + openId: state.import.openId, errors: state.import.firstErrors, fileType: state.import.fileType, fileName: state.import.fileName, diff --git a/packages/compass-import-export/src/modules/import.spec.ts b/packages/compass-import-export/src/modules/import.spec.ts index aca2d9d7a6f..b09aaadb4d3 100644 --- a/packages/compass-import-export/src/modules/import.spec.ts +++ b/packages/compass-import-export/src/modules/import.spec.ts @@ -1,6 +1,11 @@ import { expect } from 'chai'; import path from 'path'; -import { onStarted, openImport, selectImportFileName } from './import'; +import { + onStarted, + openImport, + selectImportFileName, + closeImport, +} from './import'; import type { ImportStore } from '../stores/import-store'; import { ImportPlugin } from '../index'; import { createPluginTestHelpers } from '@mongodb-js/testing-library-compass'; @@ -80,6 +85,50 @@ describe('import [module]', function () { ); expect(mockStore.getState().import.isOpen).to.equal(true); }); + + it('increments openId each time import is opened', function () { + expect(mockStore.getState().import.openId).to.equal(0); + + mockStore.dispatch( + openImport({ + namespace: 'test.test', + origin: 'menu', + connectionId: 'TEST', + }) as any + ); + expect(mockStore.getState().import.openId).to.equal(1); + + mockStore.dispatch(closeImport()); + + mockStore.dispatch( + openImport({ + namespace: 'test.test', + origin: 'menu', + connectionId: 'TEST', + }) as any + ); + expect(mockStore.getState().import.openId).to.equal(2); + }); + + it('increments openId even when re-opened without closing first', function () { + mockStore.dispatch( + openImport({ + namespace: 'test.test', + origin: 'menu', + connectionId: 'TEST', + }) as any + ); + const firstOpenId = mockStore.getState().import.openId; + + mockStore.dispatch( + openImport({ + namespace: 'test.test', + origin: 'menu', + connectionId: 'TEST', + }) as any + ); + expect(mockStore.getState().import.openId).to.equal(firstOpenId + 1); + }); }); describe('#selectImportFileName', function () { diff --git a/packages/compass-import-export/src/modules/import.ts b/packages/compass-import-export/src/modules/import.ts index cc4d2788af0..e3b5ed8910e 100644 --- a/packages/compass-import-export/src/modules/import.ts +++ b/packages/compass-import-export/src/modules/import.ts @@ -86,6 +86,7 @@ type FieldType = FieldFromJSON | FieldFromCSV; type ImportState = { isOpen: boolean; isInProgressMessageOpen: boolean; + openId: number; firstErrors: Error[]; fileType: AcceptedFileType | ''; fileName: string; @@ -122,6 +123,7 @@ type ImportState = { export const INITIAL_STATE: ImportState = { isOpen: false, isInProgressMessageOpen: false, + openId: 0, firstErrors: [], fileName: '', errorLogFilePath: '', @@ -1117,6 +1119,7 @@ export const importReducer: Reducer = ( if (action.type === OPEN) { return { ...INITIAL_STATE, + openId: state.openId + 1, namespace: action.namespace, connectionId: action.connectionId, isOpen: true,