SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1,125 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import nls = require('vs/nls');
import 'vs/css!sql/media/actionBarLabel';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { localize } from 'vs/nls';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { VIEWLET_ID } from 'sql/parts/taskHistory/viewlet/taskHistoryViewlet';
import lifecycle = require('vs/base/common/lifecycle');
import ext = require('vs/workbench/common/contributions');
import { ITaskService } from 'sql/parts/taskHistory/common/taskService';
import { IActivityBarService, NumberBadge } from 'vs/workbench/services/activity/common/activityBarService';
export class StatusUpdater implements ext.IWorkbenchContribution {
static ID = 'data.taskhistory.statusUpdater';
private badgeHandle: lifecycle.IDisposable;
private toDispose: lifecycle.IDisposable[];
constructor(
@IActivityBarService private activityBarService: IActivityBarService,
@ITaskService private _taskService: ITaskService,
@IViewletService private _viewletService: IViewletService
) {
this.toDispose = [];
this.toDispose.push(this._taskService.onAddNewTask(args => {
this.showTasksViewlet();
this.onServiceChange();
}));
this.toDispose.push(this._taskService.onTaskComplete(task => {
this.onServiceChange();
}));
}
private showTasksViewlet(): void {
let activeViewlet: IViewlet = this._viewletService.getActiveViewlet();
if (!activeViewlet || activeViewlet.getId() !== VIEWLET_ID) {
this._viewletService.openViewlet(VIEWLET_ID, true);
}
}
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(VIEWLET_ID, badge, 'taskhistory-viewlet-label');
}
public getId(): string {
return StatusUpdater.ID;
}
public dispose(): void {
this.toDispose = lifecycle.dispose(this.toDispose);
lifecycle.dispose(this.badgeHandle);
}
}
// Viewlet Action
export class TaskHistoryViewletAction extends ToggleViewletAction {
public static ID = VIEWLET_ID;
public static LABEL = nls.localize({ key: 'showTaskHistory', comment: ['Show Task History'] }, 'Show Task History');
constructor(
id: string,
label: string,
@IViewletService viewletService: IViewletService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService
) {
super(id, label, VIEWLET_ID, viewletService, editorService);
}
}
// Viewlet
const viewletDescriptor = new ViewletDescriptor(
'sql/parts/taskHistory/viewlet/taskHistoryViewlet',
'TaskHistoryViewlet',
VIEWLET_ID,
'Task History',
'taskHistoryViewlet',
-90
);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
// Register StatusUpdater
(<ext.IWorkbenchContributionsRegistry>Registry.as(ext.Extensions.Workbench)).registerWorkbenchContribution(StatusUpdater);
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(
new SyncActionDescriptor(
TaskHistoryViewletAction,
TaskHistoryViewletAction.ID,
TaskHistoryViewletAction.LABEL,
{ primary: KeyMod.CtrlCmd | KeyCode.KEY_T }),
'View: Show Task Histry',
localize('view', "View")
);
let configurationRegistry = <IConfigurationRegistry>Registry.as(Extensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'taskHistory',
'title': localize('taskHistory', 'Task History'),
'type': 'object',
'properties': {
'datasource.task': {
'description': localize('datasource.task', 'Operation Task Status'),
'type': 'array'
}
}
});

View File

