Theia filesystem extension providing comprehensive file operations, tree widgets, dialogs, and file system integration for IDE environments.
—
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.
High-level service providing convenient methods for showing file dialogs with proper type handling and result processing.
/**
* High-level service for showing file open/save dialogs
*/
interface FileDialogService {
/** Show file open dialog for single file selection */
showOpenDialog(props: OpenFileDialogProps, folder?: FileStat): Promise<URI | undefined>;
/** Show file open dialog for multiple file selection */
showOpenDialog(props: OpenFileDialogProps & { canSelectMany: true }, folder?: FileStat): Promise<MaybeArray<URI> | undefined>;
/** Show file save dialog */
showSaveDialog(props: SaveFileDialogProps, folder?: FileStat): Promise<URI | undefined>;
}
type MaybeArray<T> = T | T[];Comprehensive configuration options for customizing dialog behavior, appearance, and filtering.
/**
* Base dialog properties with filters and modal settings
*/
interface FileDialogProps {
/** Dialog title text */
title?: string;
/** File type filters */
filters?: FileFilter[];
/** Default filter to select */
defaultFilter?: FileFilter;
/** Whether dialog should be modal */
modal?: boolean;
/** Initial directory to open */
defaultPath?: string;
/** Custom CSS class names */
className?: string;
}
/**
* Properties specific to open file dialogs
*/
interface OpenFileDialogProps extends FileDialogProps {
/** Allow file selection */
canSelectFiles?: boolean;
/** Allow folder selection */
canSelectFolders?: boolean;
/** Allow multiple selection */
canSelectMany?: boolean;
/** Label for open button */
openLabel?: string;
}
/**
* Properties specific to save file dialogs
*/
interface SaveFileDialogProps extends FileDialogProps {
/** Label for save button */
saveLabel?: string;
/** Default filename in input field */
inputValue?: string;
/** Placeholder text for filename input */
placeholder?: string;
}
/**
* File type filter definition
*/
interface FileFilter {
/** Display name for the filter */
name: string;
/** Array of file extensions (with or without dots) */
extensions: string[];
}Factory functions for creating dialog instances with proper dependency injection.
/**
* Factory function for creating open file dialogs
*/
type OpenFileDialogFactory = (props: OpenFileDialogProps) => OpenFileDialog;
/**
* Factory function for creating save file dialogs
*/
type SaveFileDialogFactory = (props: SaveFileDialogProps) => SaveFileDialog;Core dialog implementations providing the actual user interface and interaction logic.
/**
* Base file dialog with navigation controls
*/
abstract class FileDialog<T> extends AbstractDialog<T> {
/** Back navigation button */
protected readonly back: HTMLSpanElement;
/** Forward navigation button */
protected readonly forward: HTMLSpanElement;
/** Home directory button */
protected readonly home: HTMLSpanElement;
/** Parent directory (up) button */
protected readonly up: HTMLSpanElement;
/** Current location URI */
protected location: URI | undefined;
/** Navigate to specific location */
protected navigateTo(location: URI): void;
/** Get available drives for navigation */
protected getDrives(): Promise<URI[]>;
}
/**
* File selection dialog implementation
*/
class OpenFileDialog extends FileDialog<URI | URI[]> {
/** Dialog properties */
readonly props: OpenFileDialogProps;
/** Currently selected items */
readonly selectedItems: URI[];
/** Accept the current selection */
accept(): void;
}
/**
* File save dialog implementation
*/
class SaveFileDialog extends FileDialog<URI> {
/** Dialog properties */
readonly props: SaveFileDialogProps;
/** Filename input element */
readonly fileNameInput: HTMLInputElement;
/** Get the entered filename */
readonly fileName: string;
/** Accept the current filename */
accept(): void;
}Model classes managing dialog state and file tree integration for directory navigation.
/**
* Dialog model managing state and navigation
*/
interface FileDialogModel extends FileTreeModel {
/** Available file filters */
readonly filters: FileFilter[];
/** Currently active filter */
activeFilter: FileFilter | undefined;
/** Whether to show hidden files */
showHiddenFiles: boolean;
/** Apply current filter to tree nodes */
filterTree(): void;
}
/**
* Tree implementation for file dialogs
*/
interface FileDialogTree extends FileTree {
/** Dialog-specific tree model */
readonly model: FileDialogModel;
/** Handle file filter changes */
applyFileFilter(filter: FileFilter): void;
}Complete widget implementation with all UI components and interaction handlers.
/**
* Main dialog widget with all components
*/
interface FileDialogWidget extends DialogWidget {
/** Dialog model instance */
readonly model: FileDialogModel;
/** File tree component */
readonly tree: FileDialogTree;
/** Location navigation bar */
readonly locationBar: HTMLElement;
/** File filter dropdown */
readonly filterSelect: HTMLSelectElement;
/** Hidden files toggle */
readonly hiddenFilesToggle: HTMLInputElement;
}Default service implementation with support for both web and Electron environments.
/**
* Default implementation of FileDialogService
*/
@injectable()
class DefaultFileDialogService implements FileDialogService {
/** Open file dialog factory */
protected readonly openFileDialogFactory: OpenFileDialogFactory;
/** Save file dialog factory */
protected readonly saveFileDialogFactory: SaveFileDialogFactory;
async showOpenDialog(props: OpenFileDialogProps, folder?: FileStat): Promise<URI | URI[] | undefined> {
const dialog = this.openFileDialogFactory(props);
if (folder) {
dialog.model.location = folder.resource;
}
const result = await dialog.open();
return result;
}
async showSaveDialog(props: SaveFileDialogProps, folder?: FileStat): Promise<URI | undefined> {
const dialog = this.saveFileDialogFactory(props);
if (folder) {
dialog.model.location = folder.resource;
}
return dialog.open();
}
}Usage Examples:
import { FileDialogService, OpenFileDialogProps, SaveFileDialogProps } from "@theia/filesystem/lib/browser";
import { URI } from "@theia/core/lib/common/uri";
// Inject the service
const dialogService = container.get(FileDialogService);
// Open single file
const fileUri = await dialogService.showOpenDialog({
title: 'Select Configuration File',
canSelectFiles: true,
canSelectFolders: false,
filters: [
{ name: 'JSON Files', extensions: ['json'] },
{ name: 'YAML Files', extensions: ['yml', 'yaml'] },
{ name: 'All Files', extensions: ['*'] }
]
});
if (fileUri) {
console.log(`Selected file: ${fileUri.toString()}`);
}
// Open multiple files
const fileUris = await dialogService.showOpenDialog({
title: 'Select Source Files',
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: true,
filters: [
{ name: 'TypeScript Files', extensions: ['ts', 'tsx'] },
{ name: 'JavaScript Files', extensions: ['js', 'jsx'] }
]
});
if (Array.isArray(fileUris)) {
console.log(`Selected ${fileUris.length} files`);
fileUris.forEach(uri => console.log(uri.toString()));
} else if (fileUris) {
console.log(`Selected single file: ${fileUris.toString()}`);
}
// Select folder
const folderUri = await dialogService.showOpenDialog({
title: 'Select Project Folder',
canSelectFiles: false,
canSelectFolders: true,
openLabel: 'Select Folder'
});
// Save file dialog
const saveUri = await dialogService.showSaveDialog({
title: 'Save Output File',
saveLabel: 'Save',
inputValue: 'output.json',
filters: [
{ name: 'JSON Files', extensions: ['json'] },
{ name: 'Text Files', extensions: ['txt'] }
]
});
if (saveUri) {
console.log(`Save location: ${saveUri.toString()}`);
}
// Advanced dialog with initial location
const workspaceFolder = URI.parse('file:///workspace');
const fileUri2 = await dialogService.showOpenDialog({
title: 'Select File from Workspace',
canSelectFiles: true,
defaultPath: workspaceFolder.fsPath
}, {
resource: workspaceFolder,
isDirectory: true
} as FileStat);For Electron applications, native system dialogs are used when available:
import { ElectronFileDialogService } from "@theia/filesystem/lib/electron-browser";
// Electron-specific service uses native dialogs
@injectable()
class ElectronFileDialogService implements FileDialogService {
// Uses Electron's dialog.showOpenDialog() and dialog.showSaveDialog()
// Provides native OS file dialog experience
}// Custom dialog with additional validation
class ValidatingFileDialog extends OpenFileDialog {
protected accept(): void {
const selected = this.selectedItems;
// Custom validation logic
if (!this.validateSelection(selected)) {
this.setErrorMessage('Invalid file selection');
return;
}
super.accept();
}
private validateSelection(uris: URI[]): boolean {
// Custom validation logic
return uris.every(uri =>
uri.toString().includes('valid-directory')
);
}
}Install with Tessl CLI
npx tessl i tessl/npm-theia--filesystem