0
# File Dialog System
1
2
Configurable file and folder selection dialogs with filtering, navigation controls, and support for both native (Electron) and web-based implementations. Provides standardized file selection interfaces across different Theia deployment environments.
3
4
## Capabilities
5
6
### FileDialogService Interface
7
8
High-level service providing convenient methods for showing file dialogs with proper type handling and result processing.
9
10
```typescript { .api }
11
/**
12
* High-level service for showing file open/save dialogs
13
*/
14
interface FileDialogService {
15
/** Show file open dialog for single file selection */
16
showOpenDialog(props: OpenFileDialogProps, folder?: FileStat): Promise<URI | undefined>;
17
18
/** Show file open dialog for multiple file selection */
19
showOpenDialog(props: OpenFileDialogProps & { canSelectMany: true }, folder?: FileStat): Promise<MaybeArray<URI> | undefined>;
20
21
/** Show file save dialog */
22
showSaveDialog(props: SaveFileDialogProps, folder?: FileStat): Promise<URI | undefined>;
23
}
24
25
type MaybeArray<T> = T | T[];
26
```
27
28
### Dialog Properties and Configuration
29
30
Comprehensive configuration options for customizing dialog behavior, appearance, and filtering.
31
32
```typescript { .api }
33
/**
34
* Base dialog properties with filters and modal settings
35
*/
36
interface FileDialogProps {
37
/** Dialog title text */
38
title?: string;
39
40
/** File type filters */
41
filters?: FileFilter[];
42
43
/** Default filter to select */
44
defaultFilter?: FileFilter;
45
46
/** Whether dialog should be modal */
47
modal?: boolean;
48
49
/** Initial directory to open */
50
defaultPath?: string;
51
52
/** Custom CSS class names */
53
className?: string;
54
}
55
56
/**
57
* Properties specific to open file dialogs
58
*/
59
interface OpenFileDialogProps extends FileDialogProps {
60
/** Allow file selection */
61
canSelectFiles?: boolean;
62
63
/** Allow folder selection */
64
canSelectFolders?: boolean;
65
66
/** Allow multiple selection */
67
canSelectMany?: boolean;
68
69
/** Label for open button */
70
openLabel?: string;
71
}
72
73
/**
74
* Properties specific to save file dialogs
75
*/
76
interface SaveFileDialogProps extends FileDialogProps {
77
/** Label for save button */
78
saveLabel?: string;
79
80
/** Default filename in input field */
81
inputValue?: string;
82
83
/** Placeholder text for filename input */
84
placeholder?: string;
85
}
86
87
/**
88
* File type filter definition
89
*/
90
interface FileFilter {
91
/** Display name for the filter */
92
name: string;
93
94
/** Array of file extensions (with or without dots) */
95
extensions: string[];
96
}
97
```
98
99
### Dialog Factory Functions
100
101
Factory functions for creating dialog instances with proper dependency injection.
102
103
```typescript { .api }
104
/**
105
* Factory function for creating open file dialogs
106
*/
107
type OpenFileDialogFactory = (props: OpenFileDialogProps) => OpenFileDialog;
108
109
/**
110
* Factory function for creating save file dialogs
111
*/
112
type SaveFileDialogFactory = (props: SaveFileDialogProps) => SaveFileDialog;
113
```
114
115
### Dialog Classes
116
117
Core dialog implementations providing the actual user interface and interaction logic.
118
119
```typescript { .api }
120
/**
121
* Base file dialog with navigation controls
122
*/
123
abstract class FileDialog<T> extends AbstractDialog<T> {
124
/** Back navigation button */
125
protected readonly back: HTMLSpanElement;
126
127
/** Forward navigation button */
128
protected readonly forward: HTMLSpanElement;
129
130
/** Home directory button */
131
protected readonly home: HTMLSpanElement;
132
133
/** Parent directory (up) button */
134
protected readonly up: HTMLSpanElement;
135
136
/** Current location URI */
137
protected location: URI | undefined;
138
139
/** Navigate to specific location */
140
protected navigateTo(location: URI): void;
141
142
/** Get available drives for navigation */
143
protected getDrives(): Promise<URI[]>;
144
}
145
146
/**
147
* File selection dialog implementation
148
*/
149
class OpenFileDialog extends FileDialog<URI | URI[]> {
150
/** Dialog properties */
151
readonly props: OpenFileDialogProps;
152
153
/** Currently selected items */
154
readonly selectedItems: URI[];
155
156
/** Accept the current selection */
157
accept(): void;
158
}
159
160
/**
161
* File save dialog implementation
162
*/
163
class SaveFileDialog extends FileDialog<URI> {
164
/** Dialog properties */
165
readonly props: SaveFileDialogProps;
166
167
/** Filename input element */
168
readonly fileNameInput: HTMLInputElement;
169
170
/** Get the entered filename */
171
readonly fileName: string;
172
173
/** Accept the current filename */
174
accept(): void;
175
}
176
```
177
178
### Dialog Model and Tree Integration
179
180
Model classes managing dialog state and file tree integration for directory navigation.
181
182
```typescript { .api }
183
/**
184
* Dialog model managing state and navigation
185
*/
186
interface FileDialogModel extends FileTreeModel {
187
/** Available file filters */
188
readonly filters: FileFilter[];
189
190
/** Currently active filter */
191
activeFilter: FileFilter | undefined;
192
193
/** Whether to show hidden files */
194
showHiddenFiles: boolean;
195
196
/** Apply current filter to tree nodes */
197
filterTree(): void;
198
}
199
200
/**
201
* Tree implementation for file dialogs
202
*/
203
interface FileDialogTree extends FileTree {
204
/** Dialog-specific tree model */
205
readonly model: FileDialogModel;
206
207
/** Handle file filter changes */
208
applyFileFilter(filter: FileFilter): void;
209
}
210
```
211
212
### Dialog Widget and Components
213
214
Complete widget implementation with all UI components and interaction handlers.
215
216
```typescript { .api }
217
/**
218
* Main dialog widget with all components
219
*/
220
interface FileDialogWidget extends DialogWidget {
221
/** Dialog model instance */
222
readonly model: FileDialogModel;
223
224
/** File tree component */
225
readonly tree: FileDialogTree;
226
227
/** Location navigation bar */
228
readonly locationBar: HTMLElement;
229
230
/** File filter dropdown */
231
readonly filterSelect: HTMLSelectElement;
232
233
/** Hidden files toggle */
234
readonly hiddenFilesToggle: HTMLInputElement;
235
}
236
```
237
238
### Default Implementation
239
240
Default service implementation with support for both web and Electron environments.
241
242
```typescript { .api }
243
/**
244
* Default implementation of FileDialogService
245
*/
246
@injectable()
247
class DefaultFileDialogService implements FileDialogService {
248
/** Open file dialog factory */
249
protected readonly openFileDialogFactory: OpenFileDialogFactory;
250
251
/** Save file dialog factory */
252
protected readonly saveFileDialogFactory: SaveFileDialogFactory;
253
254
async showOpenDialog(props: OpenFileDialogProps, folder?: FileStat): Promise<URI | URI[] | undefined> {
255
const dialog = this.openFileDialogFactory(props);
256
if (folder) {
257
dialog.model.location = folder.resource;
258
}
259
const result = await dialog.open();
260
return result;
261
}
262
263
async showSaveDialog(props: SaveFileDialogProps, folder?: FileStat): Promise<URI | undefined> {
264
const dialog = this.saveFileDialogFactory(props);
265
if (folder) {
266
dialog.model.location = folder.resource;
267
}
268
return dialog.open();
269
}
270
}
271
```
272
273
**Usage Examples:**
274
275
```typescript
276
import { FileDialogService, OpenFileDialogProps, SaveFileDialogProps } from "@theia/filesystem/lib/browser";
277
import { URI } from "@theia/core/lib/common/uri";
278
279
// Inject the service
280
const dialogService = container.get(FileDialogService);
281
282
// Open single file
283
const fileUri = await dialogService.showOpenDialog({
284
title: 'Select Configuration File',
285
canSelectFiles: true,
286
canSelectFolders: false,
287
filters: [
288
{ name: 'JSON Files', extensions: ['json'] },
289
{ name: 'YAML Files', extensions: ['yml', 'yaml'] },
290
{ name: 'All Files', extensions: ['*'] }
291
]
292
});
293
294
if (fileUri) {
295
console.log(`Selected file: ${fileUri.toString()}`);
296
}
297
298
// Open multiple files
299
const fileUris = await dialogService.showOpenDialog({
300
title: 'Select Source Files',
301
canSelectFiles: true,
302
canSelectFolders: false,
303
canSelectMany: true,
304
filters: [
305
{ name: 'TypeScript Files', extensions: ['ts', 'tsx'] },
306
{ name: 'JavaScript Files', extensions: ['js', 'jsx'] }
307
]
308
});
309
310
if (Array.isArray(fileUris)) {
311
console.log(`Selected ${fileUris.length} files`);
312
fileUris.forEach(uri => console.log(uri.toString()));
313
} else if (fileUris) {
314
console.log(`Selected single file: ${fileUris.toString()}`);
315
}
316
317
// Select folder
318
const folderUri = await dialogService.showOpenDialog({
319
title: 'Select Project Folder',
320
canSelectFiles: false,
321
canSelectFolders: true,
322
openLabel: 'Select Folder'
323
});
324
325
// Save file dialog
326
const saveUri = await dialogService.showSaveDialog({
327
title: 'Save Output File',
328
saveLabel: 'Save',
329
inputValue: 'output.json',
330
filters: [
331
{ name: 'JSON Files', extensions: ['json'] },
332
{ name: 'Text Files', extensions: ['txt'] }
333
]
334
});
335
336
if (saveUri) {
337
console.log(`Save location: ${saveUri.toString()}`);
338
}
339
340
// Advanced dialog with initial location
341
const workspaceFolder = URI.parse('file:///workspace');
342
const fileUri2 = await dialogService.showOpenDialog({
343
title: 'Select File from Workspace',
344
canSelectFiles: true,
345
defaultPath: workspaceFolder.fsPath
346
}, {
347
resource: workspaceFolder,
348
isDirectory: true
349
} as FileStat);
350
```
351
352
### Electron Native Dialog Integration
353
354
For Electron applications, native system dialogs are used when available:
355
356
```typescript
357
import { ElectronFileDialogService } from "@theia/filesystem/lib/electron-browser";
358
359
// Electron-specific service uses native dialogs
360
@injectable()
361
class ElectronFileDialogService implements FileDialogService {
362
// Uses Electron's dialog.showOpenDialog() and dialog.showSaveDialog()
363
// Provides native OS file dialog experience
364
}
365
```
366
367
### Custom Dialog Implementations
368
369
```typescript
370
// Custom dialog with additional validation
371
class ValidatingFileDialog extends OpenFileDialog {
372
373
protected accept(): void {
374
const selected = this.selectedItems;
375
376
// Custom validation logic
377
if (!this.validateSelection(selected)) {
378
this.setErrorMessage('Invalid file selection');
379
return;
380
}
381
382
super.accept();
383
}
384
385
private validateSelection(uris: URI[]): boolean {
386
// Custom validation logic
387
return uris.every(uri =>
388
uri.toString().includes('valid-directory')
389
);
390
}
391
}
392
```