mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 17:22:45 -05:00
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:
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[]>();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
50
src/sql/parts/objectExplorer/viewlet/treeNodeContextKey.ts
Normal file
50
src/sql/parts/objectExplorer/viewlet/treeNodeContextKey.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
27
src/sql/sqlops.proposed.d.ts
vendored
27
src/sql/sqlops.proposed.d.ts
vendored
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user