mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Object Explorer API (#783)
See https://github.com/Microsoft/sqlopsstudio/wiki/Extensibility-API#object-explorer for usage details
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
import { NodeType } from 'sql/parts/registeredServer/common/nodeType';
|
||||
import { TreeNode } from 'sql/parts/registeredServer/common/treeNode';
|
||||
import { TreeNode, TreeItemCollapsibleState, ObjectExplorerCallbacks } from 'sql/parts/registeredServer/common/treeNode';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -20,6 +20,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { warn, error } from 'sql/base/common/log';
|
||||
import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView';
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export const SERVICE_ID = 'ObjectExplorerService';
|
||||
|
||||
@@ -36,7 +37,7 @@ export interface IObjectExplorerService {
|
||||
|
||||
refreshNode(providerId: string, session: sqlops.ObjectExplorerSession, nodePath: string): Thenable<sqlops.ObjectExplorerExpandInfo>;
|
||||
|
||||
expandTreeNode(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]>;
|
||||
resolveTreeNodeChildren(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]>;
|
||||
|
||||
refreshTreeNode(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]>;
|
||||
|
||||
@@ -66,16 +67,19 @@ export interface IObjectExplorerService {
|
||||
onSelectionOrFocusChange: Event<void>;
|
||||
|
||||
getServerTreeView(): ServerTreeView;
|
||||
|
||||
getActiveConnectionNodes(): TreeNode[];
|
||||
|
||||
getTreeNode(connectionId: string, nodePath: string): Thenable<TreeNode>;
|
||||
}
|
||||
|
||||
interface SessionStatus {
|
||||
nodes: { [nodePath: string]: NodeStatus };
|
||||
connection: ConnectionProfile;
|
||||
|
||||
}
|
||||
|
||||
interface NodeStatus {
|
||||
expandHandler: (result: sqlops.ObjectExplorerExpandInfo) => void;
|
||||
expandEmitter: Emitter<sqlops.ObjectExplorerExpandInfo>;
|
||||
}
|
||||
|
||||
export interface ObjectExplorerNodeEventArgs {
|
||||
@@ -83,6 +87,10 @@ export interface ObjectExplorerNodeEventArgs {
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
export interface NodeInfoWithConnection {
|
||||
connectionId: string;
|
||||
nodeInfo: sqlops.NodeInfo;
|
||||
}
|
||||
|
||||
export class ObjectExplorerService implements IObjectExplorerService {
|
||||
|
||||
@@ -153,8 +161,8 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
||||
}
|
||||
|
||||
let nodeStatus = this._sessions[expandResponse.sessionId].nodes[expandResponse.nodePath];
|
||||
if (nodeStatus && nodeStatus.expandHandler) {
|
||||
nodeStatus.expandHandler(expandResponse);
|
||||
if (nodeStatus && nodeStatus.expandEmitter) {
|
||||
nodeStatus.expandEmitter.fire(expandResponse);
|
||||
} else {
|
||||
warn(`Cannot find node status for session: ${expandResponse.sessionId} and node path: ${expandResponse.nodePath}`);
|
||||
}
|
||||
@@ -268,24 +276,33 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
||||
let self = this;
|
||||
return new Promise<sqlops.ObjectExplorerExpandInfo>((resolve, reject) => {
|
||||
if (session.sessionId in self._sessions && self._sessions[session.sessionId]) {
|
||||
self._sessions[session.sessionId].nodes[nodePath] = {
|
||||
expandHandler: ((expandResult) => {
|
||||
if (expandResult && !expandResult.errorMessage) {
|
||||
resolve(expandResult);
|
||||
}
|
||||
else {
|
||||
reject(expandResult ? expandResult.errorMessage : undefined);
|
||||
}
|
||||
let newRequest = false;
|
||||
if (!self._sessions[session.sessionId].nodes[nodePath]) {
|
||||
self._sessions[session.sessionId].nodes[nodePath] = {
|
||||
expandEmitter: new Emitter<sqlops.ObjectExplorerExpandInfo>()
|
||||
};
|
||||
newRequest = true;
|
||||
}
|
||||
self._sessions[session.sessionId].nodes[nodePath].expandEmitter.event(((expandResult) => {
|
||||
if (expandResult && !expandResult.errorMessage) {
|
||||
resolve(expandResult);
|
||||
}
|
||||
else {
|
||||
reject(expandResult ? expandResult.errorMessage : undefined);
|
||||
}
|
||||
if (newRequest) {
|
||||
delete self._sessions[session.sessionId].nodes[nodePath];
|
||||
})
|
||||
};
|
||||
self.callExpandOrRefreshFromProvider(provider, {
|
||||
sessionId: session ? session.sessionId : undefined,
|
||||
nodePath: nodePath
|
||||
}, refresh).then(result => {
|
||||
}, error => {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
}));
|
||||
if (newRequest) {
|
||||
self.callExpandOrRefreshFromProvider(provider, {
|
||||
sessionId: session.sessionId,
|
||||
nodePath: nodePath
|
||||
}, refresh).then(result => {
|
||||
}, error => {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
reject(`session cannot find to expand node. id: ${session.sessionId} nodePath: ${nodePath}`);
|
||||
}
|
||||
@@ -323,7 +340,7 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
||||
this._disposables = dispose(this._disposables);
|
||||
}
|
||||
|
||||
public expandTreeNode(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]> {
|
||||
public resolveTreeNodeChildren(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]> {
|
||||
return this.expandOrRefreshTreeNode(session, parentTree);
|
||||
}
|
||||
|
||||
@@ -377,7 +394,12 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
||||
}
|
||||
|
||||
return new TreeNode(nodeInfo.nodeType, nodeInfo.label, isLeaf, nodeInfo.nodePath,
|
||||
nodeInfo.nodeSubType, nodeInfo.nodeStatus, parent, nodeInfo.metadata);
|
||||
nodeInfo.nodeSubType, nodeInfo.nodeStatus, parent, nodeInfo.metadata, {
|
||||
getChildren: treeNode => this.getChildren(treeNode),
|
||||
isExpanded: treeNode => this.isExpanded(treeNode),
|
||||
setNodeExpandedState: (treeNode, expandedState) => this.setNodeExpandedState(treeNode, expandedState),
|
||||
setNodeSelected: (treeNode, selected, clearOtherSelections: boolean = undefined) => this.setNodeSelected(treeNode, selected, clearOtherSelections)
|
||||
});
|
||||
}
|
||||
|
||||
public registerServerTreeView(view: ServerTreeView): void {
|
||||
@@ -424,4 +446,96 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
||||
public getServerTreeView() {
|
||||
return this._serverTreeView;
|
||||
}
|
||||
|
||||
public getActiveConnectionNodes(): TreeNode[] {
|
||||
return Object.values(this._activeObjectExplorerNodes);
|
||||
}
|
||||
|
||||
private async setNodeExpandedState(treeNode: TreeNode, expandedState: TreeItemCollapsibleState): Promise<void> {
|
||||
treeNode = await this.getUpdatedTreeNode(treeNode);
|
||||
let expandNode = this.getTreeItem(treeNode);
|
||||
if (expandedState === TreeItemCollapsibleState.Expanded) {
|
||||
await this._serverTreeView.reveal(expandNode);
|
||||
}
|
||||
return this._serverTreeView.setExpandedState(expandNode, expandedState);
|
||||
}
|
||||
|
||||
private async setNodeSelected(treeNode: TreeNode, selected: boolean, clearOtherSelections: boolean = undefined): Promise<void> {
|
||||
treeNode = await this.getUpdatedTreeNode(treeNode);
|
||||
let selectNode = this.getTreeItem(treeNode);
|
||||
if (selected) {
|
||||
await this._serverTreeView.reveal(selectNode);
|
||||
}
|
||||
return this._serverTreeView.setSelected(selectNode, selected, clearOtherSelections);
|
||||
}
|
||||
|
||||
private async getChildren(treeNode: TreeNode): Promise<TreeNode[]> {
|
||||
treeNode = await this.getUpdatedTreeNode(treeNode);
|
||||
if (treeNode.isAlwaysLeaf) {
|
||||
return [];
|
||||
}
|
||||
if (!treeNode.children) {
|
||||
await this.resolveTreeNodeChildren(treeNode.getSession(), treeNode);
|
||||
}
|
||||
return treeNode.children;
|
||||
}
|
||||
|
||||
private async isExpanded(treeNode: TreeNode): Promise<boolean> {
|
||||
treeNode = await this.getUpdatedTreeNode(treeNode);
|
||||
do {
|
||||
let expandNode = this.getTreeItem(treeNode);
|
||||
if (!this._serverTreeView.isExpanded(expandNode)) {
|
||||
return false;
|
||||
}
|
||||
treeNode = treeNode.parent;
|
||||
} while (treeNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private getTreeItem(treeNode: TreeNode): TreeNode | ConnectionProfile {
|
||||
let rootNode = this._activeObjectExplorerNodes[treeNode.getConnectionProfile().id];
|
||||
if (treeNode === rootNode) {
|
||||
return treeNode.connection;
|
||||
}
|
||||
return treeNode;
|
||||
}
|
||||
|
||||
private getUpdatedTreeNode(treeNode: TreeNode): Promise<TreeNode> {
|
||||
return this.getTreeNode(treeNode.getConnectionProfile().id, treeNode.nodePath).then(treeNode => {
|
||||
if (!treeNode) {
|
||||
throw new Error(nls.localize('treeNodeNoLongerExists', 'The given tree node no longer exists'));
|
||||
}
|
||||
return treeNode;
|
||||
});
|
||||
}
|
||||
|
||||
public async getTreeNode(connectionId: string, nodePath: string): Promise<TreeNode> {
|
||||
let parentNode = this._activeObjectExplorerNodes[connectionId];
|
||||
if (!parentNode) {
|
||||
return undefined;
|
||||
}
|
||||
if (!nodePath) {
|
||||
return parentNode;
|
||||
}
|
||||
let currentNode = parentNode;
|
||||
while (currentNode.nodePath !== nodePath) {
|
||||
let nextNode = undefined;
|
||||
if (!currentNode.isAlwaysLeaf && !currentNode.children) {
|
||||
await this.resolveTreeNodeChildren(currentNode.getSession(), currentNode);
|
||||
}
|
||||
if (currentNode.children) {
|
||||
// Look at the next node in the path, which is the child object with the longest path where the desired path starts with the child path
|
||||
let children = currentNode.children.filter(child => nodePath.startsWith(child.nodePath));
|
||||
if (children.length > 0) {
|
||||
nextNode = children.reduce((currentMax, candidate) => currentMax.nodePath.length < candidate.nodePath.length ? candidate : currentMax);
|
||||
}
|
||||
}
|
||||
if (!nextNode) {
|
||||
return undefined;
|
||||
}
|
||||
currentNode = nextNode;
|
||||
}
|
||||
return currentNode;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,19 @@ import * as sqlops from 'sqlops';
|
||||
|
||||
import * as UUID from 'vs/base/common/uuid';
|
||||
|
||||
export enum TreeItemCollapsibleState {
|
||||
None = 0,
|
||||
Collapsed = 1,
|
||||
Expanded = 2
|
||||
}
|
||||
|
||||
export interface ObjectExplorerCallbacks {
|
||||
getChildren(treeNode: TreeNode): Thenable<TreeNode[]>;
|
||||
isExpanded(treeNode: TreeNode): Thenable<boolean>;
|
||||
setNodeExpandedState(TreeNode: TreeNode, expandedState: TreeItemCollapsibleState): Thenable<void>;
|
||||
setNodeSelected(TreeNode: TreeNode, selected: boolean, clearOtherSelections?: boolean): Thenable<void>;
|
||||
}
|
||||
|
||||
export class TreeNode {
|
||||
/**
|
||||
* id for TreeNode
|
||||
@@ -59,8 +72,8 @@ export class TreeNode {
|
||||
public nodeStatus: string;
|
||||
|
||||
/**
|
||||
* Children of this node
|
||||
*/
|
||||
* Children of this node
|
||||
*/
|
||||
public children: TreeNode[];
|
||||
|
||||
|
||||
@@ -108,8 +121,38 @@ export class TreeNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
public toNodeInfo(): sqlops.NodeInfo {
|
||||
return <sqlops.NodeInfo> {
|
||||
nodePath: this.nodePath,
|
||||
nodeType: this.nodeTypeId,
|
||||
nodeSubType: this.nodeSubType,
|
||||
nodeStatus: this.nodeStatus,
|
||||
label: this.label,
|
||||
isLeaf: this.isAlwaysLeaf,
|
||||
metadata: this.metadata,
|
||||
errorMessage: this.errorStateMessage
|
||||
};
|
||||
}
|
||||
|
||||
public getChildren(): Thenable<TreeNode[]> {
|
||||
return this._objectExplorerCallbacks.getChildren(this);
|
||||
}
|
||||
|
||||
public isExpanded(): Thenable<boolean> {
|
||||
return this._objectExplorerCallbacks.isExpanded(this);
|
||||
}
|
||||
|
||||
public setExpandedState(expandedState: TreeItemCollapsibleState): Thenable<void> {
|
||||
return this._objectExplorerCallbacks.setNodeExpandedState(this, expandedState);
|
||||
}
|
||||
|
||||
public setSelected(selected: boolean, clearOtherSelections?: boolean): Thenable<void> {
|
||||
return this._objectExplorerCallbacks.setNodeSelected(this, selected, clearOtherSelections);
|
||||
}
|
||||
|
||||
constructor(nodeTypeId: string, label: string, isAlwaysLeaf: boolean, nodePath: string,
|
||||
nodeSubType: string, nodeStatus: string, parent: TreeNode, metadata: sqlops.ObjectMetadata) {
|
||||
nodeSubType: string, nodeStatus: string, parent: TreeNode, metadata: sqlops.ObjectMetadata,
|
||||
private _objectExplorerCallbacks: ObjectExplorerCallbacks) {
|
||||
this.nodeTypeId = nodeTypeId;
|
||||
this.label = label;
|
||||
this.isAlwaysLeaf = isAlwaysLeaf;
|
||||
|
||||
@@ -74,7 +74,7 @@ export class ServerTreeDataSource implements IDataSource {
|
||||
if (node.children) {
|
||||
resolve(node.children);
|
||||
} else {
|
||||
this._objectExplorerService.expandTreeNode(node.getSession(), node).then(() => {
|
||||
this._objectExplorerService.resolveTreeNodeChildren(node.getSession(), node).then(() => {
|
||||
resolve(node.children);
|
||||
}, expandError => {
|
||||
this.showError(expandError);
|
||||
|
||||
@@ -28,6 +28,7 @@ import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesServ
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { attachButtonStyler } from 'sql/common/theme/styler';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { TreeNode, TreeItemCollapsibleState } from 'sql/parts/registeredServer/common/treeNode';
|
||||
|
||||
const $ = builder.$;
|
||||
|
||||
@@ -428,6 +429,48 @@ export class ServerTreeView {
|
||||
return this._tree.isDOMFocused();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the given element is expanded or collapsed
|
||||
*/
|
||||
public setExpandedState(element: TreeNode | ConnectionProfile, expandedState: TreeItemCollapsibleState): Thenable<void> {
|
||||
if (expandedState === TreeItemCollapsibleState.Collapsed) {
|
||||
return this._tree.collapse(element);
|
||||
} else if (expandedState === TreeItemCollapsibleState.Expanded) {
|
||||
return this._tree.expand(element);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reveal the given element in the tree
|
||||
*/
|
||||
public reveal(element: TreeNode | ConnectionProfile): Thenable<void> {
|
||||
return this._tree.reveal(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the given element in the tree and clear any other selections
|
||||
*/
|
||||
public setSelected(element: TreeNode | ConnectionProfile, selected: boolean, clearOtherSelections: boolean): Thenable<void> {
|
||||
if (clearOtherSelections || (selected && clearOtherSelections !== false)) {
|
||||
this._tree.clearSelection();
|
||||
}
|
||||
if (selected) {
|
||||
this._tree.select(element);
|
||||
return this._tree.reveal(element);
|
||||
} else {
|
||||
this._tree.deselect(element);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given element in the tree is expanded
|
||||
*/
|
||||
public isExpanded(element: TreeNode | ConnectionProfile): boolean {
|
||||
return this._tree.isExpanded(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* dispose the server tree view
|
||||
*/
|
||||
|
||||
@@ -209,7 +209,7 @@ export class TreeUpdateUtils {
|
||||
} else {
|
||||
var rootNode = objectExplorerService.getObjectExplorerNode(connection);
|
||||
if (rootNode) {
|
||||
objectExplorerService.expandTreeNode(rootNode.getSession(), rootNode).then(() => {
|
||||
objectExplorerService.resolveTreeNodeChildren(rootNode.getSession(), rootNode).then(() => {
|
||||
resolve(rootNode.children);
|
||||
}, expandError => {
|
||||
resolve([]);
|
||||
|
||||
61
src/sql/sqlops.d.ts
vendored
61
src/sql/sqlops.d.ts
vendored
@@ -108,6 +108,67 @@ declare module 'sqlops' {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Namespace for interacting with Object Explorer
|
||||
*/
|
||||
export namespace objectexplorer {
|
||||
/**
|
||||
* Get an Object Explorer node corresponding to the given connection and path. If no path
|
||||
* is given, it returns the top-level node for the given connection. If there is no node at
|
||||
* the given path, it returns undefined.
|
||||
* @param {string} connectionId The id of the connection that the node exists on
|
||||
* @param {string?} nodePath The path of the node to get
|
||||
* @returns {ObjectExplorerNode} The node corresponding to the given connection and path,
|
||||
* or undefined if no such node exists.
|
||||
*/
|
||||
export function getNode(connectionId: string, nodePath?: string): Thenable<ObjectExplorerNode>;
|
||||
|
||||
/**
|
||||
* Get all active Object Explorer connection nodes
|
||||
* @returns {ObjectExplorerNode[]} The Object Explorer nodes for each saved connection
|
||||
*/
|
||||
export function getActiveConnectionNodes(): Thenable<ObjectExplorerNode[]>;
|
||||
|
||||
/**
|
||||
* Interface for representing and interacting with items in Object Explorer
|
||||
*/
|
||||
export interface ObjectExplorerNode extends NodeInfo {
|
||||
/**
|
||||
* The id of the connection that the node exists under
|
||||
*/
|
||||
connectionId: string;
|
||||
|
||||
/**
|
||||
* Whether the node is currently expanded in Object Explorer
|
||||
*/
|
||||
isExpanded(): Thenable<boolean>;
|
||||
|
||||
/**
|
||||
* Set whether the node is expanded or collapsed
|
||||
* @param expandedState The new state of the node. If 'None', the node will not be changed
|
||||
*/
|
||||
setExpandedState(expandedState: vscode.TreeItemCollapsibleState): Thenable<void>;
|
||||
|
||||
/**
|
||||
* Set whether the node is selected
|
||||
* @param selected Whether the node should be selected
|
||||
* @param clearOtherSelections If true, clear any other selections. If false, leave any existing selections.
|
||||
* Defaults to true when selected is true and false when selected is false.
|
||||
*/
|
||||
setSelected(selected: boolean, clearOtherSelections?: boolean): Thenable<void>;
|
||||
|
||||
/**
|
||||
* Get all the child nodes. Returns an empty list if there are no children.
|
||||
*/
|
||||
getChildren(): Thenable<ObjectExplorerNode[]>;
|
||||
|
||||
/**
|
||||
* Get the parent node. Returns undefined if there is none.
|
||||
*/
|
||||
getParent(): Thenable<ObjectExplorerNode>;
|
||||
}
|
||||
}
|
||||
|
||||
// EXPORTED INTERFACES /////////////////////////////////////////////////
|
||||
export interface ConnectionInfo {
|
||||
|
||||
|
||||
70
src/sql/workbench/api/node/extHostObjectExplorer.ts
Normal file
70
src/sql/workbench/api/node/extHostObjectExplorer.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||
import { ExtHostObjectExplorerShape, SqlMainContext, MainThreadObjectExplorerShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class ExtHostObjectExplorer implements ExtHostObjectExplorerShape {
|
||||
|
||||
private _proxy: MainThreadObjectExplorerShape;
|
||||
|
||||
constructor(
|
||||
threadService: IThreadService
|
||||
) {
|
||||
this._proxy = threadService.get(SqlMainContext.MainThreadObjectExplorer);
|
||||
}
|
||||
|
||||
public $getNode(connectionId: string, nodePath?: string): Thenable<sqlops.objectexplorer.ObjectExplorerNode> {
|
||||
return this._proxy.$getNode(connectionId, nodePath).then(nodeInfo => nodeInfo === undefined ? undefined : new ExtHostObjectExplorerNode(nodeInfo, connectionId, this._proxy));
|
||||
}
|
||||
|
||||
public $getActiveConnectionNodes(): Thenable<sqlops.objectexplorer.ObjectExplorerNode[]> {
|
||||
return this._proxy.$getActiveConnectionNodes().then(results => results.map(result => new ExtHostObjectExplorerNode(result.nodeInfo, result.connectionId, this._proxy)));
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostObjectExplorerNode implements sqlops.objectexplorer.ObjectExplorerNode {
|
||||
public connectionId: string;
|
||||
public nodePath: string;
|
||||
public nodeType: string;
|
||||
public nodeSubType: string;
|
||||
public nodeStatus: string;
|
||||
public label: string;
|
||||
public isLeaf: boolean;
|
||||
public metadata: sqlops.ObjectMetadata;
|
||||
public errorMessage: string;
|
||||
|
||||
constructor(nodeInfo: sqlops.NodeInfo, connectionId: string, private _proxy: MainThreadObjectExplorerShape) {
|
||||
Object.entries(nodeInfo).forEach(([key, value]) => this[key] = value);
|
||||
this.connectionId = connectionId;
|
||||
}
|
||||
|
||||
isExpanded(): Thenable<boolean> {
|
||||
return this._proxy.$isExpanded(this.connectionId, this.nodePath);
|
||||
}
|
||||
|
||||
setExpandedState(expandedState: vscode.TreeItemCollapsibleState): Thenable<void> {
|
||||
return this._proxy.$setExpandedState(this.connectionId, this.nodePath, expandedState);
|
||||
}
|
||||
|
||||
setSelected(selected: boolean, clearOtherSelections: boolean = undefined): Thenable<void> {
|
||||
return this._proxy.$setSelected(this.connectionId, this.nodePath, selected, clearOtherSelections);
|
||||
}
|
||||
|
||||
getChildren(): Thenable<sqlops.objectexplorer.ObjectExplorerNode[]> {
|
||||
return this._proxy.$getChildren(this.connectionId, this.nodePath).then(children => children.map(nodeInfo => new ExtHostObjectExplorerNode(nodeInfo, this.connectionId, this._proxy)));
|
||||
}
|
||||
|
||||
getParent(): Thenable<sqlops.objectexplorer.ObjectExplorerNode> {
|
||||
let parentPathEndIndex = this.nodePath.lastIndexOf('/');
|
||||
if (parentPathEndIndex === -1) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return this._proxy.$getNode(this.connectionId, this.nodePath.slice(0, parentPathEndIndex)).then(nodeInfo => nodeInfo ? new ExtHostObjectExplorerNode(nodeInfo, this.connectionId, this._proxy) : undefined);
|
||||
}
|
||||
}
|
||||
72
src/sql/workbench/api/node/mainThreadObjectExplorer.ts
Normal file
72
src/sql/workbench/api/node/mainThreadObjectExplorer.ts
Normal 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 { SqlExtHostContext, SqlMainContext, ExtHostObjectExplorerShape, MainThreadObjectExplorerShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { IObjectExplorerService, NodeInfoWithConnection } from 'sql/parts/registeredServer/common/objectExplorerService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
@extHostNamedCustomer(SqlMainContext.MainThreadObjectExplorer)
|
||||
export class MainThreadObjectExplorer implements MainThreadObjectExplorerShape {
|
||||
|
||||
private _proxy: ExtHostObjectExplorerShape;
|
||||
private _toDispose: IDisposable[];
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IWorkbenchEditorService private _workbenchEditorService: IWorkbenchEditorService
|
||||
) {
|
||||
if (extHostContext) {
|
||||
this._proxy = extHostContext.get(SqlExtHostContext.ExtHostObjectExplorer);
|
||||
}
|
||||
this._toDispose = [];
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
public $getNode(connectionId: string, nodePath?: string): Thenable<sqlops.NodeInfo> {
|
||||
return this._objectExplorerService.getTreeNode(connectionId, nodePath).then(treeNode => {
|
||||
if (!treeNode) {
|
||||
return undefined;
|
||||
}
|
||||
return treeNode.toNodeInfo();
|
||||
});
|
||||
}
|
||||
|
||||
public $getActiveConnectionNodes(): Thenable<NodeInfoWithConnection[]> {
|
||||
let connectionNodes = this._objectExplorerService.getActiveConnectionNodes();
|
||||
return Promise.resolve(connectionNodes.map(node => {
|
||||
return {connectionId: node.connection.id, nodeInfo: node.toNodeInfo()};
|
||||
}));
|
||||
}
|
||||
|
||||
public $setExpandedState(connectionId: string, nodePath: string, expandedState: vscode.TreeItemCollapsibleState): Thenable<void> {
|
||||
return this._objectExplorerService.getTreeNode(connectionId, nodePath).then(treeNode => treeNode.setExpandedState(expandedState));
|
||||
}
|
||||
|
||||
public $setSelected(connectionId: string, nodePath: string, selected: boolean, clearOtherSelections: boolean = undefined): Thenable<void> {
|
||||
return this._objectExplorerService.getTreeNode(connectionId, nodePath).then(treeNode => treeNode.setSelected(selected, clearOtherSelections));
|
||||
}
|
||||
|
||||
public $getChildren(connectionId: string, nodePath: string): Thenable<sqlops.NodeInfo[]> {
|
||||
return this._objectExplorerService.getTreeNode(connectionId, nodePath).then(treeNode => treeNode.getChildren().then(children => children.map(node => node.toNodeInfo())));
|
||||
}
|
||||
|
||||
public $isExpanded(connectionId: string, nodePath: string): Thenable<boolean> {
|
||||
return this._objectExplorerService.getTreeNode(connectionId, nodePath).then(treeNode => treeNode.isExpanded());
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import { IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
import { ExtHostDashboardWebviews } from 'sql/workbench/api/node/extHostDashboardWebview';
|
||||
import { ExtHostConnectionManagement } from 'sql/workbench/api/node/extHostConnectionManagement';
|
||||
import { ExtHostDashboard } from 'sql/workbench/api/node/extHostDashboard';
|
||||
import { ExtHostObjectExplorer } from 'sql/workbench/api/node/extHostObjectExplorer';
|
||||
|
||||
export interface ISqlExtensionApiFactory {
|
||||
vsCodeFactory(extension: IExtensionDescription): typeof vscode;
|
||||
@@ -56,6 +57,7 @@ export function createApiFactory(
|
||||
const extHostConnectionManagement = threadService.set(SqlExtHostContext.ExtHostConnectionManagement, new ExtHostConnectionManagement(threadService));
|
||||
const extHostCredentialManagement = threadService.set(SqlExtHostContext.ExtHostCredentialManagement, new ExtHostCredentialManagement(threadService));
|
||||
const extHostDataProvider = threadService.set(SqlExtHostContext.ExtHostDataProtocol, new ExtHostDataProtocol(threadService));
|
||||
const extHostObjectExplorer = threadService.set(SqlExtHostContext.ExtHostObjectExplorer, new ExtHostObjectExplorer(threadService));
|
||||
const extHostSerializationProvider = threadService.set(SqlExtHostContext.ExtHostSerializationProvider, new ExtHostSerializationProvider(threadService));
|
||||
const extHostResourceProvider = threadService.set(SqlExtHostContext.ExtHostResourceProvider, new ExtHostResourceProvider(threadService));
|
||||
const extHostModalDialogs = threadService.set(SqlExtHostContext.ExtHostModalDialogs, new ExtHostModalDialogs(threadService));
|
||||
@@ -105,6 +107,16 @@ export function createApiFactory(
|
||||
}
|
||||
};
|
||||
|
||||
// namespace: objectexplorer
|
||||
const objectExplorer: typeof sqlops.objectexplorer = {
|
||||
getNode(connectionId: string, nodePath?: string): Thenable<sqlops.objectexplorer.ObjectExplorerNode> {
|
||||
return extHostObjectExplorer.$getNode(connectionId, nodePath);
|
||||
},
|
||||
getActiveConnectionNodes(): Thenable<sqlops.objectexplorer.ObjectExplorerNode[]> {
|
||||
return extHostObjectExplorer.$getActiveConnectionNodes();
|
||||
}
|
||||
};
|
||||
|
||||
// namespace: serialization
|
||||
const serialization: typeof sqlops.serialization = {
|
||||
registerProvider(provider: sqlops.SerializationProvider): vscode.Disposable {
|
||||
@@ -286,6 +298,7 @@ export function createApiFactory(
|
||||
accounts,
|
||||
connection,
|
||||
credentials,
|
||||
objectexplorer: objectExplorer,
|
||||
resources,
|
||||
serialization,
|
||||
dataprotocol,
|
||||
|
||||
@@ -13,6 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import 'sql/workbench/api/node/mainThreadConnectionManagement';
|
||||
import 'sql/workbench/api/node/mainThreadCredentialManagement';
|
||||
import 'sql/workbench/api/node/mainThreadDataProtocol';
|
||||
import 'sql/workbench/api/node/mainThreadObjectExplorer';
|
||||
import 'sql/workbench/api/node/mainThreadSerializationProvider';
|
||||
import 'sql/workbench/api/node/mainThreadResourceProvider';
|
||||
import 'sql/workbench/api/electron-browser/mainThreadTasks';
|
||||
|
||||
@@ -13,6 +13,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { ITaskHandlerDescription } from 'sql/platform/tasks/common/tasks';
|
||||
|
||||
@@ -305,7 +306,6 @@ export abstract class ExtHostDataProtocolShape {
|
||||
$stopSession(handle: number, sessionId: string): Thenable<boolean> { throw ni(); }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ResourceProvider extension host class.
|
||||
*/
|
||||
@@ -419,6 +419,7 @@ export const SqlMainContext = {
|
||||
MainThreadConnectionManagement: createMainId<MainThreadConnectionManagementShape>('MainThreadConnectionManagement'),
|
||||
MainThreadCredentialManagement: createMainId<MainThreadCredentialManagementShape>('MainThreadCredentialManagement'),
|
||||
MainThreadDataProtocol: createMainId<MainThreadDataProtocolShape>('MainThreadDataProtocol'),
|
||||
MainThreadObjectExplorer: createMainId<MainThreadObjectExplorerShape>('MainThreadObjectExplorer'),
|
||||
MainThreadSerializationProvider: createMainId<MainThreadSerializationProviderShape>('MainThreadSerializationProvider'),
|
||||
MainThreadResourceProvider: createMainId<MainThreadResourceProviderShape>('MainThreadResourceProvider'),
|
||||
MainThreadModalDialog: createMainId<MainThreadModalDialogShape>('MainThreadModalDialog'),
|
||||
@@ -432,6 +433,7 @@ export const SqlExtHostContext = {
|
||||
ExtHostConnectionManagement: createExtId<ExtHostConnectionManagementShape>('ExtHostConnectionManagement'),
|
||||
ExtHostCredentialManagement: createExtId<ExtHostCredentialManagementShape>('ExtHostCredentialManagement'),
|
||||
ExtHostDataProtocol: createExtId<ExtHostDataProtocolShape>('ExtHostDataProtocol'),
|
||||
ExtHostObjectExplorer: createExtId<ExtHostObjectExplorerShape>('ExtHostObjectExplorer'),
|
||||
ExtHostSerializationProvider: createExtId<ExtHostSerializationProviderShape>('ExtHostSerializationProvider'),
|
||||
ExtHostResourceProvider: createExtId<ExtHostResourceProviderShape>('ExtHostResourceProvider'),
|
||||
ExtHostModalDialogs: createExtId<ExtHostModalDialogsShape>('ExtHostModalDialogs'),
|
||||
@@ -485,3 +487,15 @@ export interface MainThreadDashboardWebviewShape extends IDisposable {
|
||||
$registerProvider(widgetId: string);
|
||||
$setHtml(handle: number, value: string);
|
||||
}
|
||||
|
||||
export interface ExtHostObjectExplorerShape {
|
||||
}
|
||||
|
||||
export interface MainThreadObjectExplorerShape extends IDisposable {
|
||||
$getNode(connectionId: string, nodePath?: string): Thenable<sqlops.NodeInfo>;
|
||||
$getActiveConnectionNodes(): Thenable<{ nodeInfo: sqlops.NodeInfo, connectionId: string}[]>;
|
||||
$setExpandedState(connectionId: string, nodePath: string, expandedState: vscode.TreeItemCollapsibleState): Thenable<void>;
|
||||
$setSelected(connectionId: string, nodePath: string, selected: boolean, clearOtherSelections?: boolean): Thenable<void>;
|
||||
$getChildren(connectionId: string, nodePath: string): Thenable<sqlops.NodeInfo[]>;
|
||||
$isExpanded(connectionId: string, nodePath: string): Thenable<boolean>;
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ suite('SQL Connection Tree Action tests', () => {
|
||||
function createObjectExplorerService(connectionManagementService: TestConnectionManagementService): TypeMoq.Mock<ObjectExplorerService> {
|
||||
let objectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService, TypeMoq.MockBehavior.Strict, connectionManagementService);
|
||||
objectExplorerService.callBase = true;
|
||||
objectExplorerService.setup(x => x.getObjectExplorerNode(TypeMoq.It.isAny())).returns(() => new TreeNode('', '', false, '', '', '', undefined, undefined));
|
||||
objectExplorerService.setup(x => x.getObjectExplorerNode(undefined)).returns(() => new TreeNode('', '', false, '', '', '', undefined, undefined));
|
||||
objectExplorerService.setup(x => x.getObjectExplorerNode(TypeMoq.It.isAny())).returns(() => new TreeNode('', '', false, '', '', '', undefined, undefined, undefined));
|
||||
objectExplorerService.setup(x => x.getObjectExplorerNode(undefined)).returns(() => new TreeNode('', '', false, '', '', '', undefined, undefined, undefined));
|
||||
objectExplorerService.setup(x => x.onUpdateObjectExplorerNodes).returns(() => new Emitter<ObjectExplorerNodeEventArgs>().event);
|
||||
|
||||
objectExplorerService.setup(x => x.onUpdateObjectExplorerNodes).returns(() => new Emitter<ObjectExplorerNodeEventArgs>().event);
|
||||
@@ -144,7 +144,7 @@ suite('SQL Connection Tree Action tests', () => {
|
||||
saveProfile: true,
|
||||
id: 'testId'
|
||||
});
|
||||
let treeNode = new TreeNode(NodeType.Database, 'db node', false, '', '', '', undefined, undefined);
|
||||
let treeNode = new TreeNode(NodeType.Database, 'db node', false, '', '', '', undefined, undefined, undefined);
|
||||
treeNode.connection = connection;
|
||||
var actionContext = new ObjectExplorerActionsContext();
|
||||
actionContext.treeNode = treeNode;
|
||||
@@ -395,11 +395,11 @@ suite('SQL Connection Tree Action tests', () => {
|
||||
errorMessage: ''
|
||||
};
|
||||
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', null, null);
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', null, null, undefined);
|
||||
tablesNode.connection = connection;
|
||||
tablesNode.session = objectExplorerSession;
|
||||
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
|
||||
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
|
||||
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null, undefined);
|
||||
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null, undefined);
|
||||
tablesNode.children = [table1Node, table2Node];
|
||||
let objectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService, TypeMoq.MockBehavior.Loose, connectionManagementService.object);
|
||||
objectExplorerService.callBase = true;
|
||||
@@ -486,11 +486,11 @@ suite('SQL Connection Tree Action tests', () => {
|
||||
errorMessage: ''
|
||||
};
|
||||
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', null, null);
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', null, null, undefined);
|
||||
tablesNode.connection = connection;
|
||||
tablesNode.session = objectExplorerSession;
|
||||
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
|
||||
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
|
||||
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null, undefined);
|
||||
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null, undefined);
|
||||
tablesNode.children = [table1Node, table2Node];
|
||||
let objectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService, TypeMoq.MockBehavior.Loose, connectionManagementService.object);
|
||||
objectExplorerService.callBase = true;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile
|
||||
import { ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
|
||||
import { ObjectExplorerService } from 'sql/parts/registeredServer/common/objectExplorerService';
|
||||
import { NodeType } from 'sql/parts/registeredServer/common/nodeType';
|
||||
import { TreeNode } from 'sql/parts/registeredServer/common/treeNode';
|
||||
import { TreeNode, TreeItemCollapsibleState, ObjectExplorerCallbacks } from 'sql/parts/registeredServer/common/treeNode';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as sqlops from 'sqlops';
|
||||
@@ -37,11 +37,12 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
let sessionId = '1234';
|
||||
let failedSessionId = '12345';
|
||||
let numberOfFailedSession: number = 0;
|
||||
let serverTreeView: TypeMoq.Mock<ServerTreeView>;
|
||||
|
||||
setup(() => {
|
||||
|
||||
let NodeInfoTable1 = {
|
||||
nodePath: 'testServerName\tables\dbo.Table1',
|
||||
nodePath: 'testServerName/tables/dbo.Table1',
|
||||
nodeType: NodeType.Table,
|
||||
label: 'dbo.Table1',
|
||||
isLeaf: false,
|
||||
@@ -51,7 +52,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
errorMessage: ''
|
||||
};
|
||||
let NodeInfoTable2 = {
|
||||
nodePath: 'testServerName\tables\dbo.Table2',
|
||||
nodePath: 'testServerName/tables/dbo.Table2',
|
||||
nodeType: NodeType.Table,
|
||||
label: 'dbo.Table2',
|
||||
isLeaf: false,
|
||||
@@ -62,7 +63,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
};
|
||||
|
||||
let NodeInfoTable3 = {
|
||||
nodePath: 'testServerName\tables\dbo.Table3',
|
||||
nodePath: 'testServerName/tables/dbo.Table3',
|
||||
nodeType: NodeType.Table,
|
||||
label: 'dbo.Table3',
|
||||
isLeaf: false,
|
||||
@@ -76,7 +77,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
success: true,
|
||||
sessionId: sessionId,
|
||||
rootNode: {
|
||||
nodePath: 'testServerName\tables',
|
||||
nodePath: 'testServerName/tables',
|
||||
nodeType: NodeType.Folder,
|
||||
label: 'Tables',
|
||||
isLeaf: false,
|
||||
@@ -284,6 +285,14 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
numberOfFailedSession++;
|
||||
}
|
||||
});
|
||||
|
||||
serverTreeView = TypeMoq.Mock.ofInstance({
|
||||
setExpandedState: (element, expandedState) => Promise.resolve() as Thenable<void>,
|
||||
reveal: element => Promise.resolve() as Thenable<void>,
|
||||
setSelected: (element, selected, clearOtherSelections) => undefined,
|
||||
isExpanded: element => undefined,
|
||||
onSelectionOrFocusChange: Event.None
|
||||
} as ServerTreeView);
|
||||
});
|
||||
|
||||
test('create new session should create session successfully', (done) => {
|
||||
@@ -332,7 +341,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
test('expand node should expand node correctly', (done) => {
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.expandNode('MSSQL', objectExplorerSession, 'testServerName\tables').then(expandInfo => {
|
||||
objectExplorerService.expandNode('MSSQL', objectExplorerSession, 'testServerName/tables').then(expandInfo => {
|
||||
assert.equal(expandInfo !== null || expandInfo !== undefined, true);
|
||||
assert.equal(expandInfo.sessionId, '1234');
|
||||
assert.equal(expandInfo.nodes.length, 2);
|
||||
@@ -350,7 +359,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
test('refresh node should refresh node correctly', (done) => {
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.refreshNode('MSSQL', objectExplorerSession, 'testServerName\tables').then(expandInfo => {
|
||||
objectExplorerService.refreshNode('MSSQL', objectExplorerSession, 'testServerName/tables').then(expandInfo => {
|
||||
assert.equal(expandInfo !== null || expandInfo !== undefined, true);
|
||||
assert.equal(expandInfo.sessionId, '1234');
|
||||
assert.equal(expandInfo.nodes.length, 2);
|
||||
@@ -365,19 +374,19 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('expand tree node should children correctly', (done) => {
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\tables', '', '', null, null);
|
||||
test('expand tree node should get correct children', (done) => {
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName/tables', '', '', null, null, undefined);
|
||||
tablesNode.connection = connection;
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.expandTreeNode(objectExplorerSession, tablesNode).then(children => {
|
||||
objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, tablesNode).then(children => {
|
||||
assert.equal(children !== null || children !== undefined, true);
|
||||
assert.equal(children[0].label, 'dbo.Table1');
|
||||
assert.equal(children[0].parent, tablesNode);
|
||||
assert.equal(children[0].nodePath, 'testServerName\tables\dbo.Table1');
|
||||
assert.equal(children[0].nodePath, 'testServerName/tables/dbo.Table1');
|
||||
assert.equal(children[1].label, 'dbo.Table2');
|
||||
assert.equal(children[1].parent, tablesNode);
|
||||
assert.equal(children[1].nodePath, 'testServerName\tables\dbo.Table2');
|
||||
assert.equal(children[1].nodePath, 'testServerName/tables/dbo.Table2');
|
||||
done();
|
||||
}, err => {
|
||||
// Must call done here so test indicates it's finished if errors occur
|
||||
@@ -387,7 +396,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
});
|
||||
|
||||
test('refresh tree node should children correctly', (done) => {
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\tables', '', '', null, null);
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName/tables', '', '', null, null, undefined);
|
||||
tablesNode.connection = connection;
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
@@ -395,10 +404,10 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
assert.equal(children !== null || children !== undefined, true);
|
||||
assert.equal(children[0].label, 'dbo.Table1');
|
||||
assert.equal(children[0].parent, tablesNode);
|
||||
assert.equal(children[0].nodePath, 'testServerName\tables\dbo.Table1');
|
||||
assert.equal(children[0].nodePath, 'testServerName/tables/dbo.Table1');
|
||||
assert.equal(children[1].label, 'dbo.Table3');
|
||||
assert.equal(children[1].parent, tablesNode);
|
||||
assert.equal(children[1].nodePath, 'testServerName\tables\dbo.Table3');
|
||||
assert.equal(children[1].nodePath, 'testServerName/tables/dbo.Table3');
|
||||
done();
|
||||
}, err => {
|
||||
// Must call done here so test indicates it's finished if errors occur
|
||||
@@ -416,7 +425,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
assert.equal(treeNode.getSession(), objectExplorerSession);
|
||||
assert.equal(treeNode.getConnectionProfile(), connection);
|
||||
assert.equal(treeNode.label, 'Tables');
|
||||
assert.equal(treeNode.nodePath, 'testServerName\tables');
|
||||
assert.equal(treeNode.nodePath, 'testServerName/tables');
|
||||
done();
|
||||
}, err => {
|
||||
// Must call done here so test indicates it's finished if errors occur
|
||||
@@ -450,13 +459,13 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
name: 'Db1',
|
||||
schema: null
|
||||
};
|
||||
var databaseNode = new TreeNode(NodeType.Database, 'Db1', false, 'testServerName\Db1', '', '', null, databaseMetaData);
|
||||
var databaseNode = new TreeNode(NodeType.Database, 'Db1', false, 'testServerName\\Db1', '', '', null, databaseMetaData, undefined);
|
||||
databaseNode.connection = connection;
|
||||
databaseNode.session = objectExplorerSession;
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', databaseNode, null);
|
||||
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\\Db1\\tables', '', '', databaseNode, null, undefined);
|
||||
databaseNode.children = [tablesNode];
|
||||
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\Db1\tables\dbo.Table1', '', '', tablesNode, null);
|
||||
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table2', false, 'testServerName\Db1\tables\dbo.Table2', '', '', tablesNode, null);
|
||||
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\\Db1\\tables\\dbo.Table1', '', '', tablesNode, null, undefined);
|
||||
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table2', false, 'testServerName\\Db1\\tables\\dbo.Table2', '', '', tablesNode, null, undefined);
|
||||
tablesNode.children = [table1Node, table2Node];
|
||||
assert.equal(table1Node.getSession(), objectExplorerSession);
|
||||
assert.equal(table1Node.getConnectionProfile(), connection);
|
||||
@@ -475,7 +484,7 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
|
||||
test('getSelectedProfileAndDatabase returns the profile but no database if children of a server are selected', () => {
|
||||
let serverTreeView = TypeMoq.Mock.ofInstance({ getSelection: () => undefined, onSelectionOrFocusChange: Event.None } as ServerTreeView);
|
||||
let databaseNode = new TreeNode(NodeType.Folder, 'Folder1', false, 'testServerName\\Folder1', '', '', undefined, undefined);
|
||||
let databaseNode = new TreeNode(NodeType.Folder, 'Folder1', false, 'testServerName\\Folder1', '', '', undefined, undefined, undefined);
|
||||
databaseNode.connection = connection;
|
||||
serverTreeView.setup(x => x.getSelection()).returns(() => [databaseNode]);
|
||||
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||
@@ -495,8 +504,8 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
schema: undefined
|
||||
};
|
||||
let databaseName = 'Db1';
|
||||
let databaseNode = new TreeNode(NodeType.Database, databaseName, false, 'testServerName\\Db1', '', '', undefined, databaseMetadata);
|
||||
let tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\\Db1\\tables', '', '', databaseNode, undefined);
|
||||
let databaseNode = new TreeNode(NodeType.Database, databaseName, false, 'testServerName\\Db1', '', '', undefined, databaseMetadata, undefined);
|
||||
let tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\\Db1\\tables', '', '', databaseNode, undefined, undefined);
|
||||
databaseNode.connection = connection;
|
||||
databaseNode.children = [tablesNode];
|
||||
serverTreeView.setup(x => x.getSelection()).returns(() => [tablesNode]);
|
||||
@@ -515,4 +524,208 @@ suite('SQL Object Explorer Service tests', () => {
|
||||
let selectedProfileAndDatabase = objectExplorerService.getSelectedProfileAndDatabase();
|
||||
assert.equal(selectedProfileAndDatabase, undefined);
|
||||
});
|
||||
|
||||
test('isExpanded returns true when the node and its parents are expanded', (done) => {
|
||||
let table1NodePath = objectExplorerExpandInfo.nodes[0].nodePath;
|
||||
let tableExpandInfo = {
|
||||
sessionId: sessionId,
|
||||
nodes: [],
|
||||
errorMessage: '',
|
||||
nodePath: table1NodePath
|
||||
};
|
||||
serverTreeView.setup(x => x.isExpanded(TypeMoq.It.isAny())).returns(treeNode => {
|
||||
return treeNode === connection || treeNode.nodePath === table1NodePath;
|
||||
});
|
||||
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, objectExplorerService.getObjectExplorerNode(connection)).then(childNodes => {
|
||||
sqlOEProvider.setup(x => x.expandNode(TypeMoq.It.isAny())).callback(() => {
|
||||
objectExplorerService.onNodeExpanded(1, tableExpandInfo);
|
||||
}).returns(() => TPromise.as(true));
|
||||
let tableNode = childNodes.find(node => node.nodePath === table1NodePath);
|
||||
objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, tableNode).then(() => {
|
||||
// If I check whether the table is expanded, the answer should be yes
|
||||
tableNode.isExpanded().then(isExpanded => {
|
||||
try {
|
||||
assert.equal(isExpanded, true);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
});
|
||||
|
||||
test('isExpanded returns false when the node is not expanded', (done) => {
|
||||
let table1NodePath = objectExplorerExpandInfo.nodes[0].nodePath;
|
||||
serverTreeView.setup(x => x.isExpanded(TypeMoq.It.isAny())).returns(treeNode => {
|
||||
return treeNode === connection;
|
||||
});
|
||||
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, objectExplorerService.getObjectExplorerNode(connection)).then(childNodes => {
|
||||
// If I check whether the table is expanded, the answer should be no because only its parent node is expanded
|
||||
let tableNode = childNodes.find(node => node.nodePath === table1NodePath);
|
||||
tableNode.isExpanded().then(isExpanded => {
|
||||
try {
|
||||
assert.equal(isExpanded, false);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
});
|
||||
|
||||
test('isExpanded returns false when the parent of the requested node is not expanded', (done) => {
|
||||
let table1NodePath = objectExplorerExpandInfo.nodes[0].nodePath;
|
||||
let tableExpandInfo = {
|
||||
sessionId: sessionId,
|
||||
nodes: [],
|
||||
errorMessage: '',
|
||||
nodePath: table1NodePath
|
||||
};
|
||||
serverTreeView.setup(x => x.isExpanded(TypeMoq.It.isAny())).returns(treeNode => {
|
||||
return treeNode.nodePath === table1NodePath;
|
||||
});
|
||||
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, objectExplorerService.getObjectExplorerNode(connection)).then(childNodes => {
|
||||
sqlOEProvider.setup(x => x.expandNode(TypeMoq.It.isAny())).callback(() => {
|
||||
objectExplorerService.onNodeExpanded(1, tableExpandInfo);
|
||||
}).returns(() => TPromise.as(true));
|
||||
objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, childNodes.find(node => node.nodePath === table1NodePath)).then(() => {
|
||||
// If I check whether the table is expanded, the answer should be yes
|
||||
let tableNode = childNodes.find(node => node.nodePath === table1NodePath);
|
||||
tableNode.isExpanded().then(isExpanded => {
|
||||
try {
|
||||
assert.equal(isExpanded, false);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
});
|
||||
|
||||
test('setting a node to expanded calls expand on the requested tree node', (done) => {
|
||||
let table1NodePath = objectExplorerExpandInfo.nodes[0].nodePath;
|
||||
let tableExpandInfo = {
|
||||
sessionId: sessionId,
|
||||
nodes: [],
|
||||
errorMessage: '',
|
||||
nodePath: table1NodePath
|
||||
};
|
||||
// Set up the OE provider so that the second expand call expands the table
|
||||
sqlOEProvider.setup(x => x.expandNode(TypeMoq.It.is(nodeInfo => nodeInfo.nodePath === table1NodePath))).callback(() => {
|
||||
objectExplorerService.onNodeExpanded(1, tableExpandInfo);
|
||||
}).returns(() => TPromise.as(true));
|
||||
serverTreeView.setup(x => x.setExpandedState(TypeMoq.It.isAny(), TypeMoq.It.is(state => state === TreeItemCollapsibleState.Expanded))).returns(treeNode => {
|
||||
if (treeNode instanceof ConnectionProfile) {
|
||||
treeNode = objectExplorerService.getObjectExplorerNode(treeNode);
|
||||
}
|
||||
return objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, treeNode).then(() => undefined);
|
||||
});
|
||||
serverTreeView.setup(x => x.reveal(TypeMoq.It.isAny())).returns(() => Promise.resolve());
|
||||
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
// If I expand the node, then it should get revealed and expanded
|
||||
objectExplorerService.getTreeNode(connection.id, table1NodePath).then(tableNode => {
|
||||
tableNode.setExpandedState(TreeItemCollapsibleState.Expanded).then(() => {
|
||||
try {
|
||||
serverTreeView.verify(x => x.setExpandedState(TypeMoq.It.isValue(tableNode), TypeMoq.It.is(state => state === TreeItemCollapsibleState.Expanded)), TypeMoq.Times.once());
|
||||
serverTreeView.verify(x => x.reveal(TypeMoq.It.isValue(tableNode)), TypeMoq.Times.once());
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
});
|
||||
});
|
||||
|
||||
test('setting a node to collapsed calls collapse on the requested tree node', (done) => {
|
||||
serverTreeView.setup(x => x.isExpanded(TypeMoq.It.isAny())).returns(treeNode => {
|
||||
return treeNode === connection;
|
||||
});
|
||||
serverTreeView.setup(x => x.setExpandedState(TypeMoq.It.is(treeNode => treeNode === connection), TypeMoq.It.is(state => state === TreeItemCollapsibleState.Collapsed))).returns(() => Promise.resolve());
|
||||
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.resolveTreeNodeChildren(objectExplorerSession, objectExplorerService.getObjectExplorerNode(connection)).then(childNodes => {
|
||||
// If I collapse the connection node, then the tree's collapse method should get called
|
||||
objectExplorerService.getTreeNode(connection.id, undefined).then(treeNode => treeNode.setExpandedState(TreeItemCollapsibleState.Collapsed).then(() => {
|
||||
try {
|
||||
serverTreeView.verify(x => x.setExpandedState(TypeMoq.It.is(treeNode => treeNode === connection), TypeMoq.It.is(state => state === TreeItemCollapsibleState.Collapsed)), TypeMoq.Times.once());
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err)));
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
});
|
||||
|
||||
test('setNodeSelected sets the tree selection to the requested tree node', (done) => {
|
||||
let table1NodePath = objectExplorerExpandInfo.nodes[0].nodePath;
|
||||
serverTreeView.setup(x => x.setSelected(TypeMoq.It.is((treeNode: TreeNode) => treeNode.nodePath === table1NodePath), TypeMoq.It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
serverTreeView.setup(x => x.reveal(TypeMoq.It.isAny())).returns(() => Promise.resolve());
|
||||
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
// If I select the table node, then it should be selected and revealed
|
||||
objectExplorerService.getTreeNode(connection.id, table1NodePath).then(tableNode => {
|
||||
tableNode.setSelected(true).then(() => {
|
||||
try {
|
||||
serverTreeView.verify(x => x.setSelected(TypeMoq.It.isValue(tableNode), TypeMoq.It.isValue(true), undefined), TypeMoq.Times.once());
|
||||
serverTreeView.verify(x => x.reveal(TypeMoq.It.isValue(tableNode)), TypeMoq.Times.once());
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
}, err => done(err));
|
||||
});
|
||||
|
||||
test('findTreeNode returns the tree node for the relevant node', (done) => {
|
||||
let table1NodePath = objectExplorerExpandInfo.nodes[0].nodePath;
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.getTreeNode(connection.id, table1NodePath).then(treeNode => {
|
||||
try {
|
||||
assert.equal(treeNode.nodePath, objectExplorerExpandInfo.nodes[0].nodePath);
|
||||
assert.equal(treeNode.nodeTypeId, objectExplorerExpandInfo.nodes[0].nodeType);
|
||||
assert.equal(treeNode.label, objectExplorerExpandInfo.nodes[0].label);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err));
|
||||
});
|
||||
});
|
||||
|
||||
test('findTreeNode returns undefined if the requested node does not exist', (done) => {
|
||||
let invalidNodePath = objectExplorerSession.rootNode.nodePath + '/invalidNode';
|
||||
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
|
||||
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||
objectExplorerService.getTreeNode(connection.id, invalidNodePath).then(nodeInfo => {
|
||||
try {
|
||||
assert.equal(nodeInfo, undefined);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, err => done(err));
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user