1
1
import React , { useCallback , useLayoutEffect , useState } from 'react' ;
2
+ import type { ElectronShowFileDialogProvider } from '@mongodb-js/compass-components' ;
2
3
import {
3
4
HorizontalRule ,
4
5
css ,
5
6
resetGlobalCSS ,
6
7
spacing ,
8
+ FileInputBackendProvider ,
9
+ createElectronFileInputBackend ,
10
+ type ElectronFileDialogOptions ,
7
11
} from '@mongodb-js/compass-components' ;
12
+ import type { ConnectionOptions } from 'mongodb-data-service' ;
8
13
9
14
import OverviewHeader from './overview-header' ;
10
15
import ConnectionStatus from './connection-status' ;
11
16
import ConnectHelper from './connect-helper' ;
12
17
import AtlasCta from './atlas-cta' ;
13
18
import ResourcesPanel from './resources-panel/panel' ;
14
19
import { ConnectionForm } from './connection-form' ;
15
- import useConnectionForm from './use-connection-form' ;
20
+ import useConnectionForm , {
21
+ FILE_CHOOSER_MODE ,
22
+ type FileChooserOptions ,
23
+ } from './use-connection-form' ;
24
+ import type { MessageFromExtensionToWebview } from './extension-app-message-constants' ;
25
+ import { MESSAGE_TYPES } from './extension-app-message-constants' ;
16
26
17
27
const pageStyles = css ( {
18
28
width : '90%' ,
@@ -39,6 +49,7 @@ const OverviewPage: React.FC = () => {
39
49
handleCancelConnectClicked,
40
50
handleSaveConnectionClicked,
41
51
handleConnectClicked,
52
+ handleOpenFileChooser,
42
53
} = useConnectionForm ( ) ;
43
54
const handleResourcesPanelClose = useCallback (
44
55
( ) => setShowResourcesPanel ( false ) ,
@@ -55,30 +66,91 @@ const OverviewPage: React.FC = () => {
55
66
resetGlobalCSS ( ) ;
56
67
} , [ ] ) ;
57
68
69
+ function handleOpenFileChooserResult < T > (
70
+ options : FileChooserOptions
71
+ ) : Promise < T > {
72
+ const requestId = handleOpenFileChooser ( options ) ;
73
+ return new Promise ( ( resolve ) => {
74
+ const messageHandler = (
75
+ event : MessageEvent < MessageFromExtensionToWebview >
76
+ ) : void => {
77
+ const message = event . data ;
78
+ if (
79
+ message . command === MESSAGE_TYPES . OPEN_FILE_CHOOSER_RESULT &&
80
+ message . requestId === requestId
81
+ ) {
82
+ window . removeEventListener ( 'message' , messageHandler ) ;
83
+ resolve ( message . fileChooserResult as T ) ;
84
+ }
85
+ } ;
86
+ window . addEventListener ( 'message' , messageHandler ) ;
87
+ } ) ;
88
+ }
89
+
90
+ // Electron 32.0 removed support for the `path` property of the Web File object in favor of the webUtils.getPathForFile method.
91
+ // https://github.com/electron/electron/blob/83d704009687956fb4b69cb13ab03664d7950118/docs/breaking-changes.md%23removed-filepath
92
+ // We can not import `dialog` and `webUtils` from 'electron' in the sandboxed webview.
93
+ // To work around this, we use a custom dialog provider that uses webview APIs
94
+ // to send a message to the extension process to open the electron file dialog
95
+ // and listen for the response to get the file path and send them to the electron file input backend.
96
+ const dialogProvider : ElectronShowFileDialogProvider < void > = {
97
+ getCurrentWindow ( ) : void { } ,
98
+ dialog : {
99
+ async showSaveDialog (
100
+ window : void ,
101
+ electronFileDialogOptions : Partial < ElectronFileDialogOptions >
102
+ ) : Promise < { canceled : boolean ; filePath ?: string } > {
103
+ return handleOpenFileChooserResult ( {
104
+ electronFileDialogOptions,
105
+ mode : FILE_CHOOSER_MODE . SAVE ,
106
+ } ) ;
107
+ } ,
108
+ async showOpenDialog (
109
+ window : void ,
110
+ electronFileDialogOptions : Partial < ElectronFileDialogOptions >
111
+ ) : Promise < { canceled : boolean ; filePaths : string [ ] } > {
112
+ return handleOpenFileChooserResult ( {
113
+ electronFileDialogOptions,
114
+ mode : FILE_CHOOSER_MODE . OPEN ,
115
+ } ) ;
116
+ } ,
117
+ } ,
118
+ } ;
119
+
58
120
return (
59
121
< div data-testid = "overview-page" className = { pageStyles } >
60
122
{ showResourcesPanel && (
61
123
< ResourcesPanel onClose = { handleResourcesPanelClose } />
62
124
) }
63
125
{ isConnectionFormOpen && (
64
- < ConnectionForm
65
- isConnecting = { isConnecting }
66
- initialConnectionInfo = { initialConnectionInfo }
67
- onSaveAndConnectClicked = { ( { id, connectionOptions } ) => {
68
- void handleSaveConnectionClicked ( {
69
- id,
70
- connectionOptions,
71
- } ) ;
72
- handleConnectClicked ( {
126
+ < FileInputBackendProvider
127
+ createFileInputBackend = { createElectronFileInputBackend (
128
+ dialogProvider ,
129
+ null
130
+ ) }
131
+ >
132
+ < ConnectionForm
133
+ isConnecting = { isConnecting }
134
+ initialConnectionInfo = { initialConnectionInfo }
135
+ onSaveAndConnectClicked = { ( {
73
136
id,
74
137
connectionOptions,
75
- } ) ;
76
- } }
77
- onCancelConnectClicked = { handleCancelConnectClicked }
78
- onClose = { closeConnectionForm }
79
- open = { isConnectionFormOpen }
80
- connectionErrorMessage = { connectionErrorMessage }
81
- />
138
+ } : {
139
+ id : string ;
140
+ connectionOptions : ConnectionOptions ;
141
+ } ) : void => {
142
+ void handleSaveConnectionClicked ( ) ;
143
+ handleConnectClicked ( {
144
+ id,
145
+ connectionOptions,
146
+ } ) ;
147
+ } }
148
+ onCancelConnectClicked = { handleCancelConnectClicked }
149
+ onClose = { closeConnectionForm }
150
+ open = { isConnectionFormOpen }
151
+ connectionErrorMessage = { connectionErrorMessage }
152
+ />
153
+ </ FileInputBackendProvider >
82
154
) }
83
155
< OverviewHeader onResourcesClick = { handleResourcesClick } />
84
156
< HorizontalRule />
0 commit comments