mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-30 09:35:39 -05:00
243 lines
9.2 KiB
TypeScript
243 lines
9.2 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
'use strict';
|
|
|
|
import 'vs/css!sql/media/icons/common-icons';
|
|
import 'vs/css!./media/fileBrowserDialog';
|
|
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
|
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
|
import * as DialogHelper from 'sql/base/browser/ui/modal/dialogHelper';
|
|
import { Modal } from 'sql/base/browser/ui/modal/modal';
|
|
import { attachModalDialogStyler } from 'sql/common/theme/styler';
|
|
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
|
import { FileNode } from 'sql/parts/fileBrowser/common/fileNode';
|
|
import { FileBrowserTreeView } from 'sql/parts/fileBrowser/fileBrowserTreeView';
|
|
import { FileBrowserViewModel } from 'sql/parts/fileBrowser/fileBrowserViewModel';
|
|
|
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
|
import { Builder } from 'vs/base/browser/builder';
|
|
import { Button } from 'vs/base/browser/ui/button/button';
|
|
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
|
import Event, { Emitter } from 'vs/base/common/event';
|
|
import { localize } from 'vs/nls';
|
|
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|
import { attachInputBoxStyler, attachButtonStyler, attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
|
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
|
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
|
import * as DOM from 'vs/base/browser/dom';
|
|
|
|
export class FileBrowserDialog extends Modal {
|
|
private _viewModel: FileBrowserViewModel;
|
|
private _bodyBuilder: Builder;
|
|
private _filePathInputBox: InputBox;
|
|
private _fileFilterSelectBox: SelectBox;
|
|
private _okButton: Button;
|
|
private _cancelButton: Button;
|
|
private _onOk = new Emitter<string>();
|
|
public onOk: Event<string> = this._onOk.event;
|
|
|
|
private _treeContainer: Builder;
|
|
private _fileBrowserTreeView: FileBrowserTreeView;
|
|
private _selectedFilePath: string;
|
|
private _isFolderSelected: boolean;
|
|
|
|
constructor(title: string,
|
|
@IPartService partService: IPartService,
|
|
@IWorkbenchThemeService private _themeService: IWorkbenchThemeService,
|
|
@IInstantiationService private _instantiationService: IInstantiationService,
|
|
@IContextViewService private _contextViewService: IContextViewService,
|
|
@ITelemetryService telemetryService: ITelemetryService,
|
|
@IContextKeyService contextKeyService: IContextKeyService
|
|
) {
|
|
super(title, TelemetryKeys.Backup, partService, telemetryService, contextKeyService, { isFlyout: true, hasTitleIcon: false, hasBackButton: true, hasSpinner: true });
|
|
this._viewModel = this._instantiationService.createInstance(FileBrowserViewModel);
|
|
this._viewModel.onAddFileTree(args => this.handleOnAddFileTree(args.rootNode, args.selectedNode, args.expandedNodes));
|
|
this._viewModel.onPathValidate(args => this.handleOnValidate(args.succeeded, args.message));
|
|
}
|
|
|
|
protected layout(height?: number): void {
|
|
}
|
|
|
|
protected renderBody(container: HTMLElement) {
|
|
new Builder(container).div({ 'class': 'file-browser-dialog' }, (bodyBuilder) => {
|
|
this._bodyBuilder = bodyBuilder;
|
|
});
|
|
}
|
|
|
|
public render() {
|
|
super.render();
|
|
attachModalDialogStyler(this, this._themeService);
|
|
|
|
if (this.backButton) {
|
|
|
|
this._register(DOM.addDisposableListener(this.backButton.getElement(), DOM.EventType.CLICK, () => {
|
|
this.close();
|
|
}));
|
|
this._register(attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND }));
|
|
}
|
|
|
|
this._bodyBuilder.div({ class: 'tree-view' }, (treeContainer) => {
|
|
this._treeContainer = treeContainer;
|
|
});
|
|
|
|
this._bodyBuilder.div({ class: 'option-section' }, (tableWrapper) => {
|
|
tableWrapper.element('table', { class: 'file-table-content' }, (tableContainer) => {
|
|
let pathLabel = localize('filebrowser.filepath', 'Selected path');
|
|
let pathBuilder = DialogHelper.appendRow(tableContainer, pathLabel, 'file-input-label', 'file-input-box');
|
|
this._filePathInputBox = new InputBox(pathBuilder.getHTMLElement(), this._contextViewService);
|
|
|
|
this._fileFilterSelectBox = new SelectBox(['*'], '*');
|
|
let filterLabel = localize('fileFilter', 'Files of type');
|
|
let filterBuilder = DialogHelper.appendRow(tableContainer, filterLabel, 'file-input-label', 'file-input-box');
|
|
DialogHelper.appendInputSelectBox(filterBuilder, this._fileFilterSelectBox);
|
|
});
|
|
});
|
|
|
|
this._okButton = this.addFooterButton(localize('ok', 'OK'), () => this.ok());
|
|
this._okButton.enabled = false;
|
|
this._cancelButton = this.addFooterButton(localize('discard', 'Discard'), () => this.close());
|
|
|
|
this.registerListeners();
|
|
this.updateTheme();
|
|
}
|
|
|
|
public open(ownerUri: string,
|
|
expandPath: string,
|
|
fileFilters: [{ label: string, filters: string[] }],
|
|
fileValidationServiceType: string,
|
|
) {
|
|
this._viewModel.initialize(ownerUri, expandPath, fileFilters, fileValidationServiceType);
|
|
this._fileFilterSelectBox.setOptions(this._viewModel.formattedFileFilters);
|
|
this._fileFilterSelectBox.select(0);
|
|
this._filePathInputBox.value = expandPath;
|
|
this._isFolderSelected = true;
|
|
this.enableOkButton();
|
|
this.showSpinner();
|
|
this.show();
|
|
|
|
this._fileBrowserTreeView = this._instantiationService.createInstance(FileBrowserTreeView);
|
|
this._fileBrowserTreeView.setOnClickedCallback((arg) => this.onClicked(arg));
|
|
this._fileBrowserTreeView.setOnDoubleClickedCallback((arg) => this.onDoubleClicked(arg));
|
|
this._viewModel.openFileBrowser(0, false);
|
|
}
|
|
|
|
/* enter key */
|
|
protected onAccept() {
|
|
if (this._okButton.enabled === true) {
|
|
this.ok();
|
|
}
|
|
}
|
|
|
|
private handleOnAddFileTree(rootNode: FileNode, selectedNode: FileNode, expandedNodes: FileNode[]) {
|
|
this.updateFileTree(rootNode, selectedNode, expandedNodes);
|
|
this.hideSpinner();
|
|
}
|
|
|
|
private enableOkButton() {
|
|
if (DialogHelper.isNullOrWhiteSpace(this._selectedFilePath) || this._isFolderSelected === true) {
|
|
this._okButton.enabled = false;
|
|
} else {
|
|
this._okButton.enabled = true;
|
|
}
|
|
}
|
|
|
|
private onClicked(selectedNode: FileNode) {
|
|
this._filePathInputBox.value = selectedNode.fullPath;
|
|
|
|
if (selectedNode.isFile === true) {
|
|
this._isFolderSelected = false;
|
|
} else {
|
|
this._isFolderSelected = true;
|
|
}
|
|
|
|
this.enableOkButton();
|
|
}
|
|
|
|
private onDoubleClicked(selectedNode: FileNode) {
|
|
if (selectedNode.isFile === true) {
|
|
this.ok();
|
|
}
|
|
}
|
|
|
|
private onFilePathChange(filePath: string) {
|
|
this._isFolderSelected = false;
|
|
this._selectedFilePath = filePath;
|
|
|
|
this._filePathInputBox.hideMessage();
|
|
this.enableOkButton();
|
|
}
|
|
|
|
private onFilePathBlur(param) {
|
|
if (!DialogHelper.isNullOrWhiteSpace(param.value)) {
|
|
this._viewModel.validateFilePaths([param.value]);
|
|
}
|
|
}
|
|
|
|
private ok() {
|
|
this._onOk.fire(this._selectedFilePath);
|
|
this.close();
|
|
}
|
|
|
|
private handleOnValidate(succeeded: boolean, errorMessage: string) {
|
|
if (succeeded === false) {
|
|
if (DialogHelper.isNullOrWhiteSpace(errorMessage)) {
|
|
errorMessage = 'The provided path is invalid.';
|
|
}
|
|
this._filePathInputBox.showMessage({ type: MessageType.ERROR, content: errorMessage });
|
|
}
|
|
}
|
|
|
|
private close() {
|
|
if (this._fileBrowserTreeView) {
|
|
this._fileBrowserTreeView.dispose();
|
|
}
|
|
this._onOk.dispose();
|
|
this.hide();
|
|
this._viewModel.closeFileBrowser();
|
|
}
|
|
|
|
private updateFileTree(rootNode: FileNode, selectedNode: FileNode, expandedNodes: FileNode[]): void {
|
|
this._fileBrowserTreeView.renderBody(this._treeContainer.getHTMLElement(), rootNode, selectedNode, expandedNodes);
|
|
this._fileBrowserTreeView.setVisible(true);
|
|
this._fileBrowserTreeView.layout(DOM.getTotalHeight(this._treeContainer.getHTMLElement()));
|
|
}
|
|
|
|
private onFilterSelectChanged(filterIndex) {
|
|
this.showSpinner();
|
|
this._viewModel.openFileBrowser(filterIndex, true);
|
|
}
|
|
|
|
private registerListeners(): void {
|
|
this._register(this._fileFilterSelectBox.onDidSelect(selection => {
|
|
this.onFilterSelectChanged(selection.index);
|
|
}));
|
|
this._register(this._filePathInputBox.onDidChange(e => {
|
|
this.onFilePathChange(e);
|
|
}));
|
|
this._register(this._filePathInputBox.onLoseFocus(params => {
|
|
this.onFilePathBlur(params);
|
|
}));
|
|
|
|
// Theme styler
|
|
this._register(attachInputBoxStyler(this._filePathInputBox, this._themeService));
|
|
this._register(attachSelectBoxStyler(this._fileFilterSelectBox, this._themeService));
|
|
this._register(attachButtonStyler(this._okButton, this._themeService));
|
|
this._register(attachButtonStyler(this._cancelButton, this._themeService));
|
|
|
|
this._register(this._themeService.onDidColorThemeChange(e => this.updateTheme()));
|
|
}
|
|
|
|
// Update theming that is specific to file browser
|
|
private updateTheme(): void {
|
|
if (this._treeContainer) {
|
|
this._treeContainer.style('background-color', this.headerAndFooterBackground);
|
|
}
|
|
}
|
|
} |