Extensibility: Context menu support in Object Explorer (#1883)

- Fixes #1867 context menu should be extensible
- Added context keys to support "when" conditions on the new extensions
- Fixes issue where actions like New Query, scripting show up even if these are not valid for the provider type or object type
- Fixed node expansion bug where rapid connect / expand / disconnect could break the app (fix in ObjectExplorerService.onNodeExpanded)
- Major change to how internal actions work. These cannot assume the context has non-serializable objects. Opened up some APIs to make this easier to handle.
- Fixed a number of existing bugs in internal actions.
  - Notably, DisconnectAction was adding a listener on each right-click on an active connection and never getting it disposed. This wasn't needed at all due to design changes.
  - Another bug fix is that the Manage action now correctly navigates to the DB dashboard for database-level connections. Before this it went to the server-level dashboard.

* Define API for context info
This commit is contained in:
Kevin Cunnane
2018-07-10 12:23:47 -07:00
committed by GitHub
parent 0f0b959e14
commit d51a7a9eb7
24 changed files with 397 additions and 333 deletions

View File

@@ -29,19 +29,22 @@ export class TabComponent implements OnDestroy {
@Input() public identifier: string;
@Input() private visibilityType: 'if' | 'visibility' = 'if';
private rendered = false;
private destroyed: boolean = false;
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef
) { }
public set active(val: boolean) {
this._active = val;
if (this.active) {
this.rendered = true;
}
this._cd.detectChanges();
if (this.active && this._child) {
this._child.layout();
if (!this.destroyed) {
this._active = val;
if (this.active) {
this.rendered = true;
}
this._cd.detectChanges();
if (this.active && this._child) {
this._child.layout();
}
}
}
@@ -50,6 +53,7 @@ export class TabComponent implements OnDestroy {
}
ngOnDestroy() {
this.destroyed = true;
if (this.actions && this.actions.length > 0) {
this.actions.forEach((action) => action.dispose());
}

View File

@@ -13,3 +13,6 @@ export const SerializationDisabled = 'Saving results into different format disab
*/
export const RestoreFeatureName = 'restore';
export const BackupFeatureName = 'backup';
export const MssqlProviderId = 'MSSQL';

View File

@@ -8,7 +8,7 @@
import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IConnectionProfile } from 'sqlops';
export class ConnectionContextkey implements IContextKey<IConnectionProfile> {
export class ConnectionContextKey implements IContextKey<IConnectionProfile> {
static Provider = new RawContextKey<string>('connectionProvider', undefined);
static Server = new RawContextKey<string>('serverName', undefined);
@@ -23,10 +23,10 @@ export class ConnectionContextkey implements IContextKey<IConnectionProfile> {
constructor(
@IContextKeyService contextKeyService: IContextKeyService
) {
this._providerKey = ConnectionContextkey.Provider.bindTo(contextKeyService);
this._serverKey = ConnectionContextkey.Server.bindTo(contextKeyService);
this._databaseKey = ConnectionContextkey.Database.bindTo(contextKeyService);
this._connectionKey = ConnectionContextkey.Connection.bindTo(contextKeyService);
this._providerKey = ConnectionContextKey.Provider.bindTo(contextKeyService);
this._serverKey = ConnectionContextKey.Server.bindTo(contextKeyService);
this._databaseKey = ConnectionContextKey.Database.bindTo(contextKeyService);
this._connectionKey = ConnectionContextKey.Connection.bindTo(contextKeyService);
}
set(value: IConnectionProfile) {

View File

@@ -174,7 +174,7 @@ export interface IConnectionManagementService {
disconnectEditor(owner: IConnectableInput, force?: boolean): Promise<boolean>;
disconnect(connection: ConnectionProfile): Promise<void>;
disconnect(connection: IConnectionProfile): Promise<void>;
disconnect(ownerUri: string): Promise<void>;
@@ -208,7 +208,7 @@ export interface IConnectionManagementService {
*/
cancelEditorConnection(owner: IConnectableInput): Thenable<boolean>;
showDashboard(connection: ConnectionProfile): Thenable<boolean>;
showDashboard(connection: IConnectionProfile): Thenable<boolean>;
closeDashboard(uri: string): void;
@@ -216,7 +216,7 @@ export interface IConnectionManagementService {
hasRegisteredServers(): boolean;
canChangeConnectionConfig(profile: ConnectionProfile, newGroupID: string): boolean;
canChangeConnectionConfig(profile: IConnectionProfile, newGroupID: string): boolean;
getTabColorForUri(uri: string): string;

View File

@@ -553,7 +553,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
});
}
public showDashboard(connection: ConnectionProfile): Thenable<boolean> {
public showDashboard(connection: IConnectionProfile): Thenable<boolean> {
return this.showDashboardForConnectionManagementInfo(connection);
}

View File

@@ -240,7 +240,7 @@ export class ConnectionStore {
return connectionProfile;
} else {
return undefined;
};
}
});
}
@@ -352,7 +352,7 @@ export class ConnectionStore {
list.unshift(savedProfile);
let newList = list.map(c => {
let connectionProfile = c ? c.toIConnectionProfile() : undefined;;
let connectionProfile = c ? c.toIConnectionProfile() : undefined;
return connectionProfile;
});
return newList.filter(n => n !== undefined);
@@ -372,7 +372,7 @@ export class ConnectionStore {
});
let newList = list.map(c => {
let connectionProfile = c ? c.toIConnectionProfile() : undefined;;
let connectionProfile = c ? c.toIConnectionProfile() : undefined;
return connectionProfile;
});
return newList.filter(n => n !== undefined);

View File

@@ -18,7 +18,7 @@ import { DashboardModule } from './dashboard.module';
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
import { IDashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { DASHBOARD_SELECTOR } from 'sql/parts/dashboard/dashboard.component';
import { ConnectionContextkey } from 'sql/parts/connection/common/connectionContextKey';
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
@@ -110,7 +110,7 @@ export class DashboardEditor extends BaseEditor {
let serverInfo = this._connMan.getConnectionInfo(this.input.uri).serverInfo;
this._dashboardService.changeToDashboard({ profile, serverInfo });
let scopedContextService = this._contextKeyService.createScoped(input.container);
let connectionContextKey = new ConnectionContextkey(scopedContextService);
let connectionContextKey = new ConnectionContextKey(scopedContextService);
connectionContextKey.set(input.connectionProfile);
let params: IDashboardComponentParams = {

View File

@@ -162,10 +162,16 @@ export class ObjectExplorerService implements IObjectExplorerService {
error(expandResponse.errorMessage);
}
let nodeStatus = this._sessions[expandResponse.sessionId].nodes[expandResponse.nodePath];
if (nodeStatus && nodeStatus.expandEmitter) {
nodeStatus.expandEmitter.fire(expandResponse);
} else {
let sessionStatus = this._sessions[expandResponse.sessionId];
let foundSession = false;
if (sessionStatus) {
let nodeStatus = this._sessions[expandResponse.sessionId].nodes[expandResponse.nodePath];
foundSession = !!nodeStatus;
if (foundSession && nodeStatus.expandEmitter) {
nodeStatus.expandEmitter.fire(expandResponse);
}
}
if (!foundSession) {
warn(`Cannot find node status for session: ${expandResponse.sessionId} and node path: ${expandResponse.nodePath}`);
}
}

View File

@@ -33,7 +33,7 @@ export class RefreshAction extends Action {
id: string,
label: string,
tree: ITree,
private element: ConnectionProfile | TreeNode,
private element: IConnectionProfile | TreeNode,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IErrorMessageService private _errorMessageService: IErrorMessageService
@@ -88,80 +88,31 @@ export class DisconnectConnectionAction extends Action {
public static ID = 'objectExplorer.disconnect';
public static LABEL = localize('DisconnectAction', 'Disconnect');
private _disposables: IDisposable[] = [];
private _connectionProfile: ConnectionProfile;
private _container: HTMLElement;
constructor(
id: string,
label: string,
private _connectionProfile: ConnectionProfile,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IErrorMessageService private _errorMessageService: IErrorMessageService
) {
super(id, label);
const self = this;
this._disposables.push(this._connectionManagementService.onConnect(() => {
self.setLabel();
})
);
this._disposables.push(this._connectionManagementService.onDisconnect((disconnectParams) => {
if (this._connectionProfile) {
this._connectionProfile.isDisconnecting = false;
}
self.setLabel();
self._connectionManagementService.closeDashboard(disconnectParams.connectionUri);
})
);
if (this._objectExplorerService && this._objectExplorerService.onUpdateObjectExplorerNodes) {
this._disposables.push(this._objectExplorerService.onUpdateObjectExplorerNodes((args) => {
self.removeSpinning(args.connection);
if (args.errorMessage !== undefined) {
self.showError(args.errorMessage);
}
})
);
}
}
private showError(errorMessage: string) {
if (this._errorMessageService) {
this._errorMessageService.showDialog(Severity.Error, '', errorMessage);
}
}
private setLabel(): void {
if (!this._connectionProfile) {
this.label = 'Connect';
return;
}
this.label = this._connectionManagementService.isProfileConnected(this._connectionProfile) ? 'Disconnect' : 'Connect';
}
private removeSpinning(connection: IConnectionProfile): void {
if (this._connectionProfile) {
if (connection.id === this._connectionProfile.id && this._container) {
ObjectExplorerActionUtilities.hideLoadingIcon(this._container, ObjectExplorerActionUtilities.connectionElementClass);
}
}
}
run(actionContext: ObjectExplorerActionsContext): TPromise<any> {
return new TPromise<boolean>((resolve, reject) => {
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._connectionProfile = actionContext.connectionProfile;
this._container = actionContext.container;
resolve(true);
}
if (!this._connectionProfile) {
resolve(true);
}
if (this._connectionManagementService.isProfileConnected(this._connectionProfile)) {
this._connectionProfile.isDisconnecting = true;
let profileImpl = this._connectionProfile as ConnectionProfile;
if (profileImpl) {
profileImpl.isDisconnecting = true;
}
this._connectionManagementService.disconnect(this._connectionProfile).then((value) => {
if (profileImpl) {
profileImpl.isDisconnecting = false;
}
resolve(true);
}
).catch(disconnectError => {
@@ -172,11 +123,6 @@ export class DisconnectConnectionAction extends Action {
}
});
}
dispose(): void {
super.dispose();
this._disposables = dispose(this._disposables);
}
}
@@ -362,11 +308,11 @@ export class RecentConnectionsFilterAction extends Action {
export class NewQueryAction extends Action {
public static ID = 'registeredServers.newQuery';
public static LABEL = localize('registeredServers.newQuery', 'New Query');
private _connectionProfile: ConnectionProfile;
get connectionProfile(): ConnectionProfile {
private _connectionProfile: IConnectionProfile;
get connectionProfile(): IConnectionProfile {
return this._connectionProfile;
}
set connectionProfile(profile: ConnectionProfile) {
set connectionProfile(profile: IConnectionProfile) {
this._connectionProfile = profile;
}
@@ -403,7 +349,7 @@ export class DeleteConnectionAction extends Action {
constructor(
id: string,
label: string,
private element: ConnectionProfile | ConnectionProfileGroup,
private element: IConnectionProfile | ConnectionProfileGroup,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
) {
super(id, label);
@@ -413,7 +359,6 @@ export class DeleteConnectionAction extends Action {
}
if (element instanceof ConnectionProfile) {
element = <ConnectionProfile>element;
let parent: ConnectionProfileGroup = element.parent;
if (parent && parent.id === Constants.unsavedGroupId) {
this.enabled = false;

View File

@@ -8,11 +8,14 @@ import { localize } from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { ExecuteCommandAction } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import * as sqlops from 'sqlops';
import { IConnectionManagementService, IConnectionCompletionOptions, IErrorMessageService } from 'sql/parts/connection/common/connectionManagement';
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import {
NewQueryAction, ScriptSelectAction, EditDataAction, ScriptCreateAction,
ScriptSelectAction, EditDataAction, ScriptCreateAction,
ScriptExecuteAction, ScriptDeleteAction, ScriptAlterAction
} from 'sql/workbench/common/actions';
import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
@@ -23,41 +26,51 @@ import { IScriptingService } from 'sql/services/scripting/scriptingService';
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
import * as Constants from 'sql/parts/connection/common/constants';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ExecuteCommandAction } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
export class ObjectExplorerActionsContext {
public treeNode: TreeNode;
public connectionProfile: ConnectionProfile;
public container: HTMLElement;
public tree: ITree;
export class ObjectExplorerActionsContext implements sqlops.ObjectExplorerContext {
public connectionProfile: IConnectionProfile;
public nodeInfo: sqlops.NodeInfo;
public isConnectionNode: boolean = false;
}
async function getTreeNode(context: ObjectExplorerActionsContext, objectExplorerService: IObjectExplorerService): TPromise<TreeNode> {
if (context.isConnectionNode) {
return Promise.resolve(undefined);
}
return await objectExplorerService.getTreeNode(context.connectionProfile.id, context.nodeInfo.nodePath);
}
export class OEAction extends ExecuteCommandAction {
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
id: string, label: string,
@IInstantiationService private _instantiationService: IInstantiationService,
@ICommandService commandService: ICommandService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService
) {
super(id, label, commandService);
}
public run(actionContext: any): TPromise<boolean> {
public async run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
let profile: IConnectionProfile;
if (actionContext.connectionProfile) {
profile = actionContext.connectionProfile;
} else {
profile = TreeUpdateUtils.getConnectionProfile(<TreeNode>actionContext.treeNode);
if (actionContext instanceof ObjectExplorerActionsContext) {
if (actionContext.isConnectionNode) {
profile = actionContext.connectionProfile;
} else {
// Get the "correct" version from the tree
let treeNode = await getTreeNode(actionContext, this._objectExplorerService);
profile = TreeUpdateUtils.getConnectionProfile(treeNode);
}
}
this._treeSelectionHandler.onTreeActionStateChange(true);
@@ -72,18 +85,16 @@ export class ManageConnectionAction extends Action {
public static ID = 'objectExplorer.manage';
public static LABEL = localize('ManageAction', 'Manage');
private _connectionProfile: ConnectionProfile;
private _objectExplorerTreeNode: TreeNode;
private _treeSelectionHandler: TreeSelectionHandler;
protected _container: HTMLElement;
constructor(
id: string,
label: string,
private _tree: ITree,
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
@ICapabilitiesService protected _capabilitiesService: ICapabilitiesService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IObjectExplorerService private _objectExplorerService?: IObjectExplorerService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService
) {
super(id, label);
}
@@ -91,33 +102,37 @@ export class ManageConnectionAction extends Action {
run(actionContext: ObjectExplorerActionsContext): TPromise<any> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
this._treeSelectionHandler.onTreeActionStateChange(true);
let self = this;
let promise = new TPromise<boolean>((resolve, reject) => {
this.doManage(actionContext).then((success) => {
this.done();
self.doManage(actionContext).then((success) => {
self.done();
resolve(success);
}, error => {
this.done();
self.done();
reject(error);
});
});
return promise;
}
private doManage(actionContext: ObjectExplorerActionsContext): Thenable<boolean> {
private async doManage(actionContext: ObjectExplorerActionsContext): TPromise<boolean> {
let treeNode: TreeNode = undefined;
let connectionProfile: IConnectionProfile = undefined;
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._connectionProfile = actionContext.connectionProfile;
this._objectExplorerTreeNode = actionContext.treeNode;
if (this._connectionProfile === undefined && TreeUpdateUtils.isDatabaseNode(this._objectExplorerTreeNode)) {
this._connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
// Must use a real connection profile for this action due to lookup
connectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, actionContext.connectionProfile);
if (!actionContext.isConnectionNode) {
treeNode = await getTreeNode(actionContext, this._objectExplorerService);
if (TreeUpdateUtils.isDatabaseNode(treeNode)) {
connectionProfile = TreeUpdateUtils.getConnectionProfile(treeNode);
}
}
this._container = actionContext.container;
}
if (!this._connectionProfile) {
if (!connectionProfile) {
// This should never happen. There should be always a valid connection if the manage action is called for
// an OE node or a database node
return TPromise.wrap(true);
return true;
}
let options: IConnectionCompletionOptions = {
@@ -130,10 +145,10 @@ export class ManageConnectionAction extends Action {
// If it's a database node just open a database connection and open dashboard,
// the node is already from an open OE session we don't need to create new session
if (TreeUpdateUtils.isAvailableDatabaseNode(this._objectExplorerTreeNode)) {
return this._connectionManagementService.showDashboard(this._connectionProfile);
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
return this._connectionManagementService.showDashboard(connectionProfile);
} else {
return TreeUpdateUtils.connectAndCreateOeSession(this._connectionProfile, options, this._connectionManagementService, this._objectExplorerService, actionContext.tree);
return TreeUpdateUtils.connectAndCreateOeSession(connectionProfile, options, this._connectionManagementService, this._objectExplorerService, this._tree);
}
}
@@ -149,7 +164,6 @@ export class ManageConnectionAction extends Action {
export class OEScriptSelectAction extends ScriptSelectAction {
public static ID = 'objectExplorer.' + ScriptSelectAction.ID;
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
@@ -157,23 +171,23 @@ export class OEScriptSelectAction extends ScriptSelectAction {
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
@IScriptingService protected _scriptingService: IScriptingService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IInstantiationService private _instantiationService: IInstantiationService
) {
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService);
}
public run(actionContext: any): TPromise<boolean> {
public async run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._objectExplorerTreeNode = actionContext.treeNode;
this._container = actionContext.container;
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
}
this._treeSelectionHandler.onTreeActionStateChange(true);
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
var connectionProfile = TreeUpdateUtils.getConnectionProfile(this._objectExplorerTreeNode);
var ownerUri = this._connectionManagementService.getConnectionId(connectionProfile);
ownerUri = this._connectionManagementService.getFormattedUri(ownerUri, connectionProfile);
var metadata = (<TreeNode>this._objectExplorerTreeNode).metadata;
var metadata = this._objectExplorerTreeNode.metadata;
return super.run({ profile: connectionProfile, object: metadata }).then((result) => {
this._treeSelectionHandler.onTreeActionStateChange(false);
@@ -185,7 +199,6 @@ export class OEScriptSelectAction extends ScriptSelectAction {
export class OEEditDataAction extends EditDataAction {
public static ID = 'objectExplorer.' + EditDataAction.ID;
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
@@ -193,17 +206,17 @@ export class OEEditDataAction extends EditDataAction {
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
@IScriptingService protected _scriptingService: IScriptingService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IInstantiationService private _instantiationService: IInstantiationService
) {
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService);
}
public run(actionContext: any): TPromise<boolean> {
public async run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._objectExplorerTreeNode = actionContext.treeNode;
this._container = actionContext.container;
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
}
this._treeSelectionHandler.onTreeActionStateChange(true);
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
@@ -219,7 +232,6 @@ export class OEEditDataAction extends EditDataAction {
export class OEScriptCreateAction extends ScriptCreateAction {
public static ID = 'objectExplorer.' + ScriptCreateAction.ID;
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
@@ -227,18 +239,18 @@ export class OEScriptCreateAction extends ScriptCreateAction {
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
@IScriptingService protected _scriptingService: IScriptingService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IErrorMessageService protected _errorMessageService: IErrorMessageService
) {
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
}
public run(actionContext: any): TPromise<boolean> {
public async run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._objectExplorerTreeNode = actionContext.treeNode;
this._container = actionContext.container;
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
}
this._treeSelectionHandler.onTreeActionStateChange(true);
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
@@ -256,7 +268,6 @@ export class OEScriptCreateAction extends ScriptCreateAction {
export class OEScriptExecuteAction extends ScriptExecuteAction {
public static ID = 'objectExplorer.' + ScriptExecuteAction.ID;
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
@@ -264,18 +275,18 @@ export class OEScriptExecuteAction extends ScriptExecuteAction {
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
@IScriptingService protected _scriptingService: IScriptingService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IErrorMessageService protected _errorMessageService: IErrorMessageService
) {
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
}
public run(actionContext: any): TPromise<boolean> {
public async run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._objectExplorerTreeNode = actionContext.treeNode;
this._container = actionContext.container;
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
}
this._treeSelectionHandler.onTreeActionStateChange(true);
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
@@ -293,7 +304,6 @@ export class OEScriptExecuteAction extends ScriptExecuteAction {
export class OEScriptAlterAction extends ScriptAlterAction {
public static ID = 'objectExplorer.' + ScriptAlterAction.ID;
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
@@ -301,18 +311,18 @@ export class OEScriptAlterAction extends ScriptAlterAction {
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
@IScriptingService protected _scriptingService: IScriptingService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IErrorMessageService protected _errorMessageService: IErrorMessageService
) {
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
}
public run(actionContext: any): TPromise<boolean> {
public async run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._objectExplorerTreeNode = actionContext.treeNode;
this._container = actionContext.container;
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
}
this._treeSelectionHandler.onTreeActionStateChange(true);
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
@@ -330,7 +340,6 @@ export class OEScriptAlterAction extends ScriptAlterAction {
export class OEScriptDeleteAction extends ScriptDeleteAction {
public static ID = 'objectExplorer.' + ScriptDeleteAction.ID;
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
@@ -338,18 +347,18 @@ export class OEScriptDeleteAction extends ScriptDeleteAction {
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
@IScriptingService protected _scriptingService: IScriptingService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IErrorMessageService protected _errorMessageService: IErrorMessageService
) {
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
}
public run(actionContext: any): TPromise<boolean> {
public async run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._objectExplorerTreeNode = actionContext.treeNode;
this._container = actionContext.container;
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
}
this._treeSelectionHandler.onTreeActionStateChange(true);
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
@@ -364,77 +373,11 @@ export class OEScriptDeleteAction extends ScriptDeleteAction {
}
}
export class DisconnectAction extends Action {
public static ID = 'objectExplorer.disconnect';
public static LABEL = localize('objectExplorAction.disconnect', 'Disconnect');
private _objectExplorerTreeNode: TreeNode;
private _container: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
constructor(
id: string,
label: string,
@IConnectionManagementService private connectionManagementService: IConnectionManagementService,
@IInstantiationService private _instantiationService: IInstantiationService
) {
super(id, label);
}
public run(actionContext: any): TPromise<boolean> {
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
if (actionContext instanceof ObjectExplorerActionsContext) {
//set objectExplorerTreeNode for context menu clicks
this._objectExplorerTreeNode = actionContext.treeNode;
this._container = actionContext.container;
}
var connectionProfile = (<TreeNode>this._objectExplorerTreeNode).getConnectionProfile();
if (this.connectionManagementService.isProfileConnected(connectionProfile)) {
this._treeSelectionHandler.onTreeActionStateChange(true);
this.connectionManagementService.disconnect(connectionProfile).then(() => {
this._treeSelectionHandler.onTreeActionStateChange(false);
});
}
return TPromise.as(true);
}
}
export class ObjectExplorerActionUtilities {
public static readonly objectExplorerElementClass = 'object-element-group';
public static readonly connectionElementClass = 'connection-tile';
private static getGroupContainer(container: HTMLElement, elementName: string): HTMLElement {
var element = container;
while (element && element.className !== elementName) {
element = element.parentElement;
}
return element ? element.parentElement : undefined;
}
public static showLoadingIcon(container: HTMLElement, elementName: string): void {
if (container) {
let groupContainer = this.getGroupContainer(container, elementName);
if (groupContainer) {
groupContainer.classList.add('icon');
groupContainer.classList.add('in-progress');
}
}
}
public static hideLoadingIcon(container: HTMLElement, elementName: string): void {
if (container) {
let element = this.getGroupContainer(container, elementName);
if (element && element.classList) {
element.classList.remove('icon');
element.classList.remove('in-progress');
}
}
}
public static getScriptMap(treeNode: TreeNode): Map<NodeType, any[]> {
let scriptMap = new Map<NodeType, any[]>();

View File

@@ -9,6 +9,8 @@ import { ITree } from 'vs/base/parts/tree/browser/tree';
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
import { IAction } from 'vs/base/common/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
import {
DisconnectConnectionAction, AddServerAction,
@@ -16,9 +18,7 @@ import {
}
from 'sql/parts/objectExplorer/viewlet/connectionTreeAction';
import {
DisconnectAction, ObjectExplorerActionUtilities,
ManageConnectionAction,
OEAction
ObjectExplorerActionUtilities, ManageConnectionAction, OEAction
} from 'sql/parts/objectExplorer/viewlet/objectExplorerActions';
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
@@ -27,8 +27,14 @@ import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile
import { NewProfilerAction } from 'sql/parts/profiler/contrib/profilerActions';
import { TreeUpdateUtils } from 'sql/parts/objectExplorer/viewlet/treeUpdateUtils';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import { ExecuteCommandAction } from 'vs/platform/actions/common/actions';
import { MenuId, IMenuService } from 'vs/platform/actions/common/actions';
import { NewQueryAction } from 'sql/workbench/common/actions';
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { TreeNodeContextKey } from './treeNodeContextKey';
import { IQueryManagementService } from 'sql/parts/query/common/queryManagement';
import { IScriptingService } from 'sql/services/scripting/scriptingService';
import * as constants from 'sql/common/constants';
/**
* Provides actions for the server tree elements
@@ -37,7 +43,12 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IQueryManagementService private _queryManagementService: IQueryManagementService,
@IScriptingService private _scriptingService: IScriptingService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IMenuService private menuService: IMenuService,
@IContextKeyService private _contextKeyService: IContextKeyService
) {
super();
}
@@ -57,8 +68,11 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
return TPromise.as(this.getConnectionProfileGroupActions(tree, element));
}
if (element instanceof TreeNode) {
var treeNode = <TreeNode>element;
return TPromise.as(this.getObjectExplorerNodeActions(tree, treeNode));
return TPromise.as(this.getObjectExplorerNodeActions({
tree: tree,
profile: element.getConnectionProfile(),
treeNode: element
}));
}
return TPromise.as([]);
@@ -75,23 +89,58 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
/**
* Return actions for connection elements
*/
public getConnectionActions(tree: ITree, element: ConnectionProfile): IAction[] {
let actions: IAction[] = [];
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL));
actions.push(this._instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL));
if (this._connectionManagementService.isProfileConnected(element)) {
actions.push(this._instantiationService.createInstance(DisconnectConnectionAction, DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL));
}
actions.push(this._instantiationService.createInstance(DeleteConnectionAction, DeleteConnectionAction.ID, DeleteConnectionAction.DELETE_CONNECTION_LABEL, element));
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, tree, element));
public getConnectionActions(tree: ITree, profile: ConnectionProfile): IAction[] {
return this.getAllActions({
tree: tree,
profile: profile
}, (context) => this.getBuiltinConnectionActions(context));
}
if (process.env['VSCODE_DEV']) {
private getAllActions(context: ObjectExplorerContext, getDefaultActions: (ObjectExplorerContext) => IAction[]) {
// Create metadata needed to get a useful set of actions
let scopedContextService = this.getContextKeyService(context);
let menu = this.menuService.createMenu(MenuId.ObjectExplorerItemContext, scopedContextService);
// Fill in all actions
let actions = getDefaultActions(context);
fillInActions(menu, { arg: undefined, shouldForwardArgs: true }, actions, this.contextMenuService);
// Cleanup
scopedContextService.dispose();
menu.dispose();
return actions;
}
private getBuiltinConnectionActions(context: ObjectExplorerContext): IAction[] {
let actions: IAction[] = [];
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree));
this.addNewQueryAction(context, actions);
if (this._connectionManagementService.isProfileConnected(context.profile)) {
actions.push(this._instantiationService.createInstance(DisconnectConnectionAction, DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL, context.profile));
}
actions.push(this._instantiationService.createInstance(DeleteConnectionAction, DeleteConnectionAction.ID, DeleteConnectionAction.DELETE_CONNECTION_LABEL, context.profile));
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, context.profile));
if (process.env['VSCODE_DEV'] && constants.MssqlProviderId === context.profile.providerName) {
actions.push(this._instantiationService.createInstance(OEAction, NewProfilerAction.ID, NewProfilerAction.LABEL));
}
return actions;
}
private getContextKeyService(context: ObjectExplorerContext): IContextKeyService {
let scopedContextService = this._contextKeyService.createScoped();
let connectionContextKey = new ConnectionContextKey(scopedContextService);
connectionContextKey.set(context.profile);
let treeNodeContextKey = new TreeNodeContextKey(scopedContextService);
if (context.treeNode) {
treeNodeContextKey.set(context.treeNode);
}
return scopedContextService;
}
/**
* Return actions for connection group elements
*/
@@ -106,32 +155,50 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
/**
* Return actions for OE elements
*/
public getObjectExplorerNodeActions(tree: ITree, treeNode: TreeNode): IAction[] {
let actions = [];
private getObjectExplorerNodeActions(context: ObjectExplorerContext): IAction[] {
return this.getAllActions(context, (context) => this.getBuiltInNodeActions(context));
}
private getBuiltInNodeActions(context: ObjectExplorerContext): IAction[] {
let actions: IAction[] = [];
let treeNode = context.treeNode;
if (TreeUpdateUtils.isDatabaseNode(treeNode)) {
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL));
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree));
} else {
return actions;
}
}
actions.push(this._instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL));
let scriptMap: Map<NodeType, any[]> = ObjectExplorerActionUtilities.getScriptMap(treeNode);
let supportedActions = scriptMap.get(treeNode.nodeTypeId);
let self = this;
if (supportedActions !== null && supportedActions !== undefined) {
supportedActions.forEach(action => {
actions.push(self._instantiationService.createInstance(action, action.ID, action.LABEL));
});
}
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, tree, treeNode));
if (treeNode.isTopLevel()) {
actions.push(this._instantiationService.createInstance(DisconnectAction, DisconnectAction.ID, DisconnectAction.LABEL));
}
this.addNewQueryAction(context, actions);
this.addScriptingActions(context, actions);
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, treeNode));
return actions;
}
private addNewQueryAction(context: ObjectExplorerContext, actions: IAction[]): void {
if (this._queryManagementService.isProviderRegistered(context.profile.providerName)) {
actions.push(this._instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL));
}
}
private addScriptingActions(context: ObjectExplorerContext, actions: IAction[]): void {
if (this._scriptingService.isProviderRegistered(context.profile.providerName)) {
let scriptMap: Map<NodeType, any[]> = ObjectExplorerActionUtilities.getScriptMap(context.treeNode);
let supportedActions = scriptMap.get(context.treeNode.nodeTypeId);
let self = this;
if (supportedActions !== null && supportedActions !== undefined) {
supportedActions.forEach(action => {
actions.push(self._instantiationService.createInstance(action, action.ID, action.LABEL));
});
}
}
}
}
interface ObjectExplorerContext {
tree: ITree;
profile: ConnectionProfile;
treeNode?: TreeNode;
}

View File

@@ -73,26 +73,21 @@ export class ServerTreeController extends treedefaults.DefaultController {
event.stopPropagation();
tree.setFocus(element);
let parent: ConnectionProfileGroup = undefined;
if (element instanceof ConnectionProfileGroup) {
parent = <ConnectionProfileGroup>element;
}
else if (element instanceof ConnectionProfile) {
parent = (<ConnectionProfile>element).parent;
}
var actionContext: any;
if (element instanceof TreeNode) {
actionContext = new ObjectExplorerActionsContext();
actionContext.container = event.target;
actionContext.treeNode = <TreeNode>element;
actionContext.tree = tree;
let context = new ObjectExplorerActionsContext();
context.nodeInfo = element.toNodeInfo();
context.connectionProfile = element.getConnectionProfile().toIConnectionProfile();
actionContext = context;
} else if (element instanceof ConnectionProfile) {
actionContext = new ObjectExplorerActionsContext();
actionContext.container = event.target;
actionContext.connectionProfile = <ConnectionProfile>element;
actionContext.tree = tree;
let context = new ObjectExplorerActionsContext();
context.connectionProfile = element.toIConnectionProfile();
context.isConnectionNode = true;
actionContext = context;
} else {
// TODO: because the connection group is used as a context object and isn't serializable,
// the Group-level context menu is not currently extensible
actionContext = element;
}

View File

@@ -31,12 +31,10 @@ export class ServerTreeDataSource implements IDataSource {
* No more than one element may use a given identifier.
*/
public getId(tree: ITree, element: any): string {
if (element instanceof ConnectionProfile) {
return (<ConnectionProfile>element).id;
} else if (element instanceof ConnectionProfileGroup) {
return (<ConnectionProfileGroup>element).id;
} else if (element instanceof TreeNode) {
return (<TreeNode>element).id;
if (element instanceof ConnectionProfile
|| element instanceof ConnectionProfileGroup
|| element instanceof TreeNode) {
return element.id;
} else {
return undefined;
}
@@ -49,9 +47,9 @@ export class ServerTreeDataSource implements IDataSource {
if (element instanceof ConnectionProfile) {
return true;
} else if (element instanceof ConnectionProfileGroup) {
return (<ConnectionProfileGroup>element).hasChildren();
return element.hasChildren();
} else if (element instanceof TreeNode) {
return !(<TreeNode>element).isAlwaysLeaf;
return !element.isAlwaysLeaf;
}
return false;
}
@@ -70,7 +68,7 @@ export class ServerTreeDataSource implements IDataSource {
} else if (element instanceof ConnectionProfileGroup) {
resolve((<ConnectionProfileGroup>element).getChildren());
} else if (element instanceof TreeNode) {
var node = <TreeNode>element;
var node = element;
if (node.children) {
resolve(node.children);
} else {
@@ -92,11 +90,11 @@ export class ServerTreeDataSource implements IDataSource {
*/
public getParent(tree: ITree, element: any): TPromise<any> {
if (element instanceof ConnectionProfile) {
return TPromise.as((<ConnectionProfile>element).getParent());
return TPromise.as(element.getParent());
} else if (element instanceof ConnectionProfileGroup) {
return TPromise.as((<ConnectionProfileGroup>element).getParent());
return TPromise.as(element.getParent());
} else if (element instanceof TreeNode) {
return TPromise.as(TreeUpdateUtils.getObjectExplorerParent(<TreeNode>element, this._connectionManagementService));
return TPromise.as(TreeUpdateUtils.getObjectExplorerParent(element, this._connectionManagementService));
} else {
return TPromise.as(null);
}

View File

@@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------------------------
* 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 { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IConnectionProfile } from 'sqlops';
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
export class TreeNodeContextKey implements IContextKey<TreeNode> {
static NodeType = new RawContextKey<string>('nodeType', undefined);
static SubType = new RawContextKey<string>('nodeSubType', undefined);
static Status = new RawContextKey<string>('nodeStatus', undefined);
static TreeNode = new RawContextKey<TreeNode>('treeNode', undefined);
private _nodeTypeKey: IContextKey<string>;
private _subTypeKey: IContextKey<string>;
private _statusKey: IContextKey<string>;
private _treeNodeKey: IContextKey<TreeNode>;
constructor(
@IContextKeyService contextKeyService: IContextKeyService
) {
this._nodeTypeKey = TreeNodeContextKey.NodeType.bindTo(contextKeyService);
this._subTypeKey = TreeNodeContextKey.SubType.bindTo(contextKeyService);
this._statusKey = TreeNodeContextKey.Status.bindTo(contextKeyService);
this._treeNodeKey = TreeNodeContextKey.TreeNode.bindTo(contextKeyService);
}
set(value: TreeNode) {
this._treeNodeKey.set(value);
this._nodeTypeKey.set(value && value.nodeTypeId);
this._subTypeKey.set(value && value.nodeSubType);
this._statusKey.set(value && value.nodeStatus);
}
reset(): void {
this._nodeTypeKey.reset();
this._subTypeKey.reset();
this._statusKey.reset();
this._treeNodeKey.reset();
}
public get(): TreeNode {
return this._treeNodeKey.get();
}
}

View File

@@ -104,7 +104,7 @@ export class TreeSelectionHandler {
});
}
} else if (isDoubleClick && selection && selection.length > 0 && (selection[0] instanceof TreeNode)) {
let treeNode = <TreeNode>selection[0];
let treeNode = selection[0];
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
connectionProfile = TreeUpdateUtils.getConnectionProfile(treeNode);
if (connectionProfile) {

View File

@@ -13,6 +13,7 @@ import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
import { TPromise } from 'vs/base/common/winjs.base';
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
import errors = require('vs/base/common/errors');
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
export class TreeUpdateUtils {
@@ -113,7 +114,7 @@ export class TreeUpdateUtils {
}
public static connectIfNotConnected(
connection: ConnectionProfile,
connection: IConnectionProfile,
options: IConnectionCompletionOptions,
connectionManagementService: IConnectionManagementService,
tree: ITree): TPromise<ConnectionProfile> {
@@ -172,7 +173,7 @@ export class TreeUpdateUtils {
* @param connectionManagementService Connection management service instance
* @param objectExplorerService Object explorer service instance
*/
public static connectAndCreateOeSession(connection: ConnectionProfile, options: IConnectionCompletionOptions,
public static connectAndCreateOeSession(connection: IConnectionProfile, options: IConnectionCompletionOptions,
connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, tree: ITree): TPromise<boolean> {
return new TPromise<boolean>((resolve, reject) => {
TreeUpdateUtils.connectIfNotConnected(connection, options, connectionManagementService, tree).then(connectedConnection => {

View File

@@ -21,6 +21,7 @@ export interface IQueryManagementService {
_serviceBrand: any;
addQueryRequestHandler(queryType: string, runner: IQueryRequestHandler): IDisposable;
isProviderRegistered(providerId: string): boolean;
registerRunner(runner: QueryRunner, uri: string): void;
cancelQuery(ownerUri: string): Thenable<sqlops.QueryCancelResult>;
@@ -82,7 +83,6 @@ export interface IQueryRequestHandler {
}
export class QueryManagementService implements IQueryManagementService {
public static readonly DefaultQueryType = 'MSSQL';
public _serviceBrand: any;
private _requestHandlers = new Map<string, IQueryRequestHandler>();
@@ -143,6 +143,11 @@ export class QueryManagementService implements IQueryManagementService {
};
}
public isProviderRegistered(providerId: string): boolean {
let handler = this._requestHandlers.get(providerId);
return !!handler;
}
private addTelemetry(eventName: string, ownerUri: string, runOptions?: sqlops.ExecutionPlanOptions): void {
let providerId: string = this._connectionService.getProviderIdFromUri(ownerUri);
let data: TelemetryUtils.IConnectionTelemetryData = {

View File

@@ -6,7 +6,7 @@
import { DataService } from 'sql/parts/grid/services/dataService';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { ConnectionContextkey } from 'sql/parts/connection/common/connectionContextKey';
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
import { IBootstrapParams } from './bootstrapService';
export interface IQueryComponentParams extends IBootstrapParams {
@@ -21,7 +21,7 @@ export interface IDefaultComponentParams extends IBootstrapParams {
connection: IConnectionProfile;
ownerUri: string;
scopedContextService: IContextKeyService;
connectionContextKey: ConnectionContextkey;
connectionContextKey: ConnectionContextKey;
}
export interface IDashboardComponentParams extends IDefaultComponentParams {

View File

@@ -17,7 +17,7 @@ import { IAdminService } from 'sql/parts/admin/common/adminService';
import { IQueryManagementService } from 'sql/parts/query/common/queryManagement';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { AngularDisposable } from 'sql/base/common/lifecycle';
import { ConnectionContextkey } from 'sql/parts/connection/common/connectionContextKey';
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
import { ProviderMetadata, DatabaseInfo, SimpleExecuteResult } from 'sqlops';
@@ -47,7 +47,7 @@ export class SingleConnectionManagementService {
constructor(
private _connectionService: IConnectionManagementService,
private _uri: string,
private _contextKey: ConnectionContextkey
private _contextKey: ConnectionContextKey
) { }
public changeDatabase(name: string): Thenable<boolean> {
@@ -104,7 +104,7 @@ export class CommonServiceInterface extends AngularDisposable {
protected _singleQueryManagementService: SingleQueryManagementService;
public scopedContextKeyService: IContextKeyService;
protected _connectionContextKey: ConnectionContextkey;
protected _connectionContextKey: ConnectionContextKey;
constructor(
@Inject(IBootstrapParams) protected _params: IDefaultComponentParams,

View File

@@ -25,6 +25,11 @@ export interface IScriptingService {
*/
registerProvider(providerId: string, provider: sqlops.ScriptingProvider): void;
/**
* Specifies whether a provider with a given ID has been registered or not
*/
isProviderRegistered(providerId: string): boolean;
/**
* Callback method for when scripting is complete
*/
@@ -99,6 +104,11 @@ export class ScriptingService implements IScriptingService {
this._providers[providerId] = provider;
}
public isProviderRegistered(providerId: string): boolean {
let provider = this._providers[providerId];
return !!provider;
}
public dispose(): void {
this.disposables = dispose(this.disposables);
}

View File

@@ -973,4 +973,31 @@ declare module 'sqlops' {
*/
export function getProvidersByType<T extends DataProvider>(providerType: DataProviderType): T[];
}
/**
* Context object passed as an argument to command callbacks.
* Defines the key properties required to identify a node in the object
* explorer tree and take action against it.
*/
export interface ObjectExplorerContext {
/**
* The connection information for the selected object.
* Note that the connection is not guaranteed to be in a connected
* state on click.
*/
connectionProfile: IConnectionProfile;
/**
* Defines whether this is a Connection-level object.
* If not, the object is expected to be a child object underneath
* one of the connections.
*/
isConnectionNode: boolean;
/**
* Node info for objects below a specific connection. This
* may be null for a Connection-level object
*/
nodeInfo: NodeInfo;
}
}