Another code layering (#4037)

* working on formatting

* fixed basic lint errors; starting moving things to their appropriate location

* formatting

* update tslint to match the version of vscode we have

* remove unused code

* work in progress fixing layering

* formatting

* moved connection management service to platform

* formatting

* add missing file

* moving more servies

* formatting

* moving more services

* formatting

* wip

* moving more services

* formatting

* move css file

* add missing svgs

* moved the rest of services

* formatting

* changing around some references

* formatting

* revert tslint

* revert some changes that brake things

* formatting

* fix tests

* fix testzx

* fix tests

* fix tests

* fix compile issue
This commit is contained in:
Anthony Dresser
2019-02-19 12:11:54 -08:00
committed by GitHub
parent 4a82abc19b
commit d4704e39ac
162 changed files with 382 additions and 371 deletions

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* 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 { ITree } from 'vs/base/parts/tree/browser/tree';
import treedefaults = require('vs/base/parts/tree/browser/treeDefaults');
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
/**
* Extends the tree controller to handle mouse and keyboard events on the tree elements
*/
export class FileBrowserController extends treedefaults.DefaultController {
constructor() {
super({ clickBehavior: treedefaults.ClickBehavior.ON_MOUSE_DOWN, openMode: treedefaults.OpenMode.SINGLE_CLICK });
}
protected onLeftClick(tree: ITree, element: any, event: IMouseEvent, origin: string = 'mouse'): boolean {
// In file browser, double clicking an element calls tree.dispose(). There should not be any tree events after selection.
if (event.detail === 2) {
var payload = { origin: origin, originalEvent: event };
if (tree.getInput() === element) {
tree.clearFocus(payload);
tree.clearSelection(payload);
} else {
var isMouseDown = event && event.browserEvent && event.browserEvent.type === 'mousedown';
if (!isMouseDown) {
event.preventDefault(); // we cannot preventDefault onMouseDown because this would break DND otherwise
}
event.stopPropagation();
tree.domFocus();
tree.setSelection([element], payload);
}
return true;
} else {
return super.onLeftClick(tree, element, event, origin);
}
}
protected onEnter(tree: ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
return false;
}
var focus = tree.getFocus();
if (focus) {
// In file browser, pressing enter key on an element will close dialog and call tree.dispose(). There should not be any tree events after selection.
tree.setSelection([focus], payload);
}
return true;
}
}

View File

@@ -0,0 +1,73 @@
/*---------------------------------------------------------------------------------------------
* 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 { IFileBrowserService } from 'sql/platform/fileBrowser/common/interfaces';
import { FileNode } from 'sql/workbench/services/fileBrowser/common/fileNode';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITree, IDataSource } from 'vs/base/parts/tree/browser/tree';
/**
* Implements the DataSource(that returns a parent/children of an element) for the file browser
*/
export class FileBrowserDataSource implements IDataSource {
constructor(
@IFileBrowserService private _fileBrowserService: IFileBrowserService
) {
}
/**
* Returns the unique identifier of the given element.
* No more than one element may use a given identifier.
*/
public getId(tree: ITree, element: any): string {
if (element instanceof FileNode) {
return (<FileNode>element).id;
} else {
return undefined;
}
}
/**
* Returns a boolean value indicating whether the element has children.
*/
public hasChildren(tree: ITree, element: any): boolean {
if (element instanceof FileNode) {
return (<FileNode>element).hasChildren;
}
return false;
}
/**
* Returns the element's children as an array in a promise.
*/
public getChildren(tree: ITree, element: any): TPromise<any> {
return new TPromise<any>((resolve) => {
if (element instanceof FileNode) {
var node = <FileNode>element;
if (node.children) {
resolve(node.children);
} else {
this._fileBrowserService.expandFolderNode(node).then((nodeChildren) => {
resolve(nodeChildren);
}, expandError => {
resolve([]);
});
}
} else {
resolve([]);
}
});
}
/**
* Returns the element's parent in a promise.
*/
public getParent(tree: ITree, element: any): TPromise<any> {
return TPromise.as(null);
}
}