@@ -0,0 +1,115 @@
/*---------------------------------------------------------------------------------------------
* 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 { StopWatch } from 'vs/base/common/stopwatch';
import { generateUuid } from 'vs/base/common/uuid';
export enum TaskStatus {
notStarted = 0,
inProgress = 1,
succeeded = 2,
succeededWithWarning = 3,
failed = 4,
canceled = 5,
canceling = 6
}
export enum TaskExecutionMode {
execute = 0,
script = 1,
executeAndScript = 2,
}
export class TaskNode {
/**
* id for TaskNode
*/
public id: string;
/**
* string defining the type of the task - for example Backup, Restore
*/
public taskName: string;
/**
* sever name
*/
public serverName: string;
/**
* Database Name
*/
public databaseName: string;
/**
* Provider Name
*/
public providerName: string;
/**
* The start time of the task
*/
public startTime: string;
/**
* The end time of the task
*/
public endTime: string;
/**
* The timer for the task
*/
public timer: StopWatch;
/**
* Does this node have children
*/
public hasChildren: boolean;
/**
* Children of this node
*/
public children: TaskNode[];
/**
* Task's message
*/
public message: string;
/**
* Status of the task
*/
public status: TaskStatus;
/**
* Execution mode of task
*/
public taskExecutionMode: TaskExecutionMode;
/**
* Indicates if the task can be canceled
*/
public isCancelable: boolean;
/**
* Script of task operation
*/
public script: string;
constructor(taskName: string, serverName: string, databaseName: string, taskId: string = undefined, taskExecutionMode: TaskExecutionMode = TaskExecutionMode.execute, isCancelable: boolean = true) {
this.id = taskId || generateUuid();
this.taskName = taskName;
this.serverName = serverName;
this.databaseName = databaseName;
this.timer = StopWatch.create();
this.startTime = new Date().toLocaleTimeString();
this.status = TaskStatus.inProgress;
this.hasChildren = false;
this.taskExecutionMode = taskExecutionMode;
this.isCancelable = isCancelable;
}
}

View File

