Agent Notebooks Scheduler (#6786)

* added agent notebooks, notebook history view and view materialized notebook button

* Got a basic UI running for viewing notebook history

* made some changes to make UI look good

* Added new notebook dialog

* Added new notebook Dialog

* Added create notebook dialog

* Added edit and delete notebook job

* Added some notebook history features

* Added new notebook job icons, fixed a minor bug
in openmaterializednotebookAPI and added fixed the
schedule Picker API.

* Fixed Bugs in Notebook Grid expansion

* Fixed Notebook table highlighting and
grid generation is done using code.

* fixed some UI bugs

* Added changes to reflect sqltoolservice api

* Fixed some localize keys

* Made changes in the PR and added
ability to open Template Notebooks from
notebook history view.

* Added pin and renaming to notebook history

* made some library calls async

* fixed an import bug caused by merging from master

* Validation in NotebookJobDialog

* Added entry points for scheduling notebooks
on file explorer and notebook editor

* Handled no active connections and
a small bug in collapsing grid

* fix a bug in scheduling notebook from explorer
and toolbar

* setting up agent providers from connection now

* changed modals

* Reupload edited template

* Add dialog info, solved an edit bug and localized
UI strings.

* Bug fixes in UI, notebook renaming and
editing template on fly.

* fixed a bug that failed editing notebook jobs from notebook jobs table

* Fixed a cyclic dependency, made strings const and
some other changes in the PR

* Made some cyclic dependency and some fixes from PR

* made some changes mentioned in the PR

* Changed storage database health text

* Changed the sqltoolservice version to the point to the latest build.
This commit is contained in:
Aasim Khan
2019-09-04 15:12:35 -07:00
committed by GitHub
parent 0a393400b2
commit fbb2accacb
48 changed files with 3948 additions and 149 deletions

View File

@@ -20,6 +20,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
import { JobManagementView } from 'sql/workbench/parts/jobManagement/browser/jobManagementView';
import { NotebooksViewComponent } from 'sql/workbench/parts/jobManagement/browser/notebooksView.component';
import { NotebookHistoryComponent } from 'sql/workbench/parts/jobManagement/browser/notebookHistory.component';
export const successLabel: string = nls.localize('jobaction.successLabel', "Success");
export const errorLabel: string = nls.localize('jobaction.faillabel', "Error");
@@ -171,6 +173,22 @@ export class EditJobAction extends Action {
}
}
export class OpenMaterializedNotebookAction extends Action {
public static ID = 'notebookAction.openNotebook';
public static LABEL = nls.localize('notebookAction.openNotebook', "Open");
constructor(
@ICommandService private _commandService: ICommandService
) {
super(OpenMaterializedNotebookAction.ID, OpenMaterializedNotebookAction.LABEL, 'open');
}
public run(context: any): Promise<boolean> {
context.component.openNotebook(context.history);
return Promise.resolve(true);
}
}
export class DeleteJobAction extends Action {
public static ID = 'jobaction.deleteJob';
public static LABEL = nls.localize('jobaction.deleteJob', "Delete Job");
@@ -282,7 +300,6 @@ export class DeleteStepAction extends Action {
}
}
// Alert Actions
export class NewAlertAction extends Action {
@@ -551,3 +568,167 @@ export class DeleteProxyAction extends Action {
return Promise.resolve(true);
}
}
//Notebook Actions
export class NewNotebookJobAction extends Action {
public static ID = 'notebookaction.newJob';
public static LABEL = nls.localize('notebookaction.newJob', "New Notebook Job");
constructor(
) {
super(NewNotebookJobAction.ID, NewNotebookJobAction.LABEL, 'newStepIcon');
}
public async run(context: IJobActionInfo): Promise<boolean> {
let component = context.component as NotebooksViewComponent;
await component.openCreateNotebookDialog();
return true;
}
}
export class EditNotebookJobAction extends Action {
public static ID = 'notebookaction.editNotebook';
public static LABEL = nls.localize('notebookaction.editJob', "Edit Notebook Job");
constructor(
@ICommandService private _commandService: ICommandService
) {
super(EditNotebookJobAction.ID, EditNotebookJobAction.LABEL, 'edit');
}
public run(actionInfo: IJobActionInfo): Promise<boolean> {
this._commandService.executeCommand(
'agent.openNotebookDialog',
actionInfo.ownerUri,
actionInfo.targetObject.job);
return Promise.resolve(true);
}
}
export class OpenTemplateNotebookAction extends Action {
public static ID = 'notebookaction.openTemplate';
public static LABEL = nls.localize('notebookaction.openNotebook', "Open Template Notebook");
constructor(
@ICommandService private _commandService: ICommandService
) {
super(OpenTemplateNotebookAction.ID, OpenTemplateNotebookAction.LABEL, 'opennotebook');
}
public run(actionInfo: any): Promise<boolean> {
actionInfo.component.openTemplateNotebook();
return Promise.resolve(true);
}
}
export class DeleteNotebookAction extends Action {
public static ID = 'notebookaction.deleteNotebook';
public static LABEL = nls.localize('notebookaction.deleteNotebook', "Delete Notebook");
constructor(
@INotificationService private _notificationService: INotificationService,
@IErrorMessageService private _errorMessageService: IErrorMessageService,
@IJobManagementService private _jobService: IJobManagementService,
@IInstantiationService private instantationService: IInstantiationService,
@ITelemetryService private _telemetryService: ITelemetryService
) {
super(DeleteNotebookAction.ID, DeleteNotebookAction.LABEL);
}
public run(actionInfo: IJobActionInfo): Promise<boolean> {
let self = this;
let notebook = actionInfo.targetObject.job as azdata.AgentNotebookInfo;
let refreshAction = this.instantationService.createInstance(JobsRefreshAction);
self._notificationService.prompt(
Severity.Info,
nls.localize('jobaction.deleteNotebookConfirm', "Are you sure you'd like to delete the notebook '{0}'?", notebook.name),
[{
label: DeleteNotebookAction.LABEL,
run: () => {
this._telemetryService.publicLog(TelemetryKeys.DeleteAgentJob);
self._jobService.deleteNotebook(actionInfo.ownerUri, actionInfo.targetObject.job).then(async (result) => {
if (!result || !result.success) {
await refreshAction.run(actionInfo);
let errorMessage = nls.localize("jobaction.failedToDeleteNotebook", "Could not delete notebook '{0}'.\nError: {1}",
notebook.name, result.errorMessage ? result.errorMessage : 'Unknown error');
self._errorMessageService.showDialog(Severity.Error, errorLabel, errorMessage);
} else {
let successMessage = nls.localize('jobaction.deletedNotebook', "The notebook was successfully deleted");
self._notificationService.info(successMessage);
}
});
}
}, {
label: DeleteAlertAction.CancelLabel,
run: () => { }
}]
);
return Promise.resolve(true);
}
}
export class PinNotebookMaterializedAction extends Action {
public static ID = 'notebookaction.openTemplate';
public static LABEL = nls.localize('notebookaction.pinNotebook', "Pin");
constructor(
@ICommandService private _commandService: ICommandService
) {
super(PinNotebookMaterializedAction.ID, PinNotebookMaterializedAction.LABEL);
}
public run(actionInfo: any): Promise<boolean> {
actionInfo.component.toggleNotebookPin(actionInfo.history, true);
return Promise.resolve(true);
}
}
export class DeleteMaterializedNotebookAction extends Action {
public static ID = 'notebookaction.deleteMaterializedNotebook';
public static LABEL = nls.localize('notebookaction.deleteMaterializedNotebook', "Delete");
constructor(
@ICommandService private _commandService: ICommandService
) {
super(DeleteMaterializedNotebookAction.ID, DeleteMaterializedNotebookAction.LABEL);
}
public run(actionInfo: any): Promise<boolean> {
actionInfo.component.deleteMaterializedNotebook(actionInfo.history);
return Promise.resolve(true);
}
}
export class UnpinNotebookMaterializedAction extends Action {
public static ID = 'notebookaction.unpinNotebook';
public static LABEL = nls.localize('notebookaction.unpinNotebook', "Unpin");
constructor(
@ICommandService private _commandService: ICommandService
) {
super(UnpinNotebookMaterializedAction.ID, UnpinNotebookMaterializedAction.LABEL);
}
public run(actionInfo: any): Promise<boolean> {
actionInfo.component.toggleNotebookPin(actionInfo.history, false);
return Promise.resolve(true);
}
}
export class RenameNotebookMaterializedAction extends Action {
public static ID = 'notebookaction.openTemplate';
public static LABEL = nls.localize('notebookaction.renameNotebook', "Rename");
constructor(
@ICommandService private _commandService: ICommandService,
) {
super(RenameNotebookMaterializedAction.ID, RenameNotebookMaterializedAction.LABEL);
}
public run(actionInfo: any): Promise<boolean> {
actionInfo.component.renameNotebook(actionInfo.history);
return Promise.resolve(true);
}
}