View File

@@ -0,0 +1,250 @@
/*---------------------------------------------------------------------------------------------
* 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 { Button } from 'sql/base/browser/ui/button/button';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
import * as DialogHelper from 'sql/workbench/browser/modal/dialogHelper';
import { Modal } from 'sql/workbench/browser/modal/modal';
import { attachModalDialogStyler, attachButtonStyler } from 'sql/platform/theme/common/styler';
import * as TelemetryKeys from 'sql/common/telemetryKeys';
import { FileNode } from 'sql/workbench/services/fileBrowser/common/fileNode';
import { FileBrowserTreeView } from 'sql/workbench/services/fileBrowser/browser/fileBrowserTreeView';
import { FileBrowserViewModel } from 'sql/workbench/services/fileBrowser/common/fileBrowserViewModel';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Builder } from 'vs/base/browser/builder';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
import { Event, Emitter } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
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, attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
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';
import * as strings from 'vs/base/common/strings';
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
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 _workbenchthemeService: IWorkbenchThemeService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IContextViewService private _contextViewService: IContextViewService,
@ITelemetryService telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService,
@IClipboardService clipboardService: IClipboardService
) {
super(title, TelemetryKeys.Backup, partService, telemetryService, clipboardService, _workbenchthemeService, 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.backButton.onDidClick(() => {
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, {
ariaLabel: pathLabel
});
this._fileFilterSelectBox = new SelectBox(['*'], '*', this._contextViewService);
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('fileBrowser.ok', 'OK'), () => this.ok());
this._okButton.enabled = false;
this._cancelButton = this.addFooterButton(localize('fileBrowser.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 (strings.isFalsyOrWhitespace(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 (!strings.isFalsyOrWhitespace(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 (strings.isFalsyOrWhitespace(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._workbenchthemeService.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);
}
}
}

View File

@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* 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 { IFileBrowserDialogController } from 'sql/workbench/services/fileBrowser/common/fileBrowserDialogController';
import { FileBrowserDialog } from 'sql/workbench/services/fileBrowser/browser/fileBrowserDialog';
import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
/**
* File browser dialog service
*/
export class FileBrowserDialogController implements IFileBrowserDialogController {
_serviceBrand: any;
private _fileBrowserDialog: FileBrowserDialog;
constructor(
@IInstantiationService private _instantiationService: IInstantiationService
) {
}
public showDialog(ownerUri: string,
expandPath: string,
fileFilters: [{ label: string, filters: string[] }],
fileValidationServiceType: string,
isWide: boolean,
handleOnOk: (path: string) => void
) {
if (!this._fileBrowserDialog) {
this._fileBrowserDialog = this._instantiationService.createInstance(FileBrowserDialog, localize('filebrowser.selectFile', "Select a file"));
this._fileBrowserDialog.render();
}
this._fileBrowserDialog.setWide(isWide);
this._fileBrowserDialog.onOk((filepath) => handleOnOk(filepath));
this._fileBrowserDialog.open(ownerUri, expandPath, fileFilters, fileValidationServiceType);
}
}

View File

