Skip to content

Commit

Permalink
fix(connect): can not select files on the connection form VSCODE-658 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
alenakhineika authored Dec 10, 2024
1 parent 6af38f8 commit b19f2e7
Show file tree
Hide file tree
Showing 12 changed files with 397 additions and 193 deletions.
231 changes: 117 additions & 114 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1209,9 +1209,9 @@
"@babel/core": "^7.25.8",
"@babel/parser": "^7.25.8",
"@babel/traverse": "^7.25.7",
"@mongodb-js/compass-components": "^1.30.1",
"@mongodb-js/connection-form": "^1.42.0",
"@mongodb-js/connection-info": "^0.9.1",
"@mongodb-js/compass-components": "^1.32.1",
"@mongodb-js/connection-form": "^1.45.1",
"@mongodb-js/connection-info": "^0.9.5",
"@mongodb-js/mongodb-constants": "^0.10.3",
"@mongosh/browser-runtime-electron": "^2.3.3",
"@mongosh/i18n": "^2.3.3",
Expand Down
4 changes: 2 additions & 2 deletions src/test/suite/views/webview-app/overview-page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ describe('OverviewPage test suite', function () {
.getCalls()
.filter(
(call) =>
call.args[0].command === MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION
call.args[0].command === MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT
);
};
expect(getConnectMessages()).to.have.length(0);
Expand All @@ -165,7 +165,7 @@ describe('OverviewPage test suite', function () {
expect(connectMessages).to.have.length(1);

expect(connectMessages[0].args[0]).to.deep.equal({
command: 'EDIT_AND_CONNECT_CONNECTION',
command: 'EDIT_CONNECTION_AND_CONNECT',
connectionInfo: {
id: 'pear',
connectionOptions: {
Expand Down
12 changes: 6 additions & 6 deletions src/test/suite/views/webviewController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ suite('Webview Test Suite', () => {
const extensionPath = mdbTestExtension.extensionContextStub.extensionPath;
const htmlString = getWebviewContent({
extensionPath,
telemetryUserId: 'MOCK_ANONYMOU_ID',
telemetryUserId: 'MOCK_ANONYMOUS_ID',
webview: {
asWebviewUri: (jsUri) => {
return jsUri;
Expand All @@ -133,7 +133,7 @@ suite('Webview Test Suite', () => {
});

expect(htmlString).to.include(
">window['VSCODE_EXTENSION_SEGMENT_ANONYMOUS_ID'] = 'MOCK_ANONYMOU_ID';"
">window['VSCODE_EXTENSION_SEGMENT_ANONYMOUS_ID'] = 'MOCK_ANONYMOUS_ID';"
);
});

Expand All @@ -143,7 +143,7 @@ suite('Webview Test Suite', () => {
extensionPath,
telemetryUserId: 'test',
webview: {
asWebviewUri: (jsUri) => {
asWebviewUri: (jsUri: vscode.Uri) => {
return jsUri;
},
} as unknown as vscode.Webview,
Expand Down Expand Up @@ -177,7 +177,7 @@ suite('Webview Test Suite', () => {
extensionPath,
telemetryUserId: 'test',
webview: {
asWebviewUri: (jsUri) => {
asWebviewUri: (jsUri: vscode.Uri) => {
return jsUri;
},
} as unknown as vscode.Webview,
Expand Down Expand Up @@ -368,7 +368,7 @@ suite('Webview Test Suite', () => {
onDidReceiveMessage: (callback): void => {
messageReceived = callback;
},
asWebviewUri: () => '',
asWebviewUri: (): string => '',
};
const fakeVSCodeExecuteCommand = sandbox
.stub(vscode.commands, 'executeCommand')
Expand Down Expand Up @@ -538,7 +538,7 @@ suite('Webview Test Suite', () => {

// Mock a connection status request call.
messageReceived({
command: MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION,
command: MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT,
connectionInfo: {
id: 'pineapple',
connectionOptions: {
Expand Down
2 changes: 1 addition & 1 deletion src/views/webview-app/connection-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const ConnectionForm: React.FunctionComponent<
// Warning: This property may be removed in future
// modal releases.
contentClassName={modalContentStyles}
setOpen={() => onClose()}
setOpen={(): void => onClose()}
open={open}
size="large"
>
Expand Down
35 changes: 28 additions & 7 deletions src/views/webview-app/extension-app-message-constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ConnectionOptions } from 'mongodb-data-service';
import type { FileChooserOptions } from './use-connection-form';

export enum CONNECTION_STATUS {
LOADING = 'LOADING', // When the connection status has not yet been shared from the extension.
Expand All @@ -19,9 +20,11 @@ export enum MESSAGE_TYPES {
CANCEL_CONNECT = 'CANCEL_CONNECT',
CONNECT_RESULT = 'CONNECT_RESULT',
CONNECTION_FORM_OPENED = 'CONNECTION_FORM_OPENED',
OPEN_FILE_CHOOSER = 'OPEN_FILE_CHOOSER',
OPEN_FILE_CHOOSER_RESULT = 'OPEN_FILE_CHOOSER_RESULT',
CONNECTION_STATUS_MESSAGE = 'CONNECTION_STATUS_MESSAGE',
OPEN_EDIT_CONNECTION = 'OPEN_EDIT_CONNECTION',
EDIT_AND_CONNECT_CONNECTION = 'EDIT_AND_CONNECT_CONNECTION',
EDIT_CONNECTION_AND_CONNECT = 'EDIT_CONNECTION_AND_CONNECT',
EXTENSION_LINK_CLICKED = 'EXTENSION_LINK_CLICKED',
CREATE_NEW_PLAYGROUND = 'CREATE_NEW_PLAYGROUND',
GET_CONNECTION_STATUS = 'GET_CONNECTION_STATUS',
Expand Down Expand Up @@ -58,14 +61,20 @@ export interface OpenEditConnectionMessage extends BasicWebviewMessage {
};
}

export interface EditAndConnectConnection extends BasicWebviewMessage {
command: MESSAGE_TYPES.EDIT_AND_CONNECT_CONNECTION;
export interface EditConnectionAndConnectMessage extends BasicWebviewMessage {
command: MESSAGE_TYPES.EDIT_CONNECTION_AND_CONNECT;
connectionInfo: {
id: string;
connectionOptions: ConnectionOptions;
};
}

export interface OpenFileChooserMessage extends BasicWebviewMessage {
command: MESSAGE_TYPES.OPEN_FILE_CHOOSER;
fileChooserOptions: FileChooserOptions;
requestId: string;
}

export interface ConnectMessage extends BasicWebviewMessage {
command: MESSAGE_TYPES.CONNECT;
connectionInfo: {
Expand All @@ -85,6 +94,16 @@ export interface ConnectResultsMessage extends BasicWebviewMessage {
connectionId: string;
}

export type FileChooserResult =
| { canceled: false; filePaths: string[] }
| { canceled: false; filePath?: string };

export interface OpenFileChooserResultMessage extends BasicWebviewMessage {
command: MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT;
fileChooserResult: FileChooserResult;
requestId: string;
}

export interface GetConnectionStatusMessage extends BasicWebviewMessage {
command: MESSAGE_TYPES.GET_CONNECTION_STATUS;
}
Expand Down Expand Up @@ -113,7 +132,7 @@ export interface ThemeChangedMessage extends BasicWebviewMessage {
darkMode: boolean;
}

export type MESSAGE_FROM_WEBVIEW_TO_EXTENSION =
export type MessageFromWebviewToExtension =
| ConnectMessage
| CancelConnectMessage
| ConnectionFormOpenedMessage
Expand All @@ -123,10 +142,12 @@ export type MESSAGE_FROM_WEBVIEW_TO_EXTENSION =
| OpenConnectionStringInputMessage
| OpenTrustedLinkMessage
| RenameConnectionMessage
| EditAndConnectConnection;
| EditConnectionAndConnectMessage
| OpenFileChooserMessage;

export type MESSAGE_FROM_EXTENSION_TO_WEBVIEW =
export type MessageFromExtensionToWebview =
| ConnectResultsMessage
| ConnectionStatusMessage
| ThemeChangedMessage
| OpenEditConnectionMessage;
| OpenEditConnectionMessage
| OpenFileChooserResultMessage;
106 changes: 89 additions & 17 deletions src/views/webview-app/overview-page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import React, { useCallback, useLayoutEffect, useState } from 'react';
import type { ElectronShowFileDialogProvider } from '@mongodb-js/compass-components';
import {
HorizontalRule,
css,
resetGlobalCSS,
spacing,
FileInputBackendProvider,
createElectronFileInputBackend,
type ElectronFileDialogOptions,
} from '@mongodb-js/compass-components';
import type { ConnectionOptions } from 'mongodb-data-service';

import OverviewHeader from './overview-header';
import ConnectionStatus from './connection-status';
import ConnectHelper from './connect-helper';
import AtlasCta from './atlas-cta';
import ResourcesPanel from './resources-panel/panel';
import { ConnectionForm } from './connection-form';
import useConnectionForm from './use-connection-form';
import useConnectionForm, {
FILE_CHOOSER_MODE,
type FileChooserOptions,
} from './use-connection-form';
import type { MessageFromExtensionToWebview } from './extension-app-message-constants';
import { MESSAGE_TYPES } from './extension-app-message-constants';

const pageStyles = css({
width: '90%',
Expand All @@ -39,6 +49,7 @@ const OverviewPage: React.FC = () => {
handleCancelConnectClicked,
handleSaveConnectionClicked,
handleConnectClicked,
handleOpenFileChooser,
} = useConnectionForm();
const handleResourcesPanelClose = useCallback(
() => setShowResourcesPanel(false),
Expand All @@ -55,30 +66,91 @@ const OverviewPage: React.FC = () => {
resetGlobalCSS();
}, []);

function handleOpenFileChooserResult<T>(
options: FileChooserOptions
): Promise<T> {
const requestId = handleOpenFileChooser(options);
return new Promise((resolve) => {
const messageHandler = (
event: MessageEvent<MessageFromExtensionToWebview>
): void => {
const message = event.data;
if (
message.command === MESSAGE_TYPES.OPEN_FILE_CHOOSER_RESULT &&
message.requestId === requestId
) {
window.removeEventListener('message', messageHandler);
resolve(message.fileChooserResult as T);
}
};
window.addEventListener('message', messageHandler);
});
}

// Electron 32.0 removed support for the `path` property of the Web File object in favor of the webUtils.getPathForFile method.
// https://github.com/electron/electron/blob/83d704009687956fb4b69cb13ab03664d7950118/docs/breaking-changes.md%23removed-filepath
// We can not import `dialog` and `webUtils` from 'electron' in the sandboxed webview.
// To work around this, we use a custom dialog provider that uses webview APIs
// to send a message to the extension process to open the electron file dialog
// and listen for the response to get the file path and send them to the electron file input backend.
const dialogProvider: ElectronShowFileDialogProvider<void> = {
getCurrentWindow(): void {},
dialog: {
async showSaveDialog(
window: void,
electronFileDialogOptions: Partial<ElectronFileDialogOptions>
): Promise<{ canceled: boolean; filePath?: string }> {
return handleOpenFileChooserResult({
electronFileDialogOptions,
mode: FILE_CHOOSER_MODE.SAVE,
});
},
async showOpenDialog(
window: void,
electronFileDialogOptions: Partial<ElectronFileDialogOptions>
): Promise<{ canceled: boolean; filePaths: string[] }> {
return handleOpenFileChooserResult({
electronFileDialogOptions,
mode: FILE_CHOOSER_MODE.OPEN,
});
},
},
};

return (
<div data-testid="overview-page" className={pageStyles}>
{showResourcesPanel && (
<ResourcesPanel onClose={handleResourcesPanelClose} />
)}
{isConnectionFormOpen && (
<ConnectionForm
isConnecting={isConnecting}
initialConnectionInfo={initialConnectionInfo}
onSaveAndConnectClicked={({ id, connectionOptions }) => {
void handleSaveConnectionClicked({
id,
connectionOptions,
});
handleConnectClicked({
<FileInputBackendProvider
createFileInputBackend={createElectronFileInputBackend(
dialogProvider,
null
)}
>
<ConnectionForm
isConnecting={isConnecting}
initialConnectionInfo={initialConnectionInfo}
onSaveAndConnectClicked={({
id,
connectionOptions,
});
}}
onCancelConnectClicked={handleCancelConnectClicked}
onClose={closeConnectionForm}
open={isConnectionFormOpen}
connectionErrorMessage={connectionErrorMessage}
/>
}: {
id: string;
connectionOptions: ConnectionOptions;
}): void => {
void handleSaveConnectionClicked();
handleConnectClicked({
id,
connectionOptions,
});
}}
onCancelConnectClicked={handleCancelConnectClicked}
onClose={closeConnectionForm}
open={isConnectionFormOpen}
connectionErrorMessage={connectionErrorMessage}
/>
</FileInputBackendProvider>
)}
<OverviewHeader onResourcesClick={handleResourcesClick} />
<HorizontalRule />
Expand Down
Loading

0 comments on commit b19f2e7

Please sign in to comment.