View File

@@ -5,7 +5,7 @@
import * as azdata from 'azdata';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { JobCacheObject, AlertsCacheObject, ProxiesCacheObject, OperatorsCacheObject } from './jobManagementService';
import { JobCacheObject, AlertsCacheObject, ProxiesCacheObject, OperatorsCacheObject, NotebookCacheObject } from './jobManagementService';
import { Event } from 'vs/base/common/event';
export const SERVICE_ID = 'jobManagementService';
@@ -25,6 +25,15 @@ export interface IJobManagementService {
deleteJobStep(connectionUri: string, step: azdata.AgentJobStepInfo): Thenable<azdata.ResultStatus>;
getNotebooks(connectionUri: string): Thenable<azdata.AgentNotebooksResult>;
getNotebookHistory(connectionUri: string, jobId: string, jobName: string, targetDatabase: string): Thenable<azdata.AgentNotebookHistoryResult>;
getMaterialziedNotebook(connectionUri: string, targetDatabase: string, notebookMaterializedId: number): Thenable<azdata.AgentNotebookMaterializedResult>;
getTemplateNotebook(connectionUri: string, targetDatabase: string, jobId: string): Thenable<azdata.AgentNotebookTemplateResult>;
deleteNotebook(connectionUri: string, notebook: azdata.AgentNotebookInfo): Thenable<azdata.ResultStatus>;
deleteMaterializedNotebook(connectionUri: string, agentNotebookHistory: azdata.AgentNotebookHistoryInfo, targetDatabase: string): Thenable<azdata.ResultStatus>;
updateNotebookMaterializedName(connectionUri: string, agentNotebookHistory: azdata.AgentNotebookHistoryInfo, targetDatabase: string, name: string);
updateNotebookMaterializedPin(connectionUri: string, agentNotebookHistory: azdata.AgentNotebookHistoryInfo, targetDatabase: string, pin: boolean);
getAlerts(connectionUri: string): Thenable<azdata.AgentAlertsResult>;
deleteAlert(connectionUri: string, alert: azdata.AgentAlertInfo): Thenable<azdata.ResultStatus>;
@@ -37,10 +46,11 @@ export interface IJobManagementService {
getCredentials(connectionUri: string): Thenable<azdata.GetCredentialsResult>;
jobAction(connectionUri: string, jobName: string, action: string): Thenable<azdata.ResultStatus>;
addToCache(server: string, cache: JobCacheObject | OperatorsCacheObject);
addToCache(server: string, cache: JobCacheObject | OperatorsCacheObject | NotebookCacheObject);
jobCacheObjectMap: { [server: string]: JobCacheObject; };
notebookCacheObjectMap: { [server: string]: NotebookCacheObject; };
operatorsCacheObjectMap: { [server: string]: OperatorsCacheObject; };
alertsCacheObjectMap: { [server: string]: AlertsCacheObject; };
proxiesCacheObjectMap: { [server: string]: ProxiesCacheObject };
addToCache(server: string, cache: JobCacheObject | ProxiesCacheObject | AlertsCacheObject | OperatorsCacheObject);
}
addToCache(server: string, cache: JobCacheObject | ProxiesCacheObject | AlertsCacheObject | OperatorsCacheObject | NotebookCacheObject);
}