@@ -0,0 +1,79 @@
/*---------------------------------------------------------------------------------------------
* 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 { FileNode } from 'sql/workbench/services/fileBrowser/common/fileNode';
import { ITree, IRenderer } from 'vs/base/parts/tree/browser/tree';
import { FileKind } from 'vs/platform/files/common/files';
import URI from 'vs/base/common/uri';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { FileLabel } from 'vs/workbench/browser/labels';
import { IFileTemplateData } from 'vs/workbench/parts/files/electron-browser/views/explorerViewer';
import { toDisposable } from 'vs/base/common/lifecycle';
const EmptyDisposable = toDisposable(() => null);
/**
* Renders the tree items.
* Uses the dom template to render file browser.
*/
export class FileBrowserRenderer implements IRenderer {
public static readonly FILE_HEIGHT = 22;
private static readonly FILE_TEMPLATE_ID = 'carbonFileBrowser';
constructor(
@IInstantiationService private instantiationService: IInstantiationService
) {
}
/**
* Returns the element's height in the tree, in pixels.
*/
public getHeight(tree: ITree, element: any): number {
return FileBrowserRenderer.FILE_HEIGHT;
}
/**
* Returns a template ID for a given element.
*/
public getTemplateId(tree: ITree, element: any): string {
return FileBrowserRenderer.FILE_TEMPLATE_ID;
}
/**
* Render template in a dom element based on template id
*/
public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): IFileTemplateData {
const elementDisposable = EmptyDisposable;
const label = this.instantiationService.createInstance(FileLabel, container, void 0);
return { elementDisposable, label, container };
}
/**
* Render a element, given an object bag returned by the template
*/
public renderElement(tree: ITree, element: FileNode, templateId: string, templateData: IFileTemplateData): void {
if (element) {
templateData.label.element.style.display = 'flex';
const extraClasses = ['explorer-item'];
var fileuri = URI.file(element.fullPath);
var filekind;
if (element.parent === null) {
filekind = FileKind.ROOT_FOLDER;
} else if (element.isFile === false) {
filekind = FileKind.FOLDER;
} else {
filekind = FileKind.FILE;
}
templateData.label.setFile(fileuri, { hidePath: true, fileKind: filekind, extraClasses });
}
}
public disposeTemplate(tree: ITree, templateId: string, templateData: IFileTemplateData): void {
templateData.label.dispose();
}
}

View File

