/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { IScriptingService } from 'sql/platform/scripting/common/scriptingService'; import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { TreeViewItemHandleArg } from 'sql/workbench/common/views'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { IOEShimService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerViewTreeShim'; import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService'; import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { BaseActionContext } from 'sql/workbench/browser/actions'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { ScriptCreateAction, ScriptDeleteAction, ScriptSelectAction, ScriptExecuteAction, ScriptAlterAction, EditDataAction } from 'sql/workbench/browser/scriptingActions'; import { ObjectExplorerActionsContext, getTreeNode } from 'sql/workbench/services/objectExplorer/browser/objectExplorerActions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService'; import { TreeSelectionHandler } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler'; import { TreeUpdateUtils } from 'sql/workbench/services/objectExplorer/browser/treeUpdateUtils'; import { VIEWLET_ID } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet'; import { ILogService } from 'vs/platform/log/common/log'; import { getErrorMessage } from 'vs/base/common/errors'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { localize } from 'vs/nls'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { AsyncServerTree } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree'; import { Action, toAction } from 'vs/base/common/actions'; //#region -- Data Explorer export const SCRIPT_AS_CREATE_COMMAND_ID = 'dataExplorer.scriptAsCreate'; export const SCRIPT_AS_DELETE_COMMAND_ID = 'dataExplorer.scriptAsDelete'; export const SCRIPT_AS_SELECT_COMMAND_ID = 'dataExplorer.scriptAsSelect'; export const SCRIPT_AS_EXECUTE_COMMAND_ID = 'dataExplorer.scriptAsExecute'; export const SCRIPT_AS_ALTER_COMMAND_ID = 'dataExplorer.scriptAsAlter'; export const EDIT_DATA_COMMAND_ID = 'dataExplorer.scriptAsEdit'; // Script as Create CommandsRegistry.registerCommand({ id: SCRIPT_AS_CREATE_COMMAND_ID, handler: async (accessor, args: TreeViewItemHandleArg): Promise => { if (args.$treeItem?.payload) { const capabilitiesService = accessor.get(ICapabilitiesService); const oeShimService = accessor.get(IOEShimService); const queryEditorService = accessor.get(IQueryEditorService); const connectionManagementService = accessor.get(IConnectionManagementService); const scriptingService = accessor.get(IScriptingService); const errorMessageService = accessor.get(IErrorMessageService); const progressService = accessor.get(IProgressService); const connectionService = accessor.get(IConnectionManagementService); let payload = await connectionService.fixProfile(args.$treeItem.payload); const profile = new ConnectionProfile(capabilitiesService, payload); const baseContext: BaseActionContext = { profile: profile, object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata }; const scriptCreateAction = new ScriptCreateAction(ScriptCreateAction.ID, ScriptCreateAction.LABEL, queryEditorService, connectionManagementService, scriptingService, errorMessageService); await progressService.withProgress({ location: VIEWLET_ID }, async () => await scriptCreateAction.run(baseContext)); } } }); // Script as Delete CommandsRegistry.registerCommand({ id: SCRIPT_AS_DELETE_COMMAND_ID, handler: async (accessor, args: TreeViewItemHandleArg): Promise => { if (args.$treeItem?.payload) { const capabilitiesService = accessor.get(ICapabilitiesService); const oeShimService = accessor.get(IOEShimService); const queryEditorService = accessor.get(IQueryEditorService); const connectionManagementService = accessor.get(IConnectionManagementService); const scriptingService = accessor.get(IScriptingService); const errorMessageService = accessor.get(IErrorMessageService); const progressService = accessor.get(IProgressService); const connectionService = accessor.get(IConnectionManagementService); let payload = await connectionService.fixProfile(args.$treeItem.payload); const profile = new ConnectionProfile(capabilitiesService, payload); const baseContext: BaseActionContext = { profile: profile, object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata }; const scriptDeleteAction = new ScriptDeleteAction(ScriptDeleteAction.ID, ScriptDeleteAction.LABEL, queryEditorService, connectionManagementService, scriptingService, errorMessageService); await progressService.withProgress({ location: VIEWLET_ID }, async () => await scriptDeleteAction.run(baseContext)); } } }); // Script as Select CommandsRegistry.registerCommand({ id: SCRIPT_AS_SELECT_COMMAND_ID, handler: async (accessor, args: TreeViewItemHandleArg): Promise => { if (args.$treeItem?.payload) { const capabilitiesService = accessor.get(ICapabilitiesService); const oeShimService = accessor.get(IOEShimService); const queryEditorService = accessor.get(IQueryEditorService); const connectionManagementService = accessor.get(IConnectionManagementService); const scriptingService = accessor.get(IScriptingService); const progressService = accessor.get(IProgressService); const errorMessageService = accessor.get(IErrorMessageService); const connectionService = accessor.get(IConnectionManagementService); let payload = await connectionService.fixProfile(args.$treeItem.payload); const profile = new ConnectionProfile(capabilitiesService, payload); const baseContext: BaseActionContext = { profile: profile, object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata }; const scriptSelectAction = new ScriptSelectAction(ScriptSelectAction.ID, ScriptSelectAction.LABEL, queryEditorService, connectionManagementService, scriptingService, errorMessageService); await progressService.withProgress({ location: VIEWLET_ID }, async () => await scriptSelectAction.run(baseContext)); } } }); // Script as Execute CommandsRegistry.registerCommand({ id: SCRIPT_AS_EXECUTE_COMMAND_ID, handler: async (accessor, args: TreeViewItemHandleArg): Promise => { if (args.$treeItem?.payload) { const capabilitiesService = accessor.get(ICapabilitiesService); const oeShimService = accessor.get(IOEShimService); const queryEditorService = accessor.get(IQueryEditorService); const connectionManagementService = accessor.get(IConnectionManagementService); const scriptingService = accessor.get(IScriptingService); const progressService = accessor.get(IProgressService); const errorMessageService = accessor.get(IErrorMessageService); const connectionService = accessor.get(IConnectionManagementService); let payload = await connectionService.fixProfile(args.$treeItem.payload); const profile = new ConnectionProfile(capabilitiesService, payload); const baseContext: BaseActionContext = { profile: profile, object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata }; const scriptExecuteAction = new ScriptExecuteAction(ScriptExecuteAction.ID, ScriptExecuteAction.LABEL, queryEditorService, connectionManagementService, scriptingService, errorMessageService); await progressService.withProgress({ location: VIEWLET_ID }, async () => await scriptExecuteAction.run(baseContext)); } } }); // Script as Alter CommandsRegistry.registerCommand({ id: SCRIPT_AS_ALTER_COMMAND_ID, handler: async (accessor, args: TreeViewItemHandleArg): Promise => { if (args.$treeItem?.payload) { const capabilitiesService = accessor.get(ICapabilitiesService); const oeShimService = accessor.get(IOEShimService); const queryEditorService = accessor.get(IQueryEditorService); const connectionManagementService = accessor.get(IConnectionManagementService); const scriptingService = accessor.get(IScriptingService); const progressService = accessor.get(IProgressService); const errorMessageService = accessor.get(IErrorMessageService); const connectionService = accessor.get(IConnectionManagementService); let payload = await connectionService.fixProfile(args.$treeItem.payload); const profile = new ConnectionProfile(capabilitiesService, payload); const baseContext: BaseActionContext = { profile: profile, object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata }; const scriptAlterAction = new ScriptAlterAction(ScriptAlterAction.ID, ScriptAlterAction.LABEL, queryEditorService, connectionManagementService, scriptingService, errorMessageService); await progressService.withProgress({ location: VIEWLET_ID }, async () => await scriptAlterAction.run(baseContext)); } } }); // Edit Data CommandsRegistry.registerCommand({ id: EDIT_DATA_COMMAND_ID, handler: async (accessor, args: TreeViewItemHandleArg): Promise => { if (args.$treeItem?.payload) { const capabilitiesService = accessor.get(ICapabilitiesService); const oeShimService = accessor.get(IOEShimService); const queryEditorService = accessor.get(IQueryEditorService); const connectionManagementService = accessor.get(IConnectionManagementService); const scriptingService = accessor.get(IScriptingService); const progressService = accessor.get(IProgressService); const errorMessageService = accessor.get(IErrorMessageService); const connectionService = accessor.get(IConnectionManagementService); let payload = await connectionService.fixProfile(args.$treeItem.payload); const profile = new ConnectionProfile(capabilitiesService, payload); const baseContext: BaseActionContext = { profile: profile, object: oeShimService.getNodeInfoForTreeItem(args.$treeItem)!.metadata }; const editDataAction = new EditDataAction(EditDataAction.ID, EditDataAction.LABEL, queryEditorService, connectionManagementService, scriptingService, errorMessageService); await progressService.withProgress({ location: VIEWLET_ID }, async () => await editDataAction.run(baseContext)); } } }); //#endregion //#region -- Object Explorer export const OE_SCRIPT_AS_CREATE_COMMAND_ID = 'objectExplorer.scriptAsCreate'; export const OE_SCRIPT_AS_DELETE_COMMAND_ID = 'objectExplorer.scriptAsDelete'; export const OE_SCRIPT_AS_SELECT_COMMAND_ID = 'objectExplorer.scriptAsSelect'; export const OE_SCRIPT_AS_EXECUTE_COMMAND_ID = 'objectExplorer.scriptAsExecute'; export const OE_SCRIPT_AS_ALTER_COMMAND_ID = 'objectExplorer.scriptAsAlter'; export const OE_EDIT_DATA_COMMAND_ID = 'objectExplorer.scriptAsEdit'; export const OE_REFRESH_COMMAND_ID = 'objectExplorer.refreshNode'; async function runScriptingAction(accessor: ServicesAccessor, args: ObjectExplorerActionsContext, createAction: (instantiationService: IInstantiationService) => Action): Promise { const instantiationService = accessor.get(IInstantiationService); const objectExplorerService = accessor.get(IObjectExplorerService); const notificationService = accessor.get(INotificationService); const logService = accessor.get(ILogService); const selectionHandler = instantiationService.createInstance(TreeSelectionHandler); const notificationHandle = notificationService.notify({ message: localize('scriptingAction.inProgress', "Executing action..."), severity: Severity.Info, progress: { infinite: true } }); try { const node = (await getTreeNode(args, objectExplorerService))!; selectionHandler.onTreeActionStateChange(true); let connectionProfile = TreeUpdateUtils.getConnectionProfile(node)!; let metadata = node.metadata; const action = createAction(instantiationService); await action.run({ profile: connectionProfile, object: metadata }) selectionHandler.onTreeActionStateChange(false); notificationHandle.close(); } catch (error) { const msg = localize('scriptActionError', "An error occurred while executing the action: {0}.", getErrorMessage(error)); logService.error(msg); notificationHandle.updateSeverity(Severity.Error); notificationHandle.updateMessage(msg); notificationHandle.progress.done(); notificationHandle.updateActions({ primary: [ toAction({ id: 'closeScriptingNotification', label: localize('scriptingAction.close', "Close"), run: () => { notificationHandle.close(); } })] }) } } // Script as Select CommandsRegistry.registerCommand({ id: OE_SCRIPT_AS_SELECT_COMMAND_ID, handler: async (accessor, args: ObjectExplorerActionsContext) => { return runScriptingAction(accessor, args, (instantiationService) => { return instantiationService.createInstance(ScriptSelectAction, ScriptSelectAction.ID, ScriptSelectAction.LABEL); }); } }); // Edit Data CommandsRegistry.registerCommand({ id: OE_EDIT_DATA_COMMAND_ID, handler: async (accessor, args: ObjectExplorerActionsContext) => { return runScriptingAction(accessor, args, (instantiationService) => { return instantiationService.createInstance(EditDataAction, EditDataAction.ID, EditDataAction.LABEL); }); } }); // Script as Create CommandsRegistry.registerCommand({ id: OE_SCRIPT_AS_CREATE_COMMAND_ID, handler: async (accessor, args: ObjectExplorerActionsContext) => { return runScriptingAction(accessor, args, (instantiationService) => { return instantiationService.createInstance(ScriptCreateAction, ScriptCreateAction.ID, ScriptCreateAction.LABEL); }); } }); // Script as Execute CommandsRegistry.registerCommand({ id: OE_SCRIPT_AS_EXECUTE_COMMAND_ID, handler: async (accessor, args: ObjectExplorerActionsContext) => { return runScriptingAction(accessor, args, (instantiationService) => { return instantiationService.createInstance(ScriptExecuteAction, ScriptExecuteAction.ID, ScriptExecuteAction.LABEL); }); } }); // Script as Alter CommandsRegistry.registerCommand({ id: OE_SCRIPT_AS_ALTER_COMMAND_ID, handler: async (accessor, args: ObjectExplorerActionsContext) => { return runScriptingAction(accessor, args, (instantiationService) => { return instantiationService.createInstance(ScriptAlterAction, ScriptAlterAction.ID, ScriptAlterAction.LABEL); }); } }); // Script as Delete CommandsRegistry.registerCommand({ id: OE_SCRIPT_AS_DELETE_COMMAND_ID, handler: async (accessor, args: ObjectExplorerActionsContext) => { return runScriptingAction(accessor, args, (instantiationService) => { return instantiationService.createInstance(ScriptDeleteAction, ScriptDeleteAction.ID, ScriptDeleteAction.LABEL); }); } }); // Refresh Action for Scriptable objects CommandsRegistry.registerCommand({ id: OE_REFRESH_COMMAND_ID, handler: handleOeRefreshCommand }); export async function handleOeRefreshCommand(accessor: ServicesAccessor, args: ObjectExplorerActionsContext): Promise { const objectExplorerService = accessor.get(IObjectExplorerService); const logService = accessor.get(ILogService); const notificationService = accessor.get(INotificationService); const treeNode = await getTreeNode(args, objectExplorerService); const tree = objectExplorerService.getServerTreeView()!.tree; try { await objectExplorerService.refreshTreeNode(treeNode!.getSession()!, treeNode!); if (tree instanceof AsyncServerTree) { await tree.updateChildren(treeNode); } else { await tree.refresh(treeNode); } } catch (err) { // Display message to the user but also log the entire error to the console for the stack trace notificationService.error(localize('refreshError', "An error occurred refreshing node '{0}': {1}", args.nodeInfo?.label, getErrorMessage(err))); logService.error(err); } } //#endregion //#region -- explorer widget export class ExplorerScriptSelectAction extends ScriptSelectAction { constructor( id: string, label: string, @IQueryEditorService queryEditorService: IQueryEditorService, @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, @IProgressService private readonly progressService: IProgressService, @IErrorMessageService errorMessageService: IErrorMessageService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService, errorMessageService); } public override async run(actionContext: BaseActionContext): Promise { await this.progressService.withProgress({ location: ProgressLocation.Window }, async () => await super.run(actionContext)); } } export class ExplorerScriptCreateAction extends ScriptCreateAction { constructor( id: string, label: string, @IQueryEditorService queryEditorService: IQueryEditorService, @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, @IErrorMessageService errorMessageService: IErrorMessageService, @IProgressService private readonly progressService: IProgressService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService, errorMessageService); } public override async run(actionContext: BaseActionContext): Promise { await this.progressService.withProgress({ location: ProgressLocation.Window }, async () => await super.run(actionContext)); } } export class ExplorerScriptAlterAction extends ScriptAlterAction { constructor( id: string, label: string, @IQueryEditorService queryEditorService: IQueryEditorService, @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, @IErrorMessageService errorMessageService: IErrorMessageService, @IProgressService private readonly progressService: IProgressService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService, errorMessageService); } public override async run(actionContext: BaseActionContext): Promise { await this.progressService.withProgress({ location: ProgressLocation.Window }, async () => await super.run(actionContext)); } } export class ExplorerScriptExecuteAction extends ScriptExecuteAction { constructor( id: string, label: string, @IQueryEditorService queryEditorService: IQueryEditorService, @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, @IErrorMessageService errorMessageService: IErrorMessageService, @IProgressService private readonly progressService: IProgressService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService, errorMessageService); } public override async run(actionContext: BaseActionContext): Promise { await this.progressService.withProgress({ location: ProgressLocation.Window }, async () => await super.run(actionContext)); } } //#endregion