View File

@@ -20,7 +20,7 @@ export class JobManagementService implements IJobManagementService {
private _operatorsCacheObjectMap: { [server: string]: OperatorsCacheObject; } = {};
private _alertsCacheObject: { [server: string]: AlertsCacheObject; } = {};
private _proxiesCacheObjectMap: { [server: string]: ProxiesCacheObject; } = {};
private _notebookCacheObjectMap: { [server: string]: NotebookCacheObject; } = {};
constructor(
@IConnectionManagementService private _connectionService: IConnectionManagementService
) {
@@ -62,6 +62,54 @@ export class JobManagementService implements IJobManagementService {
});
}
// Notebooks
public getNotebooks(connectionUri: string): Thenable<azdata.AgentNotebooksResult> {
return this._runAction(connectionUri, (runner) => {
return runner.getNotebooks(connectionUri);
});
}
public getNotebookHistory(connectionUri: string, jobID: string, jobName: string, targetDatabase: string): Thenable<azdata.AgentNotebookHistoryResult> {
return this._runAction(connectionUri, (runner) => {
return runner.getNotebookHistory(connectionUri, jobID, jobName, targetDatabase);
});
}
public getMaterialziedNotebook(connectionUri: string, targetDatabase: string, notebookMaterializedId: number): Thenable<azdata.AgentNotebookMaterializedResult> {
return this._runAction(connectionUri, (runner) => {
return runner.getMaterializedNotebook(connectionUri, targetDatabase, notebookMaterializedId);
});
}
public getTemplateNotebook(connectionUri: string, targetDatabase: string, jobId: string): Thenable<azdata.AgentNotebookTemplateResult> {
return this._runAction(connectionUri, (runner) => {
return runner.getTemplateNotebook(connectionUri, targetDatabase, jobId);
});
}
public deleteNotebook(connectionUri: string, notebook: azdata.AgentNotebookInfo): Thenable<azdata.ResultStatus> {
return this._runAction(connectionUri, (runner) => {
return runner.deleteNotebook(connectionUri, notebook);
});
}
public deleteMaterializedNotebook(connectionUri: string, agentNotebookHistory: azdata.AgentNotebookHistoryInfo, targetDatabase: string): Thenable<azdata.ResultStatus> {
return this._runAction(connectionUri, (runner) => {
return runner.deleteMaterializedNotebook(connectionUri, agentNotebookHistory, targetDatabase);
});
}
public updateNotebookMaterializedName(connectionUri: string, agentNotebookHistory: azdata.AgentNotebookHistoryInfo, targetDatabase: string, name: string): Thenable<azdata.ResultStatus> {
return this._runAction(connectionUri, (runner) => {
return runner.updateNotebookMaterializedName(connectionUri, agentNotebookHistory, targetDatabase, name);
});
}
public updateNotebookMaterializedPin(connectionUri: string, agentNotebookHistory: azdata.AgentNotebookHistoryInfo, targetDatabase: string, pin: boolean): Thenable<azdata.ResultStatus> {
return this._runAction(connectionUri, (runner) => {
return runner.updateNotebookMaterializedPin(connectionUri, agentNotebookHistory, targetDatabase, pin);
});
}
// Alerts
public getAlerts(connectionUri: string): Thenable<azdata.AgentAlertsResult> {
@@ -134,6 +182,10 @@ export class JobManagementService implements IJobManagementService {
return this._alertsCacheObject;
}
public get notebookCacheObjectMap(): { [server: string]: NotebookCacheObject; } {
return this._notebookCacheObjectMap;
}
public get proxiesCacheObjectMap(): { [server: string]: ProxiesCacheObject; } {
return this._proxiesCacheObjectMap;
}
@@ -142,7 +194,7 @@ export class JobManagementService implements IJobManagementService {
return this._operatorsCacheObjectMap;
}
public addToCache(server: string, cacheObject: JobCacheObject | OperatorsCacheObject | ProxiesCacheObject | AlertsCacheObject) {
public addToCache(server: string, cacheObject: JobCacheObject | OperatorsCacheObject | ProxiesCacheObject | AlertsCacheObject | NotebookCacheObject) {
if (cacheObject instanceof JobCacheObject) {
this._jobCacheObjectMap[server] = cacheObject;
} else if (cacheObject instanceof OperatorsCacheObject) {
@@ -151,6 +203,8 @@ export class JobManagementService implements IJobManagementService {
this._alertsCacheObject[server] = cacheObject;
} else if (cacheObject instanceof ProxiesCacheObject) {
this._proxiesCacheObjectMap[server] = cacheObject;
} else if (cacheObject instanceof NotebookCacheObject) {
this._notebookCacheObjectMap[server] = cacheObject;
}
}
}
@@ -252,6 +306,94 @@ export class JobCacheObject {
this._jobSchedules[jobID] = value;
}
}
/**
* Server level caching of Operators
*/
export class NotebookCacheObject {
_serviceBrand: any;
private _notebooks: azdata.AgentNotebookInfo[] = [];
private _notebookHistories: { [jobID: string]: azdata.AgentNotebookHistoryInfo[]; } = {};
private _jobSteps: { [jobID: string]: azdata.AgentJobStepInfo[]; } = {};
private _jobSchedules: { [jobID: string]: azdata.AgentJobScheduleInfo[]; } = {};
private _runCharts: { [jobID: string]: string[]; } = {};
private _prevJobID: string;
private _serverName: string;
private _dataView: Slick.Data.DataView<any>;
/* Getters */
public get notebooks(): azdata.AgentNotebookInfo[] {
return this._notebooks;
}
public get notebookHistories(): { [jobID: string]: azdata.AgentNotebookHistoryInfo[] } {
return this._notebookHistories;
}
public get prevJobID(): string {
return this._prevJobID;
}
public getNotebookHistory(jobID: string): azdata.AgentNotebookHistoryInfo[] {
return this._notebookHistories[jobID];
}
public get serverName(): string {
return this._serverName;
}
public get dataView(): Slick.Data.DataView<any> {
return this._dataView;
}
public getRunChart(jobID: string): string[] {
return this._runCharts[jobID];
}
public getJobSteps(jobID: string): azdata.AgentJobStepInfo[] {
return this._jobSteps[jobID];
}
public getJobSchedules(jobID: string): azdata.AgentJobScheduleInfo[] {
return this._jobSchedules[jobID];
}
/* Setters */
public set notebooks(value: azdata.AgentNotebookInfo[]) {
this._notebooks = value;
}
public set notebookHistories(value: { [jobID: string]: azdata.AgentNotebookHistoryInfo[]; }) {
this._notebookHistories = value;
}
public set prevJobID(value: string) {
this._prevJobID = value;
}
public setNotebookHistory(jobID: string, value: azdata.AgentNotebookHistoryInfo[]) {
this._notebookHistories[jobID] = value;
}
public setRunChart(jobID: string, value: string[]) {
this._runCharts[jobID] = value;
}
public set serverName(value: string) {
this._serverName = value;
}
public set dataView(value: Slick.Data.DataView<any>) {
this._dataView = value;
}
public setJobSteps(jobID: string, value: azdata.AgentJobStepInfo[]) {
this._jobSteps[jobID] = value;
}
public setJobSchedules(jobID: string, value: azdata.AgentJobScheduleInfo[]) {
this._jobSchedules[jobID] = value;
}
}
/**
* Server level caching of Operators
@@ -364,4 +506,4 @@ export class ProxiesCacheObject {
public set serverName(value: string) {
this._serverName = value;
}
}
}