@@ -0,0 +1,226 @@
/*---------------------------------------------------------------------------------------------
* 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 * as data from 'data';
import { TaskNode, TaskStatus, TaskExecutionMode } from 'sql/parts/taskHistory/common/taskNode';
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import Event, { Emitter } from 'vs/base/common/event';
export const SERVICE_ID = 'taskHistoryService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IChoiceService } from 'vs/platform/message/common/message';
import { localize } from 'vs/nls';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
export const ITaskService = createDecorator<ITaskService>(SERVICE_ID);
export interface ITaskService {
_serviceBrand: any;
onTaskComplete: Event<TaskNode>;
onAddNewTask: Event<TaskNode>;
handleNewTask(task: TaskNode): void;
handleTaskComplete(eventArgs: TaskStatusChangeArgs): void;
getAllTasks(): TaskNode;
getNumberOfInProgressTasks(): number;
onNewTaskCreated(handle: number, taskInfo: data.TaskInfo);
onTaskStatusChanged(handle: number, taskProgressInfo: data.TaskProgressInfo);
cancelTask(providerId: string, taskId: string): Thenable<boolean>;
/**
* Register a ObjectExplorer provider
*/
registerProvider(providerId: string, provider: data.TaskServicesProvider): void;
}
export interface TaskStatusChangeArgs {
taskId: string;
status: data.TaskStatus;
message?: string;
script?: string;
}
export class TaskService implements ITaskService {
public _serviceBrand: any;
private _taskQueue: TaskNode;
private _onTaskComplete = new Emitter<TaskNode>();
private _onAddNewTask = new Emitter<TaskNode>();
private _providers: { [handle: string]: data.TaskServicesProvider; } = Object.create(null);
constructor(
@ILifecycleService lifecycleService: ILifecycleService,
@IChoiceService private choiceService: IChoiceService,
@IQueryEditorService private queryEditorService: IQueryEditorService
) {
this._taskQueue = new TaskNode('Root', undefined, undefined);
this._onTaskComplete = new Emitter<TaskNode>();
this._onAddNewTask = new Emitter<TaskNode>();
lifecycleService.onWillShutdown(event => event.veto(this.beforeShutdown()));
}
/**
* Register a ObjectExplorer provider
*/
public registerProvider(providerId: string, provider: data.TaskServicesProvider): void {
this._providers[providerId] = provider;
}
public onNewTaskCreated(handle: number, taskInfo: data.TaskInfo) {
let node: TaskNode = new TaskNode(taskInfo.name, taskInfo.serverName, taskInfo.databaseName, taskInfo.taskId, taskInfo.taskExecutionMode, taskInfo.isCancelable);
node.providerName = taskInfo.providerName;
this.handleNewTask(node);
}
public onTaskStatusChanged(handle: number, taskProgressInfo: data.TaskProgressInfo) {
this.handleTaskComplete({
taskId: taskProgressInfo.taskId,
status: taskProgressInfo.status,
message: taskProgressInfo.message,
script: taskProgressInfo.script
});
}
public cancelTask(providerId: string, taskId: string): Thenable<boolean> {
let task = this.getTaskInQueue(taskId);
task.status = TaskStatus.canceling;
this._onTaskComplete.fire(task);
let provider = this._providers[providerId];
if (provider) {
return provider.cancelTask({
taskId: taskId
});
}
return Promise.resolve(undefined);
}
private cancelAllTasks(): Thenable<void> {
return new TPromise<void>((resolve, reject) => {
let promises = this._taskQueue.children.map(task => {
if (task.status === TaskStatus.inProgress || task.status === TaskStatus.notStarted) {
return this.cancelTask(task.providerName, task.id);
}
return Promise.resolve(true);
});
Promise.all(promises).then(result => {
resolve(undefined);
}).catch(error => {
reject(error);
});
});
}
public handleNewTask(task: TaskNode): void {
if (this._taskQueue.hasChildren) {
this._taskQueue.children.unshift(task);
} else {
this._taskQueue.hasChildren = true;
this._taskQueue.children = [task];
}
this._onAddNewTask.fire(task);
}
public beforeShutdown(): TPromise<boolean> {
const message = localize('InProgressWarning', '1 or more tasks are in progress. Are you sure you want to quit?');
const options = [
localize('yes', "Yes"),
localize('no', "No")
];
return new TPromise<boolean>((resolve, reject) => {
let numOfInprogressTasks = this.getNumberOfInProgressTasks();
if (numOfInprogressTasks > 0) {
this.choiceService.choose(Severity.Warning, message, options, 0, false).done(choice => {
switch (choice) {
case 0:
let timeoutId: number;
let isTimeout = false;
this.cancelAllTasks().then(() => {
clearTimeout(timeoutId);
if (!isTimeout) {
resolve(false);
}
}, error => {
clearTimeout(timeoutId);
if (!isTimeout) {
resolve(false);
};
});
timeoutId = setTimeout(function () {
isTimeout = true;
resolve(false);
}, 2000);
break;
case 1:
resolve(true);
}
});
} else {
resolve(false);
}
});
}
public handleTaskComplete(eventArgs: TaskStatusChangeArgs): void {
var task = this.getTaskInQueue(eventArgs.taskId);
if (task) {
task.status = eventArgs.status;
if (eventArgs.message) {
task.message = eventArgs.message;
}
switch (task.status) {
case TaskStatus.canceled:
case TaskStatus.succeeded:
case TaskStatus.succeededWithWarning:
case TaskStatus.failed:
task.endTime = new Date().toLocaleTimeString();
task.timer.stop();
this._onTaskComplete.fire(task);
break;
default:
break;
}
if ((task.status === TaskStatus.succeeded || task.status === TaskStatus.succeededWithWarning)
&& eventArgs.script && eventArgs.script !== '') {
if (task.taskExecutionMode === TaskExecutionMode.script) {
this.queryEditorService.newSqlEditor(eventArgs.script);
} else if (task.taskExecutionMode === TaskExecutionMode.executeAndScript) {
task.script = eventArgs.script;
}
}
}
}
private getTaskInQueue(taskId: string): TaskNode {
if (this._taskQueue.hasChildren) {
return this._taskQueue.children.find(x => x.id === taskId);
}
return undefined;
}
public get onTaskComplete(): Event<TaskNode> {
return this._onTaskComplete.event;
}
public get onAddNewTask(): Event<TaskNode> {
return this._onAddNewTask.event;
}
public getNumberOfInProgressTasks(): number {
if (this._taskQueue.hasChildren) {
var inProgressTasks = this._taskQueue.children.filter(x => x.status === TaskStatus.inProgress);
return inProgressTasks ? inProgressTasks.length : 0;
}
return 0;
}
public getAllTasks(): TaskNode {
return this._taskQueue;
}
}