@@ -0,0 +1,169 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { FileBrowserDataSource } from 'sql/workbench/services/fileBrowser/browser/fileBrowserDataSource';
import { FileBrowserController } from 'sql/workbench/services/fileBrowser/browser/fileBrowserController';
import { FileBrowserRenderer } from 'sql/workbench/services/fileBrowser/browser/fileBrowserRenderer';
import { IFileBrowserService } from 'sql/platform/fileBrowser/common/interfaces';
import { FileNode } from 'sql/workbench/services/fileBrowser/common/fileNode';
import errors = require('vs/base/common/errors');
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import * as DOM from 'vs/base/browser/dom';
import nls = require('vs/nls');
import { DefaultFilter, DefaultAccessibilityProvider, DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { attachListStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ITree } from 'vs/base/parts/tree/browser/tree';
/**
* Implements tree view for file browser
*/
export class FileBrowserTreeView implements IDisposable {
private _tree: ITree;
private _toDispose: IDisposable[] = [];
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IFileBrowserService private _fileBrowserService: IFileBrowserService,
@IThemeService private _themeService: IThemeService
) {
}
/**
* Render the view body
*/
public renderBody(container: HTMLElement, rootNode: FileNode, selectedNode: FileNode, expandedNodes: FileNode[]): void {
if (!this._tree) {
DOM.addClass(container, 'show-file-icons');
this._tree = this.createFileBrowserTree(container, this._instantiationService);
this._toDispose.push(this._tree.onDidChangeSelection((event) => this.onSelected(event)));
this._toDispose.push(this._fileBrowserService.onExpandFolder(fileNode => this._tree.refresh(fileNode)));
this._toDispose.push(attachListStyler(this._tree, this._themeService));
this._tree.domFocus();
}
if (rootNode) {
this._tree.setInput(rootNode).then(() => {
if (expandedNodes) {
this._tree.expandAll(expandedNodes);
}
if (selectedNode) {
this._tree.select(selectedNode);
this._tree.setFocus(selectedNode);
}
this._tree.getFocus();
}, errors.onUnexpectedError);
}
}
/**
* Create a file browser tree
*/
public createFileBrowserTree(treeContainer: HTMLElement, instantiationService: IInstantiationService): Tree {
const dataSource = instantiationService.createInstance(FileBrowserDataSource);
const renderer = instantiationService.createInstance(FileBrowserRenderer);
const controller = instantiationService.createInstance(FileBrowserController);
const dnd = new DefaultDragAndDrop();
const filter = new DefaultFilter();
const sorter = null;
const accessibilityProvider = new DefaultAccessibilityProvider();
return new Tree(treeContainer, {
dataSource, renderer, controller, dnd, filter, sorter, accessibilityProvider
}, {
indentPixels: 10,
twistiePixels: 12,
ariaLabel: nls.localize({ key: 'fileBrowser.regTreeAriaLabel', comment: ['FileBrowserTree'] }, 'File browser tree')
});
}
/**
* Refresh the tree
*/
public refreshTree(rootNode: FileNode): void {
let selectedElement: any;
let targetsToExpand: any[];
// Focus
this._tree.domFocus();
if (this._tree) {
let selection = this._tree.getSelection();
if (selection && selection.length === 1) {
selectedElement = <any>selection[0];
}
targetsToExpand = this._tree.getExpandedElements();
}
if (rootNode) {
this._tree.setInput(rootNode).then(() => {
// Make sure to expand all folders that were expanded in the previous session
if (targetsToExpand) {
this._tree.expandAll(targetsToExpand);
}
if (selectedElement) {
this._tree.select(selectedElement);
this._tree.setFocus(selectedElement);
}
this._tree.getFocus();
}, errors.onUnexpectedError);
}
}
private onSelected(event: any) {
let selection = this._tree.getSelection();
if (selection && selection.length > 0 && (selection[0] instanceof FileNode)) {
let isMouseOrigin = event.payload && (event.payload.origin === 'mouse');
let isSingleClick = isMouseOrigin && event.payload.originalEvent && event.payload.originalEvent.detail === 1;
let isDoubleClick = isMouseOrigin && event.payload.originalEvent && event.payload.originalEvent.detail === 2;
if (isSingleClick) {
this.onClickedCallback(event.selection[0]);
} else if (isDoubleClick) {
this.onDoublieClickedCallback(event.selection[0]);
}
}
}
public onClickedCallback: any;
public setOnClickedCallback(fn: any) {
this.onClickedCallback = fn;
}
public onDoublieClickedCallback: any;
public setOnDoubleClickedCallback(fn: any) {
this.onDoublieClickedCallback = fn;
}
/**
* set the layout of the view
*/
public layout(height?: number): void {
this._tree.layout(height);
}
/**
* set the visibility of the view
*/
public setVisible(visible: boolean): void {
if (visible) {
this._tree.onVisible();
} else {
this._tree.onHidden();
}
}
/**
* dispose the file browser tree view
*/
public dispose(): void {
if (this._tree) {
this._tree.dispose();
}
this._toDispose = dispose(this._toDispose);
}
}

View File

@@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.file-browser-dialog {
height: 100%;
padding-top: 12px;
padding-left: 12px;
padding-right: 12px;
box-sizing: border-box;
}
.file-browser-dialog .tree-view {
height: calc(100% - 90px);
}
.file-table-content {
width: 100%;
}
.file-browser-dialog .option-section {
padding-top: 10px;
height: 90px;
box-sizing: border-box;
}
.file-input-label {
width: 50px;
padding-bottom: 5px;
}
.file-input-box {
width: 200px;
padding-bottom: 5px;
}
.file-browser-dialog .explorer-item {
height: 22px;
line-height: 22px;
}
.file-browser-dialog .show-file-icons .monaco-tree-row .content {
display: flex;
}
.file-browser-dialog .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before {
background-size: 16px;
background-position: 50% 50%;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
display: inline-block;
vertical-align: top;
content: ' ';
position: initial;
}

View File

@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const IFileBrowserDialogController = createDecorator<IFileBrowserDialogController>('fileBrowserDialogService');
export interface IFileBrowserDialogController {
_serviceBrand: any;
/**
* Show file browser dialog
*/
showDialog(ownerUri: string,
expandPath: string,
fileFilters: { label: string, filters: string[] }[],
fileValidationServiceType: string,
isWide: boolean,
handleOnOk: (path: string) => void): void;
}

