Rename registeredServers to objectExplorer (#1093)

This commit is contained in:
Karl Burtram
2018-04-06 13:33:49 -07:00
committed by GitHub
parent 071b510fba
commit 3990719054
60 changed files with 95 additions and 95 deletions

View File

@@ -0,0 +1,97 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export class NodeType {
public static Folder = 'Folder';
public static Root = 'root';
public static Database = 'Database';
public static Server = 'Server';
public static ScalarValuedFunction = 'ScalarValuedFunction';
public static TableValuedFunction = 'TableValuedFunction';
public static AggregateFunction = 'AggregateFunction';
public static FileGroup = 'FileGroup';
public static StoredProcedure = 'StoredProcedure';
public static UserDefinedTableType = 'UserDefinedTableType';
public static View = 'View';
public static Table = 'Table';
public static HistoryTable = 'HistoryTable';
public static ServerLevelLinkedServerLogin = 'ServerLevelLinkedServerLogin';
public static ServerLevelServerAudit = 'ServerLevelServerAudit';
public static ServerLevelCryptographicProvider = 'ServerLevelCryptographicProvider';
public static ServerLevelCredential = 'ServerLevelCredential';
public static ServerLevelServerRole = 'ServerLevelServerRole';
public static ServerLevelLogin = 'ServerLevelLogin';
public static ServerLevelServerAuditSpecification = 'ServerLevelServerAuditSpecification';
public static ServerLevelServerTrigger = 'ServerLevelServerTrigger';
public static ServerLevelLinkedServer = 'ServerLevelLinkedServer';
public static ServerLevelEndpoint = 'ServerLevelEndpoint';
public static Synonym = 'Synonym';
public static DatabaseTrigger = 'DatabaseTrigger';
public static Assembly = 'Assembly';
public static MessageType = 'MessageType';
public static Contract = 'Contract';
public static Queue = 'Queue';
public static Service = 'Service';
public static Route = 'Route';
public static DatabaseAndQueueEventNotification = 'DatabaseAndQueueEventNotification';
public static RemoteServiceBinding = 'RemoteServiceBinding';
public static BrokerPriority = 'BrokerPriority';
public static FullTextCatalog = 'FullTextCatalog';
public static FullTextStopList = 'FullTextStopList';
public static SqlLogFile = 'SqlLogFile';
public static PartitionFunction = 'PartitionFunction';
public static PartitionScheme = 'PartitionScheme';
public static SearchPropertyList = 'SearchPropertyList';
public static User = 'User';
public static Schema = 'Schema';
public static AsymmetricKey = 'AsymmetricKey';
public static Certificate = 'Certificate';
public static SymmetricKey = 'SymmetricKey';
public static DatabaseEncryptionKey = 'DatabaseEncryptionKey';
public static MasterKey = 'MasterKey';
public static DatabaseAuditSpecification = 'DatabaseAuditSpecification';
public static Column = 'Column';
public static Key = 'Key';
public static Constraint = 'Constraint';
public static Trigger = 'Trigger';
public static Index = 'Index';
public static Statistic = 'Statistic';
public static UserDefinedDataType = 'UserDefinedDataType';
public static UserDefinedType = 'UserDefinedType';
public static XmlSchemaCollection = 'XmlSchemaCollection';
public static SystemExactNumeric = 'SystemExactNumeric';
public static SystemApproximateNumeric = 'SystemApproximateNumeric';
public static SystemDateAndTime = 'SystemDateAndTime';
public static SystemCharacterString = 'SystemCharacterString';
public static SystemUnicodeCharacterString = 'SystemUnicodeCharacterString';
public static SystemBinaryString = 'SystemBinaryString';
public static SystemOtherDataType = 'SystemOtherDataType';
public static SystemClrDataType = 'SystemClrDataType';
public static SystemSpatialDataType = 'SystemSpatialDataType';
public static UserDefinedTableTypeColumn = 'UserDefinedTableTypeColumn';
public static UserDefinedTableTypeKey = 'UserDefinedTableTypeKey';
public static UserDefinedTableTypeConstraint = 'UserDefinedTableTypeConstraint';
public static StoredProcedureParameter = 'StoredProcedureParameter';
public static TableValuedFunctionParameter = 'TableValuedFunctionParameter';
public static ScalarValuedFunctionParameter = 'ScalarValuedFunctionParameter';
public static AggregateFunctionParameter = 'AggregateFunctionParameter';
public static DatabaseRole = 'DatabaseRole';
public static ApplicationRole = 'ApplicationRole';
public static FileGroupFile = 'FileGroupFile';
public static SystemMessageType = 'SystemMessageType';
public static SystemContract = 'SystemContract';
public static SystemService = 'SystemService';
public static SystemQueue = 'SystemQueue';
public static Sequence = 'Sequence';
public static SecurityPolicy = 'SecurityPolicy';
public static DatabaseScopedCredential = 'DatabaseScopedCredential';
public static ExternalResource = 'ExternalResource';
public static ExternalDataSource = 'ExternalDataSource';
public static ExternalFileFormat = 'ExternalFileFormat';
public static ExternalTable = 'ExternalTable';
public static ColumnMasterKey = 'ColumnMasterKey';
public static ColumnEncryptionKey = 'ColumnEncryptionKey';
}

View File

@@ -0,0 +1,561 @@
/*---------------------------------------------------------------------------------------------
* 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 { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
import { TreeNode, TreeItemCollapsibleState, ObjectExplorerCallbacks } from 'sql/parts/objectExplorer/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';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import Event, { Emitter } from 'vs/base/common/event';
import * as sqlops from 'sqlops';
import * as nls from 'vs/nls';
import * as TelemetryKeys from 'sql/common/telemetryKeys';
import * as TelemetryUtils from 'sql/common/telemetryUtilities';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { warn, error } from 'sql/base/common/log';
import { ServerTreeView } from 'sql/parts/objectExplorer/viewlet/serverTreeView';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import * as vscode from 'vscode';
export const SERVICE_ID = 'ObjectExplorerService';
export const IObjectExplorerService = createDecorator<IObjectExplorerService>(SERVICE_ID);
export interface IObjectExplorerService {
_serviceBrand: any;
createNewSession(providerId: string, connection: ConnectionProfile): Thenable<sqlops.ObjectExplorerSessionResponse>;
closeSession(providerId: string, session: sqlops.ObjectExplorerSession): Thenable<sqlops.ObjectExplorerCloseSessionResponse>;
expandNode(providerId: string, session: sqlops.ObjectExplorerSession, nodePath: string): Thenable<sqlops.ObjectExplorerExpandInfo>;
refreshNode(providerId: string, session: sqlops.ObjectExplorerSession, nodePath: string): Thenable<sqlops.ObjectExplorerExpandInfo>;
resolveTreeNodeChildren(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]>;
refreshTreeNode(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]>;
onSessionCreated(handle: number, sessionResponse: sqlops.ObjectExplorerSession);
onNodeExpanded(handle: number, sessionResponse: sqlops.ObjectExplorerExpandInfo);
/**
* Register a ObjectExplorer provider
*/
registerProvider(providerId: string, provider: sqlops.ObjectExplorerProvider): void;
getObjectExplorerNode(connection: IConnectionProfile): TreeNode;
updateObjectExplorerNodes(connectionProfile: IConnectionProfile): Promise<void>;
deleteObjectExplorerNode(connection: IConnectionProfile): void;
onUpdateObjectExplorerNodes: Event<ObjectExplorerNodeEventArgs>;
registerServerTreeView(view: ServerTreeView): void;
getSelectedProfileAndDatabase(): { profile: ConnectionProfile, databaseName: string };
isFocused(): boolean;
onSelectionOrFocusChange: Event<void>;
getServerTreeView(): ServerTreeView;
findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames?: string[]): Thenable<sqlops.NodeInfo[]>;
getActiveConnectionNodes(): TreeNode[];
getTreeNode(connectionId: string, nodePath: string): Thenable<TreeNode>;
}
interface SessionStatus {
nodes: { [nodePath: string]: NodeStatus };
connection: ConnectionProfile;
}
interface NodeStatus {
expandEmitter: Emitter<sqlops.ObjectExplorerExpandInfo>;
}
export interface ObjectExplorerNodeEventArgs {
connection: IConnectionProfile;
errorMessage: string;
}
export interface NodeInfoWithConnection {
connectionId: string;
nodeInfo: sqlops.NodeInfo;
}
export class ObjectExplorerService implements IObjectExplorerService {
public _serviceBrand: any;
private _disposables: IDisposable[] = [];
private _providers: { [handle: string]: sqlops.ObjectExplorerProvider; } = Object.create(null);
private _activeObjectExplorerNodes: { [id: string]: TreeNode };
private _sessions: { [sessionId: string]: SessionStatus };
private _onUpdateObjectExplorerNodes: Emitter<ObjectExplorerNodeEventArgs>;
private _serverTreeView: ServerTreeView;
private _onSelectionOrFocusChange: Emitter<void>;
constructor(
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@ITelemetryService private _telemetryService: ITelemetryService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService
) {
this._onUpdateObjectExplorerNodes = new Emitter<ObjectExplorerNodeEventArgs>();
this._activeObjectExplorerNodes = {};
this._sessions = {};
this._providers = {};
this._onSelectionOrFocusChange = new Emitter<void>();
}
public get onUpdateObjectExplorerNodes(): Event<ObjectExplorerNodeEventArgs> {
return this._onUpdateObjectExplorerNodes.event;
}
/**
* Event fired when the selection or focus of Object Explorer changes
*/
public get onSelectionOrFocusChange(): Event<void> {
return this._onSelectionOrFocusChange.event;
}
public updateObjectExplorerNodes(connection: IConnectionProfile): Promise<void> {
return this._connectionManagementService.addSavedPassword(connection).then(withPassword => {
let connectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, withPassword);
return this.updateNewObjectExplorerNode(connectionProfile);
});
}
public deleteObjectExplorerNode(connection: IConnectionProfile): void {
let self = this;
var connectionUri = connection.id;
var nodeTree = this._activeObjectExplorerNodes[connectionUri];
if (nodeTree) {
self.closeSession(connection.providerName, nodeTree.getSession()).then(() => {
delete self._activeObjectExplorerNodes[connectionUri];
delete self._sessions[nodeTree.getSession().sessionId];
});
}
}
/**
* Gets called when expanded node response is ready
*/
public onNodeExpanded(handle: number, expandResponse: sqlops.ObjectExplorerExpandInfo) {
if (expandResponse.errorMessage) {
error(expandResponse.errorMessage);
}
let nodeStatus = this._sessions[expandResponse.sessionId].nodes[expandResponse.nodePath];
if (nodeStatus && nodeStatus.expandEmitter) {
nodeStatus.expandEmitter.fire(expandResponse);
} else {
warn(`Cannot find node status for session: ${expandResponse.sessionId} and node path: ${expandResponse.nodePath}`);
}
}
/**
* Gets called when session is created
*/
public onSessionCreated(handle: number, session: sqlops.ObjectExplorerSession) {
let connection: ConnectionProfile = undefined;
let errorMessage: string = undefined;
if (this._sessions[session.sessionId]) {
connection = this._sessions[session.sessionId].connection;
if (session && session.success && session.rootNode) {
let server = this.toTreeNode(session.rootNode, null);
server.connection = connection;
server.session = session;
this._activeObjectExplorerNodes[connection.id] = server;
} else {
errorMessage = session && session.errorMessage ? session.errorMessage :
nls.localize('OeSessionFailedError', 'Failed to create Object Explorer session');
error(errorMessage);
}
} else {
warn(`cannot find session ${session.sessionId}`);
}
this.sendUpdateNodeEvent(connection, errorMessage);
}
private sendUpdateNodeEvent(connection: ConnectionProfile, errorMessage: string = undefined) {
let eventArgs: ObjectExplorerNodeEventArgs = {
connection: <IConnectionProfile>connection,
errorMessage: errorMessage
};
this._onUpdateObjectExplorerNodes.fire(eventArgs);
}
private updateNewObjectExplorerNode(connection: ConnectionProfile): Promise<void> {
let self = this;
return new Promise<void>((resolve, reject) => {
if (self._activeObjectExplorerNodes[connection.id]) {
this.sendUpdateNodeEvent(connection);
resolve();
} else {
// Create session will send the event or reject the promise
this.createNewSession(connection.providerName, connection).then(response => {
resolve();
}, error => {
this.sendUpdateNodeEvent(connection, error);
reject(error);
});
}
});
}
public getObjectExplorerNode(connection: IConnectionProfile): TreeNode {
return this._activeObjectExplorerNodes[connection.id];
}
public createNewSession(providerId: string, connection: ConnectionProfile): Thenable<sqlops.ObjectExplorerSessionResponse> {
let self = this;
return new Promise<sqlops.ObjectExplorerSessionResponse>((resolve, reject) => {
let provider = this._providers[providerId];
if (provider) {
provider.createNewSession(connection.toConnectionInfo()).then(result => {
self._sessions[result.sessionId] = {
connection: connection,
nodes: {}
};
resolve(result);
}, error => {
reject(error);
});
} else {
reject(`Provider doesn't exist. id: ${providerId}`);
}
});
}
public expandNode(providerId: string, session: sqlops.ObjectExplorerSession, nodePath: string): Thenable<sqlops.ObjectExplorerExpandInfo> {
return new Promise<sqlops.ObjectExplorerExpandInfo>((resolve, reject) => {
let provider = this._providers[providerId];
if (provider) {
TelemetryUtils.addTelemetry(this._telemetryService, TelemetryKeys.ObjectExplorerExpand, { refresh: 0, provider: providerId });
this.expandOrRefreshNode(provider, session, nodePath).then(result => {
resolve(result);
}, error => {
reject(error);
});
} else {
reject(`Provider doesn't exist. id: ${providerId}`);
}
});
}
private callExpandOrRefreshFromProvider(provider: sqlops.ObjectExplorerProvider, nodeInfo: sqlops.ExpandNodeInfo, refresh: boolean = false) {
if (refresh) {
return provider.refreshNode(nodeInfo);
} else {
return provider.expandNode(nodeInfo);
}
}
private expandOrRefreshNode(
provider: sqlops.ObjectExplorerProvider,
session: sqlops.ObjectExplorerSession,
nodePath: string,
refresh: boolean = false): Thenable<sqlops.ObjectExplorerExpandInfo> {
let self = this;
return new Promise<sqlops.ObjectExplorerExpandInfo>((resolve, reject) => {
if (session.sessionId in self._sessions && self._sessions[session.sessionId]) {
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];
}
}));
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}`);
}
});
}
public refreshNode(providerId: string, session: sqlops.ObjectExplorerSession, nodePath: string): Thenable<sqlops.ObjectExplorerExpandInfo> {
let provider = this._providers[providerId];
if (provider) {
TelemetryUtils.addTelemetry(this._telemetryService, TelemetryKeys.ObjectExplorerExpand, { refresh: 1, provider: providerId });
return this.expandOrRefreshNode(provider, session, nodePath, true);
}
return Promise.resolve(undefined);
}
public closeSession(providerId: string, session: sqlops.ObjectExplorerSession): Thenable<sqlops.ObjectExplorerCloseSessionResponse> {
let provider = this._providers[providerId];
if (provider) {
return provider.closeSession({
sessionId: session ? session.sessionId : undefined
});
}
return Promise.resolve(undefined);
}
/**
* Register a ObjectExplorer provider
*/
public registerProvider(providerId: string, provider: sqlops.ObjectExplorerProvider): void {
this._providers[providerId] = provider;
}
public dispose(): void {
this._disposables = dispose(this._disposables);
}
public resolveTreeNodeChildren(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]> {
return this.expandOrRefreshTreeNode(session, parentTree);
}
public refreshTreeNode(session: sqlops.ObjectExplorerSession, parentTree: TreeNode): Thenable<TreeNode[]> {
return this.expandOrRefreshTreeNode(session, parentTree, true);
}
private callExpandOrRefreshFromService(providerId: string, session: sqlops.ObjectExplorerSession, nodePath: string, refresh: boolean = false): Thenable<sqlops.ObjectExplorerExpandInfo> {
if (refresh) {
return this.refreshNode(providerId, session, nodePath);
} else {
return this.expandNode(providerId, session, nodePath);
}
}
private expandOrRefreshTreeNode(
session: sqlops.ObjectExplorerSession,
parentTree: TreeNode,
refresh: boolean = false): Thenable<TreeNode[]> {
return new Promise<TreeNode[]>((resolve, reject) => {
this.callExpandOrRefreshFromService(parentTree.getConnectionProfile().providerName, session, parentTree.nodePath, refresh).then(expandResult => {
let children: TreeNode[] = [];
if (expandResult && expandResult.nodes) {
children = expandResult.nodes.map(node => {
return this.toTreeNode(node, parentTree);
});
parentTree.children = children.filter(c => c !== undefined);
resolve(children);
} else {
reject(expandResult && expandResult.errorMessage ? expandResult.errorMessage : 'Failed to expand node');
}
}, error => {
reject(error);
});
});
}
private toTreeNode(nodeInfo: sqlops.NodeInfo, parent: TreeNode): TreeNode {
// Show the status for database nodes with a status field
let isLeaf: boolean = nodeInfo.isLeaf;
if (nodeInfo.nodeType === NodeType.Database) {
if (nodeInfo.nodeStatus) {
nodeInfo.label = nodeInfo.label + ' (' + nodeInfo.nodeStatus + ')';
}
if (isLeaf) {
// set to common status so we can have a single 'Unavailable' db icon
nodeInfo.nodeStatus = 'Unavailable';
} else {
nodeInfo.nodeStatus = undefined;
}
}
return new TreeNode(nodeInfo.nodeType, nodeInfo.label, isLeaf, nodeInfo.nodePath,
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 {
if (this._serverTreeView) {
throw new Error('The object explorer server tree view is already registered');
}
this._serverTreeView = view;
this._serverTreeView.onSelectionOrFocusChange(() => this._onSelectionOrFocusChange.fire());
}
/**
* Returns the connection profile corresponding to the current Object Explorer selection,
* or undefined if there are multiple selections or no such connection
*/
public getSelectedProfileAndDatabase(): { profile: ConnectionProfile, databaseName: string } {
if (!this._serverTreeView) {
return undefined;
}
let selection = this._serverTreeView.getSelection();
if (selection.length === 1) {
let selectedNode = selection[0];
if (selectedNode instanceof ConnectionProfile) {
return { profile: selectedNode, databaseName: undefined };
} else if (selectedNode instanceof TreeNode) {
let profile = selectedNode.getConnectionProfile();
let database = selectedNode.getDatabaseName();
// If the database is unavailable, use the server connection
if (selectedNode.nodeTypeId === 'Database' && selectedNode.isAlwaysLeaf) {
database = undefined;
}
return { profile: profile, databaseName: database };
}
}
return undefined;
}
/**
* Returns a boolean indicating whether the Object Explorer tree has focus
*/
public isFocused(): boolean {
return this._serverTreeView.isFocused();
}
public getServerTreeView() {
return this._serverTreeView;
}
public findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames?: string[]): Thenable<sqlops.NodeInfo[]> {
let rootNode = this._activeObjectExplorerNodes[connectionId];
if (!rootNode) {
return Promise.resolve([]);
}
let sessionId = rootNode.session.sessionId;
return this._providers[this._sessions[sessionId].connection.providerName].findNodes({
type: type,
name: name,
schema: schema,
database: database,
parentObjectNames: parentObjectNames,
sessionId: sessionId
}).then(response => {
return response.nodes;
});
}
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;
}
}

View File

@@ -0,0 +1,86 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!sql/media/actionBarLabel';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { localize } from 'vs/nls';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { VIEWLET_ID } from 'sql/parts/connection/common/connectionManagement';
import { ConnectionViewlet } from 'sql/parts/objectExplorer/viewlet/connectionViewlet';
// Viewlet Action
export class OpenConnectionsViewletAction extends ToggleViewletAction {
public static ID = VIEWLET_ID;
public static LABEL = 'Show Servers';
constructor(
id: string,
label: string,
@IViewletService viewletService: IViewletService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService
) {
super(id, label, VIEWLET_ID, viewletService, editorService);
}
}
// Viewlet
const viewletDescriptor = new ViewletDescriptor(
ConnectionViewlet,
VIEWLET_ID,
'Servers',
'connectionViewlet',
-100
);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).setDefaultViewletId(VIEWLET_ID);
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(
new SyncActionDescriptor(
OpenConnectionsViewletAction,
OpenConnectionsViewletAction.ID,
OpenConnectionsViewletAction.LABEL,
{ primary: KeyMod.CtrlCmd | KeyCode.Shift | KeyCode.KEY_C }),
'View: Show Servers',
localize('registeredServers.view', "View")
);
let configurationRegistry = <IConfigurationRegistry>Registry.as(Extensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'databaseConnections',
'title': localize('databaseConnections', 'Database Connections'),
'type': 'object',
'properties': {
'datasource.connections': {
'description': localize('datasource.connections', 'data source connections'),
'type': 'array'
},
'datasource.connectionGroups': {
'description': localize('datasource.connectionGroups', 'data source groups'),
'type': 'array'
}
}
});
configurationRegistry.registerConfiguration({
'id': 'startupConfig',
'title': localize('startupConfig', 'Startup Configuration'),
'type': 'object',
'properties': {
'startup.alwaysShowServersView': {
'type': 'boolean',
'description': localize('startup.alwaysShowServersView', 'True for the Servers view to be shown on launch of SQL Operations Studio default; false if the last opened view should be shown'),
'default': true
}
}
});

View File

@@ -0,0 +1,166 @@
/*---------------------------------------------------------------------------------------------
* 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 { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
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
*/
public id: string;
/**
* string defining the type of the node - for example Server, Database, Folder, Table
*/
public nodeTypeId: string;
/**
* Label to display to the user, describing this node
*/
public label: string;
/**
* Is this a leaf node (in which case no children can be generated) or is it expandable?
*/
public isAlwaysLeaf: boolean;
/**
* Message to show if this Node is in an error state. This indicates
* that children could be retrieved
*/
public errorStateMessage: string;
/**
* Parent of this node
*/
public parent: TreeNode;
/**
* Path identifying this node
*/
public nodePath: string;
/**
* Node sub type
*/
public nodeSubType: string;
/**
* Node Status
*/
public nodeStatus: string;
/**
* Children of this node
*/
public children: TreeNode[];
public connection: ConnectionProfile;
public session: sqlops.ObjectExplorerSession;
public metadata: sqlops.ObjectMetadata;
public getConnectionProfile(): ConnectionProfile {
var currentNode: TreeNode = this;
while (!currentNode.connection && currentNode.parent) {
currentNode = currentNode.parent;
}
return currentNode.connection;
}
public getDatabaseName(): string {
if (this.connection) {
return undefined;
}
var currentNode: TreeNode = this;
while (currentNode.nodeTypeId !== NodeType.Database && currentNode.nodeTypeId !== NodeType.Server) {
currentNode = currentNode.parent;
}
if (currentNode.nodeTypeId === NodeType.Database) {
return currentNode.metadata ? currentNode.metadata.name : null;
}
return undefined;
}
public getSession(): sqlops.ObjectExplorerSession {
var currentNode: TreeNode = this;
while (!currentNode.session && currentNode.parent) {
currentNode = currentNode.parent;
}
return currentNode.session;
}
public isTopLevel(): boolean {
if (this.parent && this.parent.nodeTypeId === NodeType.Root) {
return true;
}
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,
private _objectExplorerCallbacks: ObjectExplorerCallbacks) {
this.nodeTypeId = nodeTypeId;
this.label = label;
this.isAlwaysLeaf = isAlwaysLeaf;
this.nodePath = nodePath;
this.parent = parent;
this.metadata = metadata;
this.id = UUID.generateUuid();
this.nodeSubType = nodeSubType;
this.nodeStatus = nodeStatus;
}
}