move code from parts to contrib (#8319)
1
src/sql/workbench/contrib/tasks/browser/media/error.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#d02e00;}</style></defs><title>globalerror_red</title><path class="cls-1" d="M8,0a7.92,7.92,0,0,1,4,1.09A8.15,8.15,0,0,1,14.91,4a8,8,0,0,1,.81,1.91,8,8,0,0,1-.81,6.16A8.15,8.15,0,0,1,12,14.92a8,8,0,0,1-8.07,0,8.15,8.15,0,0,1-2.87-2.87A8,8,0,0,1,1.09,4,8.15,8.15,0,0,1,4,1.11,7.92,7.92,0,0,1,8,0ZM8,15a6.88,6.88,0,0,0,1.86-.25,7,7,0,0,0,4.89-4.89,7.07,7.07,0,0,0,0-3.73A7,7,0,0,0,9.86,1.27a7.07,7.07,0,0,0-3.73,0A7,7,0,0,0,1.25,6.15a7.07,7.07,0,0,0,0,3.73,7,7,0,0,0,4.89,4.89A6.88,6.88,0,0,0,8,15Zm3.46-9.76L8.71,8l2.75,2.76-.7.7L8,8.73,5.24,11.48l-.7-.7L7.29,8,4.54,5.26l.7-.7L8,7.31l2.76-2.75Z"/></svg>
|
||||
|
After Width: | Height: | Size: 721 B |
31
src/sql/workbench/contrib/tasks/browser/media/loading.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 0.6s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.075s; }
|
||||
circle:nth-child(3) { animation-delay: 0.15s; }
|
||||
circle:nth-child(4) { animation-delay: 0.225s; }
|
||||
circle:nth-child(5) { animation-delay: 0.3s; }
|
||||
circle:nth-child(6) { animation-delay: 0.375s; }
|
||||
circle:nth-child(7) { animation-delay: 0.45s; }
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 0.6s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.075s; }
|
||||
circle:nth-child(3) { animation-delay: 0.15s; }
|
||||
circle:nth-child(4) { animation-delay: 0.225s; }
|
||||
circle:nth-child(5) { animation-delay: 0.3s; }
|
||||
circle:nth-child(6) { animation-delay: 0.375s; }
|
||||
circle:nth-child(7) { animation-delay: 0.45s; }
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#3062d6;}.cls-2{fill:#fff;}</style></defs><title>cancelledstate_16x16</title><circle class="cls-1" cx="8.07" cy="8.07" r="7.93"/><polygon class="cls-2" points="8.82 8.07 11.53 10.78 10.83 11.48 8.12 8.78 5.41 11.48 4.7 10.78 7.42 8.07 4.65 5.31 5.36 4.61 8.12 7.37 10.83 4.67 11.53 5.36 8.82 8.07"/></svg>
|
||||
|
After Width: | Height: | Size: 423 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#212121;}</style></defs><title>queuedtask_16x16</title><path class="cls-1" d="M4,7a3.45,3.45,0,0,1-.93-.13,3.56,3.56,0,0,1-.84-.35A3.5,3.5,0,0,1,1,5.28,3.54,3.54,0,0,1,.6,4.44a3.54,3.54,0,0,1,0-1.87A3.54,3.54,0,0,1,1,1.74,3.5,3.5,0,0,1,2.21.48,3.55,3.55,0,0,1,3.05.13a3.54,3.54,0,0,1,1.87,0,3.55,3.55,0,0,1,.84.35A3.5,3.5,0,0,1,7,1.74a3.55,3.55,0,0,1,.35.84,3.54,3.54,0,0,1,0,1.87A3.56,3.56,0,0,1,7,5.28,3.5,3.5,0,0,1,5.76,6.54a3.55,3.55,0,0,1-.84.35A3.45,3.45,0,0,1,4,7ZM4,.44a3,3,0,0,0-.81.11A3.08,3.08,0,0,0,1,2.7,3.08,3.08,0,0,0,1,4.33,3.08,3.08,0,0,0,3.17,6.47a3.08,3.08,0,0,0,1.63,0A3.08,3.08,0,0,0,6.95,4.33a3.08,3.08,0,0,0,0-1.63A3.08,3.08,0,0,0,4.8.55,3,3,0,0,0,4,.44ZM4,3.51V1.32H3.55V3.95H5.3V3.51Z"/><rect class="cls-1" x="1" y="14.01" width="14" height="1"/><rect class="cls-1" x="1" y="11.03" width="14" height="1"/><rect class="cls-1" x="1" y="7.96" width="14" height="1"/><rect class="cls-1" x="9" y="4.88" width="5.97" height="1"/><rect class="cls-1" x="9" y="1.88" width="5.97" height="1"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>queuedtask_inverse_16x16</title><path class="cls-1" d="M4.08,7.37a3.45,3.45,0,0,1-.93-.13,3.56,3.56,0,0,1-.84-.35A3.5,3.5,0,0,1,1,5.63,3.54,3.54,0,0,1,.7,4.79a3.54,3.54,0,0,1,0-1.87A3.54,3.54,0,0,1,1,2.09,3.5,3.5,0,0,1,2.31.83,3.55,3.55,0,0,1,3.15.47,3.54,3.54,0,0,1,5,.47a3.55,3.55,0,0,1,.84.35A3.5,3.5,0,0,1,7.11,2.09a3.55,3.55,0,0,1,.35.84,3.54,3.54,0,0,1,0,1.87,3.56,3.56,0,0,1-.35.84A3.5,3.5,0,0,1,5.85,6.89,3.55,3.55,0,0,1,5,7.25,3.45,3.45,0,0,1,4.08,7.37Zm0-6.58A3,3,0,0,0,3.27.9,3.08,3.08,0,0,0,1.12,3a3.08,3.08,0,0,0,0,1.63A3.08,3.08,0,0,0,3.27,6.82a3.08,3.08,0,0,0,1.63,0A3.08,3.08,0,0,0,7,4.67,3.08,3.08,0,0,0,7,3,3.08,3.08,0,0,0,4.9.9,3,3,0,0,0,4.08.79Zm0,3.07V1.67H3.64V4.3H5.4V3.86Z"/><rect class="cls-1" x="1.09" y="14.36" width="14" height="1"/><rect class="cls-1" x="1.09" y="11.38" width="14" height="1"/><rect class="cls-1" x="1.09" y="8.31" width="14" height="1"/><rect class="cls-1" x="9.09" y="5.22" width="5.97" height="1"/><rect class="cls-1" x="9.09" y="2.22" width="5.97" height="1"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#3bb44a;}</style></defs><title>success_16x16</title><path class="cls-1" d="M16,3.16,5.48,13.69,0,8.2l.89-.89,4.6,4.59,9.63-9.62Z"/></svg>
|
||||
|
After Width: | Height: | Size: 255 B |
76
src/sql/workbench/contrib/tasks/browser/media/tasksPanel.css
Normal file
@@ -0,0 +1,76 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.empty-task-message {
|
||||
padding: 10px 22px 0 22px;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group {
|
||||
line-height: 22px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* task label and description */
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .label {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* style for server name | database name */
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .description {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
padding-left: 12px
|
||||
}
|
||||
|
||||
/* style for timing */
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .time {
|
||||
padding-left: 12px;
|
||||
opacity: .6;
|
||||
text-overflow: ellipsis;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
/* task icon status */
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon {
|
||||
background-size: 16px;
|
||||
background-position: left center;
|
||||
background-repeat: no-repeat;
|
||||
padding-right: 6px;
|
||||
min-width: 22px;
|
||||
height: 22px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.vs .monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.not-started {
|
||||
background-image: url('status_queuedtask.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.not-started,
|
||||
.hc-black .monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.not-started {
|
||||
background-image: url('status_queuedtask_inverse.svg');
|
||||
}
|
||||
|
||||
.vs .monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.in-progress {
|
||||
background-image: url("loading.svg");
|
||||
}
|
||||
|
||||
.vs-dark .monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.in-progress,
|
||||
.hc-black .monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.in-progress {
|
||||
background-image: url("loading_inverse.svg");
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.success {
|
||||
background-image: url("status_success.svg");
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.canceled {
|
||||
background-image: url("status_cancelled.svg");
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content > .task-group > .task-icon.error {
|
||||
background-image: url("error.svg");
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { TasksPanel } from 'sql/workbench/contrib/tasks/browser/tasksPanel';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import * as ext from 'vs/workbench/common/contributions';
|
||||
import { ITaskService } from 'sql/platform/tasks/common/tasksService';
|
||||
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
|
||||
import { TASKS_PANEL_ID } from 'sql/workbench/contrib/tasks/common/tasks';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ToggleTasksAction } from 'sql/workbench/contrib/tasks/browser/tasksActions';
|
||||
|
||||
export class StatusUpdater extends lifecycle.Disposable implements ext.IWorkbenchContribution {
|
||||
static ID = 'data.taskhistory.statusUpdater';
|
||||
|
||||
private badgeHandle: lifecycle.IDisposable;
|
||||
|
||||
constructor(
|
||||
@IActivityService private readonly activityBarService: IActivityService,
|
||||
@ITaskService private readonly taskService: ITaskService,
|
||||
@IPanelService private readonly panelService: IPanelService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(this.taskService.onAddNewTask(args => {
|
||||
this.panelService.openPanel(TASKS_PANEL_ID, true);
|
||||
this.onServiceChange();
|
||||
}));
|
||||
|
||||
this._register(this.taskService.onTaskComplete(task => {
|
||||
this.onServiceChange();
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
private onServiceChange(): void {
|
||||
lifecycle.dispose(this.badgeHandle);
|
||||
let numOfInProgressTask: number = this.taskService.getNumberOfInProgressTasks();
|
||||
let badge: NumberBadge = new NumberBadge(numOfInProgressTask, n => localize('inProgressTasksChangesBadge', "{0} in progress tasks", n));
|
||||
this.badgeHandle = this.activityBarService.showActivity(TASKS_PANEL_ID, badge, 'taskhistory-viewlet-label');
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return StatusUpdater.ID;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
lifecycle.dispose(this.badgeHandle);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(
|
||||
ToggleTasksAction,
|
||||
ToggleTasksAction.ID,
|
||||
ToggleTasksAction.LABEL,
|
||||
{ primary: KeyMod.CtrlCmd | KeyCode.KEY_T }),
|
||||
'View: Toggle Tasks',
|
||||
localize('viewCategory', "View")
|
||||
);
|
||||
|
||||
// Register Output Panel
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
|
||||
TasksPanel,
|
||||
TASKS_PANEL_ID,
|
||||
localize('tasks', "Tasks"),
|
||||
'output',
|
||||
20,
|
||||
ToggleTasksAction.ID
|
||||
));
|
||||
|
||||
// Register StatusUpdater
|
||||
(<ext.IWorkbenchContributionsRegistry>Registry.as(ext.Extensions.Workbench)).registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '4_panels',
|
||||
command: {
|
||||
id: ToggleTasksAction.ID,
|
||||
title: localize({ key: 'miViewTasks', comment: ['&& denotes a mnemonic'] }, "&&Tasks")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 { TaskNode, TaskStatus, TaskExecutionMode } from 'sql/platform/tasks/common/tasksNode';
|
||||
import { CancelAction, ScriptAction } from 'sql/workbench/contrib/tasks/common/tasksAction';
|
||||
|
||||
/**
|
||||
* Provides actions for the history tasks
|
||||
*/
|
||||
export class TaskHistoryActionProvider extends ContributableActionProvider {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public hasActions(tree: ITree, element: any): boolean {
|
||||
return element instanceof TaskNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return actions given an element in the tree
|
||||
*/
|
||||
public getActions(tree: ITree, element: any): IAction[] {
|
||||
if (element instanceof TaskNode) {
|
||||
return this.getTaskHistoryActions(tree, element);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public hasSecondaryActions(tree: ITree, element: any): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return actions for history task
|
||||
*/
|
||||
public getTaskHistoryActions(tree: ITree, element: TaskNode): IAction[] {
|
||||
let actions = [];
|
||||
|
||||
// get actions for tasks in progress
|
||||
if (element.status === TaskStatus.InProgress && element.isCancelable) {
|
||||
actions.push(this._instantiationService.createInstance(CancelAction, CancelAction.ID, CancelAction.LABEL));
|
||||
}
|
||||
|
||||
// get actions for tasks succeeded
|
||||
if (element.status === TaskStatus.Succeeded || element.status === TaskStatus.SucceededWithWarning) {
|
||||
if (element.taskExecutionMode === TaskExecutionMode.executeAndScript) {
|
||||
actions.push(this._instantiationService.createInstance(ScriptAction, ScriptAction.ID, ScriptAction.LABEL));
|
||||
}
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
24
src/sql/workbench/contrib/tasks/browser/tasksActions.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { TASKS_PANEL_ID } from 'sql/workbench/contrib/tasks/common/tasks';
|
||||
|
||||
export class ToggleTasksAction extends TogglePanelAction {
|
||||
|
||||
public static readonly ID = 'workbench.action.tasks.toggleTasks';
|
||||
public static readonly LABEL = localize('toggleTasks', "Toggle Tasks");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IPanelService panelService: IPanelService,
|
||||
) {
|
||||
super(id, label, TASKS_PANEL_ID, panelService, layoutService);
|
||||
}
|
||||
}
|
||||
80
src/sql/workbench/contrib/tasks/browser/tasksController.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITree, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree';
|
||||
import * as treedefaults from 'vs/base/parts/tree/browser/treeDefaults';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { TaskHistoryActionProvider } from 'sql/workbench/contrib/tasks/browser/tasksActionProvider';
|
||||
|
||||
/**
|
||||
* Extends the tree controller to handle clicks on the tree elements
|
||||
*/
|
||||
export class TaskHistoryController extends treedefaults.DefaultController {
|
||||
|
||||
constructor(
|
||||
private actionProvider: TaskHistoryActionProvider,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IKeybindingService private keybindingService: IKeybindingService
|
||||
) {
|
||||
super({ clickBehavior: treedefaults.ClickBehavior.ON_MOUSE_DOWN });
|
||||
}
|
||||
|
||||
public onClick(tree: ITree, element: any, event: IMouseEvent): boolean {
|
||||
return super.onClick(tree, element, event);
|
||||
}
|
||||
|
||||
protected onLeftClick(tree: ITree, element: any, event: IMouseEvent, origin: string = 'mouse'): boolean {
|
||||
return super.onLeftClick(tree, element, event, origin);
|
||||
}
|
||||
|
||||
// Do not allow left / right to expand and collapse groups #7848
|
||||
protected onLeft(tree: ITree, event: IKeyboardEvent): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected onRight(tree: ITree, event: IKeyboardEvent): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected onEnter(tree: ITree, event: IKeyboardEvent): boolean {
|
||||
return super.onEnter(tree, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return actions in the context menu
|
||||
*/
|
||||
public onContextMenu(tree: ITree, element: any, event: ContextMenuEvent): boolean {
|
||||
if (event.target && event.target.tagName && event.target.tagName.toLowerCase() === 'input') {
|
||||
return false;
|
||||
}
|
||||
// Check if clicked on some element
|
||||
if (element === tree.getInput()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
tree.setFocus(element);
|
||||
|
||||
let anchor = { x: event.posx + 1, y: event.posy };
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.actionProvider.getActions(tree, element),
|
||||
getKeyBinding: (action) => this.keybindingService.lookupKeybinding(action.id),
|
||||
onHide: (wasCancelled?: boolean) => {
|
||||
if (wasCancelled) {
|
||||
tree.domFocus();
|
||||
}
|
||||
},
|
||||
getActionsContext: () => (element)
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
52
src/sql/workbench/contrib/tasks/browser/tasksDataSource.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITree, IDataSource } from 'vs/base/parts/tree/browser/tree';
|
||||
import { TaskNode } from 'sql/platform/tasks/common/tasksNode';
|
||||
|
||||
/**
|
||||
* Implements the DataSource(that returns a parent/children of an element) for the task history
|
||||
*/
|
||||
export class TaskHistoryDataSource implements IDataSource {
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of the given element.
|
||||
* No more than one element may use a given identifier.
|
||||
*/
|
||||
public getId(tree: ITree, element: any): string {
|
||||
if (element instanceof TaskNode) {
|
||||
return (<TaskNode>element).id;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value indicating whether the element has children.
|
||||
*/
|
||||
public hasChildren(tree: ITree, element: any): boolean {
|
||||
if (element instanceof TaskNode) {
|
||||
return (<TaskNode>element).hasChildren;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element's children as an array in a promise.
|
||||
*/
|
||||
public getChildren(tree: ITree, element: any): Promise<any> {
|
||||
if (element instanceof TaskNode) {
|
||||
return Promise.resolve((<TaskNode>element).children);
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element's parent in a promise.
|
||||
*/
|
||||
public getParent(tree: ITree, element: any): Promise<any> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
43
src/sql/workbench/contrib/tasks/browser/tasksPanel.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/tasksPanel';
|
||||
import { Dimension } from 'vs/base/browser/dom';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TaskHistoryView } from 'sql/workbench/contrib/tasks/browser/tasksView';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { Panel } from 'vs/workbench/browser/panel';
|
||||
import { TASKS_PANEL_ID } from 'sql/workbench/contrib/tasks/common/tasks';
|
||||
|
||||
export class TasksPanel extends Panel {
|
||||
|
||||
private _taskHistoryView: TaskHistoryView;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
) {
|
||||
super(TASKS_PANEL_ID, telemetryService, themeService, storageService);
|
||||
}
|
||||
|
||||
public create(parent: HTMLElement): void {
|
||||
super.create(parent);
|
||||
this._taskHistoryView = this.instantiationService.createInstance(TaskHistoryView);
|
||||
this._taskHistoryView.renderBody(parent);
|
||||
}
|
||||
|
||||
public setVisible(visible: boolean): void {
|
||||
super.setVisible(visible);
|
||||
this._taskHistoryView.setVisible(visible);
|
||||
}
|
||||
|
||||
public layout({ height }: Dimension): void {
|
||||
this._taskHistoryView.layout(height);
|
||||
}
|
||||
}
|
||||
147
src/sql/workbench/contrib/tasks/browser/tasksRenderer.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITree, IRenderer } from 'vs/base/parts/tree/browser/tree';
|
||||
import { TaskNode, TaskStatus } from 'sql/platform/tasks/common/tasksNode';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as Utils from 'sql/platform/connection/common/utils';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IntervalTimer } from 'vs/base/common/async';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
export interface ITaskHistoryTemplateData {
|
||||
root: HTMLElement;
|
||||
icon: HTMLElement;
|
||||
label: HTMLSpanElement;
|
||||
description: HTMLSpanElement;
|
||||
time: HTMLSpanElement;
|
||||
disposables: Array<IDisposable>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the tree items.
|
||||
* Uses the dom template to render task history.
|
||||
*/
|
||||
export class TaskHistoryRenderer implements IRenderer {
|
||||
|
||||
public static readonly TASKOBJECT_HEIGHT = 22;
|
||||
private static readonly FAIL_CLASS = 'error';
|
||||
private static readonly SUCCESS_CLASS = 'success';
|
||||
private static readonly INPROGRESS_CLASS = 'in-progress';
|
||||
private static readonly NOTSTARTED_CLASS = 'not-started';
|
||||
private static readonly CANCELED_CLASS = 'canceled';
|
||||
|
||||
/**
|
||||
* Returns the element's height in the tree, in pixels.
|
||||
*/
|
||||
public getHeight(tree: ITree, element: TaskNode): number {
|
||||
return TaskHistoryRenderer.TASKOBJECT_HEIGHT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a template ID for a given element.
|
||||
*/
|
||||
public getTemplateId(tree: ITree, element: TaskNode): string {
|
||||
return element.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render template in a dom element based on template id
|
||||
*/
|
||||
public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any {
|
||||
const taskTemplate: ITaskHistoryTemplateData = Object.create(null);
|
||||
taskTemplate.root = dom.append(container, $('.task-group'));
|
||||
taskTemplate.icon = dom.append(taskTemplate.root, $('.codicon.task-icon'));
|
||||
taskTemplate.label = dom.append(taskTemplate.root, $('.label'));
|
||||
taskTemplate.description = dom.append(taskTemplate.root, $('.description'));
|
||||
taskTemplate.time = dom.append(taskTemplate.root, $('.time'));
|
||||
taskTemplate.disposables = [];
|
||||
return taskTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a element, given an object bag returned by the template
|
||||
*/
|
||||
public renderElement(tree: ITree, element: TaskNode, templateId: string, templateData: ITaskHistoryTemplateData): void {
|
||||
let taskStatus;
|
||||
if (element) {
|
||||
templateData.icon.className = 'task-icon';
|
||||
switch (element.status) {
|
||||
case TaskStatus.Succeeded:
|
||||
dom.addClass(templateData.icon, TaskHistoryRenderer.SUCCESS_CLASS);
|
||||
taskStatus = localize('succeeded', "succeeded");
|
||||
break;
|
||||
case TaskStatus.Failed:
|
||||
dom.addClass(templateData.icon, TaskHistoryRenderer.FAIL_CLASS);
|
||||
taskStatus = localize('failed', "failed");
|
||||
break;
|
||||
case TaskStatus.InProgress:
|
||||
dom.addClass(templateData.icon, TaskHistoryRenderer.INPROGRESS_CLASS);
|
||||
taskStatus = localize('inProgress', "in progress");
|
||||
break;
|
||||
case TaskStatus.NotStarted:
|
||||
dom.addClass(templateData.icon, TaskHistoryRenderer.NOTSTARTED_CLASS);
|
||||
taskStatus = localize('notStarted', "not started");
|
||||
break;
|
||||
case TaskStatus.Canceled:
|
||||
dom.addClass(templateData.icon, TaskHistoryRenderer.CANCELED_CLASS);
|
||||
taskStatus = localize('canceled', "canceled");
|
||||
break;
|
||||
case TaskStatus.Canceling:
|
||||
dom.addClass(templateData.icon, TaskHistoryRenderer.INPROGRESS_CLASS);
|
||||
taskStatus = localize('canceling', "canceling");
|
||||
break;
|
||||
}
|
||||
// Set hover text for icon to same as task status
|
||||
templateData.icon.title = taskStatus;
|
||||
|
||||
// Determine the task title and set hover text equal to that
|
||||
templateData.label.textContent = element.taskName + ' ' + taskStatus;
|
||||
templateData.label.title = templateData.label.textContent;
|
||||
|
||||
// Determine the target name and set hover text equal to that
|
||||
let description = element.serverName;
|
||||
if (element.databaseName) {
|
||||
description += ' | ' + element.databaseName;
|
||||
}
|
||||
templateData.description.textContent = description;
|
||||
templateData.description.title = templateData.description.textContent;
|
||||
|
||||
this.timer(element, templateData.time);
|
||||
|
||||
const timer = new IntervalTimer();
|
||||
timer.cancelAndSet(() => this.timer(element, templateData.time), 1000);
|
||||
templateData.disposables.push(timer);
|
||||
}
|
||||
}
|
||||
|
||||
private timer(taskNode: TaskNode, element: HTMLElement): void {
|
||||
let timeLabel = '';
|
||||
if (taskNode.status === TaskStatus.Failed) {
|
||||
timeLabel += taskNode.startTime + ' Error: ' + taskNode.message;
|
||||
} else {
|
||||
if (taskNode.startTime) {
|
||||
timeLabel = taskNode.startTime;
|
||||
}
|
||||
if (taskNode.endTime) {
|
||||
timeLabel += ' - ' + taskNode.endTime;
|
||||
}
|
||||
|
||||
if (taskNode.timer) {
|
||||
// Round task duration to seconds and then convert back to milliseconds
|
||||
let duration = Math.floor(taskNode.timer.elapsed() / 1000) * 1000;
|
||||
timeLabel += ' (' + Utils.parseNumAsTimeString(duration) + ')';
|
||||
}
|
||||
}
|
||||
element.textContent = timeLabel;
|
||||
element.title = timeLabel;
|
||||
}
|
||||
|
||||
public disposeTemplate(tree: ITree, templateId: string, templateData: ITaskHistoryTemplateData): void {
|
||||
dispose(templateData.disposables);
|
||||
}
|
||||
}
|
||||
169
src/sql/workbench/contrib/tasks/browser/tasksView.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { DefaultFilter, DefaultDragAndDrop, DefaultAccessibilityProvider } from 'vs/base/parts/tree/browser/treeDefaults';
|
||||
import { localize } from 'vs/nls';
|
||||
import { hide, $, append } from 'vs/base/browser/dom';
|
||||
|
||||
import { TaskHistoryRenderer } from 'sql/workbench/contrib/tasks/browser/tasksRenderer';
|
||||
import { TaskHistoryDataSource } from 'sql/workbench/contrib/tasks/browser/tasksDataSource';
|
||||
import { TaskHistoryController } from 'sql/workbench/contrib/tasks/browser/tasksController';
|
||||
import { TaskHistoryActionProvider } from 'sql/workbench/contrib/tasks/browser/tasksActionProvider';
|
||||
import { ITaskService } from 'sql/platform/tasks/common/tasksService';
|
||||
import { TaskNode, TaskStatus } from 'sql/platform/tasks/common/tasksNode';
|
||||
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
||||
import { IExpandableTree } from 'sql/workbench/contrib/objectExplorer/browser/treeUpdateUtils';
|
||||
|
||||
/**
|
||||
* TaskHistoryView implements the dynamic tree view.
|
||||
*/
|
||||
export class TaskHistoryView extends Disposable {
|
||||
private _messages: HTMLElement;
|
||||
private _tree: ITree;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@ITaskService private _taskService: ITaskService,
|
||||
@IErrorMessageService private _errorMessageService: IErrorMessageService,
|
||||
@IThemeService private _themeService: IThemeService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the view body
|
||||
*/
|
||||
public renderBody(container: HTMLElement): void {
|
||||
|
||||
let taskNode = this._taskService.getAllTasks();
|
||||
|
||||
// Add div to display no task executed message
|
||||
this._messages = append(container, $('div.empty-task-message'));
|
||||
|
||||
if (taskNode && taskNode.hasChildren) {
|
||||
hide(this._messages);
|
||||
}
|
||||
let noTaskMessage = localize('noTaskMessage', "No task history to display.");
|
||||
append(this._messages, $('span')).innerText = noTaskMessage;
|
||||
|
||||
this._tree = this._register(this.createTaskHistoryTree(container, this._instantiationService));
|
||||
this._register(this._tree.onDidChangeSelection((event) => this.onSelected(event)));
|
||||
|
||||
// Theme styler
|
||||
this._register(attachListStyler(this._tree, this._themeService));
|
||||
|
||||
this._register(this._taskService.onAddNewTask(args => {
|
||||
hide(this._messages);
|
||||
this.refreshTree();
|
||||
}));
|
||||
this._register(this._taskService.onTaskComplete(task => {
|
||||
this.updateTask(task);
|
||||
}));
|
||||
|
||||
// Refresh Tree when these events are emitted
|
||||
this.refreshTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a task history tree
|
||||
*/
|
||||
public createTaskHistoryTree(treeContainer: HTMLElement, instantiationService: IInstantiationService): Tree {
|
||||
const dataSource = instantiationService.createInstance(TaskHistoryDataSource);
|
||||
const actionProvider = instantiationService.createInstance(TaskHistoryActionProvider);
|
||||
const renderer = instantiationService.createInstance(TaskHistoryRenderer);
|
||||
const controller = instantiationService.createInstance(TaskHistoryController, actionProvider);
|
||||
const dnd = new DefaultDragAndDrop();
|
||||
const filter = new DefaultFilter();
|
||||
const sorter = null;
|
||||
const accessibilityProvider = new DefaultAccessibilityProvider();
|
||||
|
||||
return new Tree(treeContainer, {
|
||||
dataSource, renderer, controller, dnd, filter, sorter, accessibilityProvider
|
||||
}, {
|
||||
indentPixels: 10,
|
||||
twistiePixels: 20,
|
||||
ariaLabel: localize({ key: 'taskHistory.regTreeAriaLabel', comment: ['TaskHistory'] }, "Task history")
|
||||
});
|
||||
}
|
||||
|
||||
private updateTask(task: TaskNode): void {
|
||||
this._tree.refresh(task);
|
||||
}
|
||||
|
||||
public refreshTree(): void {
|
||||
let selectedElement: any;
|
||||
let targetsToExpand: any[];
|
||||
|
||||
// Focus
|
||||
this._tree.domFocus();
|
||||
|
||||
if (this._tree) {
|
||||
let selection = this._tree.getSelection();
|
||||
if (selection && selection.length === 1) {
|
||||
selectedElement = <any>selection[0];
|
||||
}
|
||||
// convert to old VS Code tree interface with expandable methods
|
||||
let expandableTree: IExpandableTree = <IExpandableTree>this._tree;
|
||||
targetsToExpand = expandableTree.getExpandedElements();
|
||||
}
|
||||
|
||||
//Get the tree Input
|
||||
let treeInput = this._taskService.getAllTasks();
|
||||
if (treeInput) {
|
||||
this._tree.setInput(treeInput).then(async () => {
|
||||
// Make sure to expand all folders that where expanded in the previous session
|
||||
if (targetsToExpand) {
|
||||
await this._tree.expandAll(targetsToExpand);
|
||||
}
|
||||
if (selectedElement) {
|
||||
this._tree.select(selectedElement);
|
||||
}
|
||||
this._tree.getFocus();
|
||||
}, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
|
||||
private onSelected(event: any) {
|
||||
let selection = this._tree.getSelection();
|
||||
|
||||
if (selection && selection.length > 0 && (selection[0] instanceof TaskNode)) {
|
||||
let task = <TaskNode>selection[0];
|
||||
let isMouseOrigin = event.payload && (event.payload.origin === 'mouse');
|
||||
let isDoubleClick = isMouseOrigin && event.payload.originalEvent && event.payload.originalEvent.detail === 2;
|
||||
if (isDoubleClick) {
|
||||
if (task.status === TaskStatus.Failed) {
|
||||
let err = task.taskName + ': ' + task.message;
|
||||
this._errorMessageService.showDialog(Severity.Error, localize('taskError', "Task error"), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the layout of the view
|
||||
*/
|
||||
public layout(height: number): void {
|
||||
this._tree.layout(height);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the visibility of the view
|
||||
*/
|
||||
public setVisible(visible: boolean): void {
|
||||
if (visible) {
|
||||
this._tree.onVisible();
|
||||
} else {
|
||||
this._tree.onHidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/sql/workbench/contrib/tasks/common/tasks.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Tasks panel id
|
||||
*/
|
||||
export const TASKS_PANEL_ID = 'workbench.panel.tasks';
|
||||
68
src/sql/workbench/contrib/tasks/common/tasksAction.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { ITaskService } from 'sql/platform/tasks/common/tasksService';
|
||||
import { TaskNode } from 'sql/platform/tasks/common/tasksNode';
|
||||
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
||||
|
||||
export class CancelAction extends Action {
|
||||
public static ID = 'taskHistory.cancel';
|
||||
public static LABEL = localize('cancelTask.cancel', "Cancel");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@ITaskService private _taskService: ITaskService,
|
||||
@IErrorMessageService private _errorMessageService: IErrorMessageService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
public run(element: TaskNode): Promise<boolean> {
|
||||
if (element instanceof TaskNode) {
|
||||
this._taskService.cancelTask(element.providerName, element.id).then((result) => {
|
||||
if (!result) {
|
||||
let error = localize('errorMsgFromCancelTask', "The task is failed to cancel.");
|
||||
this.showError(error);
|
||||
}
|
||||
}, error => {
|
||||
this.showError(error);
|
||||
return Promise.resolve(true);
|
||||
});
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
private showError(errorMessage: string) {
|
||||
if (this._errorMessageService) {
|
||||
this._errorMessageService.showDialog(Severity.Error, '', errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ScriptAction extends Action {
|
||||
public static ID = 'taskHistory.script';
|
||||
public static LABEL = localize('taskAction.script', "Script");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IQueryEditorService private _queryEditorService: IQueryEditorService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(element: TaskNode): Promise<boolean> {
|
||||
if (element instanceof TaskNode) {
|
||||
if (element.script && element.script !== '') {
|
||||
this._queryEditorService.newSqlEditor(element.script);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||