View File

@@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* 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 { FileNode } from 'sql/workbench/services/fileBrowser/common/fileNode';
/**
* File tree info needed to render initially
*/
export class FileBrowserTree {
public rootNode: FileNode;
public selectedNode: FileNode;
public expandedNodes: FileNode[];
}

View File

@@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------------------------
* 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 { IFileBrowserService } from 'sql/platform/fileBrowser/common/interfaces';
import { localize } from 'vs/nls';
/**
* View model for file browser dialog
*/
export class FileBrowserViewModel {
private _ownerUri: string;
private _expandPath: string;
private _fileFilters: [{ label: string, filters: string[] }];
private _fileValidationServiceType: string;
public formattedFileFilters: string[];
constructor( @IFileBrowserService private _fileBrowserService: IFileBrowserService) {
}
public onAddFileTree(onAddFileTreeCallback) {
this._fileBrowserService.onAddFileTree(args => onAddFileTreeCallback(args));
}
public onPathValidate(onPathValidateCallback) {
this._fileBrowserService.onPathValidate(args => onPathValidateCallback(args));
}
public initialize(ownerUri: string,
expandPath: string,
fileFilters: [{ label: string, filters: string[] }],
fileValidationServiceType: string,
) {
this._ownerUri = ownerUri;
this._expandPath = expandPath;
this._fileValidationServiceType = fileValidationServiceType;
if (!fileFilters) {
this._fileFilters = [{ label: localize('allFiles', 'All files'), filters: ['*'] }];
} else {
this._fileFilters = fileFilters;
}
this.formattedFileFilters = [];
for (var i = 0; i < this._fileFilters.length; i++) {
var filterStr = this._fileFilters[i].label + '(' + this._fileFilters[i].filters.join(';') + ')';
this.formattedFileFilters.push(filterStr);
}
}
public validateFilePaths(selectedFiles: string[]) {
this._fileBrowserService.validateFilePaths(this._ownerUri, this._fileValidationServiceType, selectedFiles);
}
public openFileBrowser(filterIndex: number, changeFilter: boolean) {
if (this._fileFilters[filterIndex]) {
this._fileBrowserService.openFileBrowser(this._ownerUri, this._expandPath, this._fileFilters[filterIndex].filters, changeFilter);
}
}
public closeFileBrowser() {
this._fileBrowserService.closeFileBrowser(this._ownerUri);
}
}

View File

@@ -0,0 +1,72 @@
/*---------------------------------------------------------------------------------------------
* 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 { generateUuid } from 'vs/base/common/uuid';
/**
* File/folder node in file browser
* FileTreeNode is converted to this FileNode for UI interactions
*/
export class FileNode {
/**
* Node id
*/
public id: string;
/**
* Connection uri
*/
public ownerUri: string;
/**
* File or folder name
*/
public name: string;
/**
* Full path of file or folder
*/
public fullPath: string;
/**
* Parent node
*/
public parent: FileNode;
/**
* Children nodes
*/
public children: FileNode[];
/**
* Is the node expanded
*/
public isExpanded: boolean;
/**
* Is the node file or folder
*/
public isFile: boolean;
/**
* Does this node have children
*/
public hasChildren: boolean;
constructor(id: string, name: string, fullPath: string, isFile: boolean, isExpanded: boolean, ownerUri: string, parent: FileNode) {
if (id) {
this.id = id;
} else {
this.id = generateUuid();
}
this.name = name;
this.fullPath = fullPath;
this.isFile = isFile;
this.ownerUri = ownerUri;
this.isExpanded = isExpanded;
this.parent = parent;
}
}

View File

@@ -0,0 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*
* List of services that provide file validation callback to file browser service
*/
export const backup: string = 'Backup';
export const restore: string = 'Restore';