mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-16 17:22:29 -05:00
Agent: Edit Job improvements (#2721)
* fixed right click context menu bug in jobs view * added stepInfo and edit job WIP * show jobs in job edit * added schedule description on select schedule * fetch schedules during history and show in edit job * added alerts to job histories and show in edit * made history calls async * filter menus now close when esc is pressed * fixed bug where clicking on error row wouldnt populate job details
This commit is contained in:
@@ -39,16 +39,26 @@ export class HeaderFilter {
|
||||
this.handler.subscribe(this.grid.onHeaderCellRendered, (e, args) => this.handleHeaderCellRendered(e , args))
|
||||
.subscribe(this.grid.onBeforeHeaderCellDestroy, (e, args) => this.handleBeforeHeaderCellDestroy(e, args))
|
||||
.subscribe(this.grid.onClick, (e) => this.handleBodyMouseDown)
|
||||
.subscribe(this.grid.onColumnsResized, () => this.columnsResized());
|
||||
|
||||
.subscribe(this.grid.onColumnsResized, () => this.columnsResized())
|
||||
.subscribe(this.grid.onKeyDown, (e) => this.handleKeyDown);
|
||||
this.grid.setColumns(this.grid.getColumns());
|
||||
|
||||
$(document.body).bind('mousedown', this.handleBodyMouseDown);
|
||||
$(document.body).bind('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.handler.unsubscribeAll();
|
||||
$(document.body).unbind('mousedown', this.handleBodyMouseDown);
|
||||
$(document.body).unbind('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
private handleKeyDown = (e) => {
|
||||
if (this.$menu && (e.key === 'Escape' || e.keyCode === 27)) {
|
||||
this.hideMenu();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
private handleBodyMouseDown = (e) => {
|
||||
|
||||
@@ -17,7 +17,9 @@ export class JobManagementUtilities {
|
||||
switch(status) {
|
||||
case(0): return nls.localize('agentUtilities.failed','Failed');
|
||||
case(1): return nls.localize('agentUtilities.succeeded', 'Succeeded');
|
||||
case(3): return nls.localize('agentUtilities.canceled', 'Canceled');
|
||||
case(2): return nls.localize('agentUtilities.retry', 'Retry');
|
||||
case(3): return nls.localize('agentUtilities.canceled', 'Cancelled');
|
||||
case(4): return nls.localize('agentUtilities.inProgress', 'In Progress');
|
||||
case(5): return nls.localize('agentUtilities.statusUnknown', 'Status Unknown');
|
||||
default: return nls.localize('agentUtilities.statusUnknown', 'Status Unknown');
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ export class JobHistoryComponent extends JobManagementView implements OnInit {
|
||||
stepViewRow.runStatus = jobStepStatus ? JobManagementUtilities.convertToStatusString(0) :
|
||||
JobManagementUtilities.convertToStatusString(step.runStatus);
|
||||
self._runStatus = JobManagementUtilities.convertToStatusString(self.agentJobHistoryInfo.runStatus);
|
||||
stepViewRow.stepName = step.stepName;
|
||||
stepViewRow.stepID = step.stepId.toString();
|
||||
stepViewRow.stepName = step.stepDetails.stepName;
|
||||
stepViewRow.stepId = step.stepDetails.id.toString();
|
||||
return stepViewRow;
|
||||
});
|
||||
this._showSteps = self._stepRows.length > 0;
|
||||
|
||||
@@ -66,7 +66,7 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
||||
}, { verticalScrollMode: ScrollbarVisibility.Visible });
|
||||
this._register(attachListStyler(this._tree, this.themeService));
|
||||
}
|
||||
this._tree.layout(JobStepsViewComponent._pageSize);
|
||||
this._tree.layout(500);
|
||||
this._tree.setInput(new JobStepsViewModel());
|
||||
$('jobstepsview-component .steps-tree .monaco-tree').attr('tabIndex', '-1');
|
||||
$('jobstepsview-component .steps-tree .monaco-tree-row').attr('tabIndex', '0');
|
||||
@@ -74,8 +74,6 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._tree = new Tree(this._tableContainer.nativeElement, {
|
||||
controller: this._treeController,
|
||||
dataSource: this._treeDataSource,
|
||||
|
||||
@@ -14,7 +14,7 @@ import { AgentJobHistoryInfo } from 'sqlops';
|
||||
import { JobManagementUtilities } from 'sql/parts/jobManagement/common/jobManagementUtilities';
|
||||
|
||||
export class JobStepsViewRow {
|
||||
public stepID: string;
|
||||
public stepId: string;
|
||||
public stepName: string;
|
||||
public message: string;
|
||||
public rowID: string = generateUuid();
|
||||
@@ -121,7 +121,7 @@ export class JobStepsViewRenderer implements tree.IRenderer {
|
||||
public renderElement(tree: tree.ITree, element: JobStepsViewRow, templateId: string, templateData: IListTemplate): void {
|
||||
let stepIdCol: HTMLElement = DOM.$('div');
|
||||
stepIdCol.className = 'tree-id-col';
|
||||
stepIdCol.innerText = element.stepID;
|
||||
stepIdCol.innerText = element.stepId;
|
||||
let stepNameCol: HTMLElement = DOM.$('div');
|
||||
stepNameCol.className = 'tree-name-col';
|
||||
stepNameCol.innerText = element.stepName;
|
||||
|
||||
@@ -37,6 +37,7 @@ import { IDashboardService } from 'sql/services/dashboard/common/dashboardServic
|
||||
import { escape } from 'sql/base/common/strings';
|
||||
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { tableBackground, cellBackground, tableHoverBackground, jobsHeadingBackground, cellBorderColor } from 'sql/common/theme/colors';
|
||||
import { JobStepsViewRow } from 'sql/parts/jobManagement/views/jobStepsViewTree';
|
||||
|
||||
export const JOBSVIEW_SELECTOR: string = 'jobsview-component';
|
||||
export const ROW_HEIGHT: number = 45;
|
||||
@@ -171,7 +172,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
});
|
||||
this.rowDetail = rowDetail;
|
||||
columns.unshift(this.rowDetail.getColumnDefinition());
|
||||
|
||||
let filterPlugin = new HeaderFilter({}, this._themeService);
|
||||
this.filterPlugin = filterPlugin;
|
||||
$(this._gridEl.nativeElement).empty();
|
||||
@@ -475,7 +475,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
case ('Failed'):
|
||||
resultIndicatorClass = 'jobview-jobnameindicatorfailure';
|
||||
break;
|
||||
case ('Canceled'):
|
||||
case ('Cancelled'):
|
||||
resultIndicatorClass = 'jobview-jobnameindicatorcancel';
|
||||
break;
|
||||
case ('Status Unknown'):
|
||||
@@ -523,17 +523,15 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
this.rowDetail.applyTemplateNewLineHeight(item, true);
|
||||
}
|
||||
|
||||
private loadJobHistories(): void {
|
||||
private async loadJobHistories() {
|
||||
if (this.jobs) {
|
||||
let erroredJobs = 0;
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
let separatedJobs = this.separateFailingJobs();
|
||||
// grab histories of the failing jobs first
|
||||
// so they can be expanded quicker
|
||||
let failing = separatedJobs[0];
|
||||
this.curateJobHistory(failing, ownerUri);
|
||||
let passing = separatedJobs[1];
|
||||
this.curateJobHistory(passing, ownerUri);
|
||||
Promise.all([this.curateJobHistory(failing, ownerUri), this.curateJobHistory(passing, ownerUri)]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,11 +576,10 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
return job;
|
||||
}
|
||||
|
||||
private curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
|
||||
private async curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
|
||||
const self = this;
|
||||
for (let i = 0; i < jobs.length; i++) {
|
||||
let job = jobs[i];
|
||||
this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
|
||||
jobs.forEach(async (job) => {
|
||||
await this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
|
||||
if (result && result.jobs) {
|
||||
self.jobHistories[job.jobId] = result.jobs;
|
||||
self._jobCacheObject.setJobHistory(job.jobId, result.jobs);
|
||||
@@ -600,7 +597,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private createJobChart(jobId: string, jobHistories: sqlops.AgentJobHistoryInfo[]): void {
|
||||
@@ -848,6 +845,40 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
return TPromise.as(actions);
|
||||
}
|
||||
|
||||
protected convertStepsToStepInfos(steps: sqlops.AgentJobStep[], job: sqlops.AgentJobInfo): sqlops.AgentJobStepInfo[] {
|
||||
let result = [];
|
||||
steps.forEach(step => {
|
||||
let stepInfo: sqlops.AgentJobStepInfo = {
|
||||
jobId: job.jobId,
|
||||
jobName: job.name,
|
||||
script: null,
|
||||
scriptName: null,
|
||||
stepName: step.stepName,
|
||||
subSystem: null,
|
||||
id: +step.stepId,
|
||||
failureAction: null,
|
||||
successAction: null,
|
||||
failStepId: null,
|
||||
successStepId: null,
|
||||
command: null,
|
||||
commandExecutionSuccessCode: null,
|
||||
databaseName: null,
|
||||
databaseUserName: null,
|
||||
server: null,
|
||||
outputFileName: null,
|
||||
appendToLogFile: null,
|
||||
appendToStepHist: null,
|
||||
writeLogToTable: null,
|
||||
appendLogToTable: null,
|
||||
retryAttempts: null,
|
||||
retryInterval: null,
|
||||
proxyName: null
|
||||
};
|
||||
result.push(stepInfo);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
protected getCurrentTableObject(rowIndex: number): any {
|
||||
let data = this._table.grid.getData();
|
||||
if (!data || rowIndex >= data.getLength()) {
|
||||
@@ -855,10 +886,60 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
}
|
||||
|
||||
let jobId = data.getItem(rowIndex).jobId;
|
||||
let job = this.jobs.filter(job => {
|
||||
if (!jobId) {
|
||||
// if we couldn't find the ID, check if it's an
|
||||
// error row
|
||||
let isErrorRow: boolean = data.getItem(rowIndex).id.indexOf('error') >= 0;
|
||||
if (isErrorRow) {
|
||||
jobId = data.getItem(rowIndex - 1).jobId;
|
||||
}
|
||||
}
|
||||
let job: sqlops.AgentJobInfo[] = this.jobs.filter(job => {
|
||||
return job.jobId === jobId;
|
||||
});
|
||||
|
||||
let jobHistories = this.jobHistories[jobId];
|
||||
let steps: sqlops.AgentJobStep[] = undefined;
|
||||
let schedules: sqlops.AgentJobScheduleInfo[] = undefined;
|
||||
let alerts: sqlops.AgentAlertInfo[] = undefined;
|
||||
if (jobHistories && jobHistories[jobHistories.length-1]) {
|
||||
// add steps
|
||||
steps = jobHistories[jobHistories.length-1].steps;
|
||||
if (steps && steps.length > 0) {
|
||||
if (!job[0].JobSteps) {
|
||||
job[0].JobSteps = [];
|
||||
}
|
||||
if (job[0].JobSteps.length !== steps.length) {
|
||||
job[0].JobSteps = [];
|
||||
steps.forEach(step => {
|
||||
job[0].JobSteps.push(step.stepDetails);
|
||||
});
|
||||
}
|
||||
}
|
||||
// add schedules
|
||||
schedules = jobHistories[jobHistories.length-1].schedules;
|
||||
if (schedules && schedules.length > 0) {
|
||||
if (!job[0].JobSchedules) {
|
||||
job[0].JobSchedules = [];
|
||||
}
|
||||
if (job[0].JobSchedules.length !== schedules.length) {
|
||||
job[0].JobSchedules = [];
|
||||
schedules.forEach(schedule => {
|
||||
job[0].JobSchedules.push(schedule);
|
||||
});
|
||||
}
|
||||
}
|
||||
// add alerts
|
||||
alerts = jobHistories[jobHistories.length-1].alerts;
|
||||
if (!job[0].Alerts) {
|
||||
job[0].Alerts = [];
|
||||
}
|
||||
if (job[0].Alerts.length !== alerts.length) {
|
||||
job[0].Alerts = [];
|
||||
alerts.forEach(alert => {
|
||||
job[0].Alerts.push(alert);
|
||||
});
|
||||
}
|
||||
}
|
||||
return job && job.length > 0 ? job[0] : undefined;
|
||||
}
|
||||
|
||||
|
||||
4
src/sql/sqlops.d.ts
vendored
4
src/sql/sqlops.d.ts
vendored
@@ -1313,6 +1313,7 @@ declare module 'sqlops' {
|
||||
jobCount: number;
|
||||
activeEndDate: string;
|
||||
scheduleUid: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface AgentJobStep {
|
||||
@@ -1322,6 +1323,7 @@ declare module 'sqlops' {
|
||||
message: string;
|
||||
runDate: string;
|
||||
runStatus: number;
|
||||
stepDetails: AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface AgentJobStepInfo {
|
||||
@@ -1369,6 +1371,8 @@ declare module 'sqlops' {
|
||||
retriesAttempted: string;
|
||||
server: string;
|
||||
steps: AgentJobStep[];
|
||||
schedules: AgentJobScheduleInfo[];
|
||||
alerts: AgentAlertInfo[];
|
||||
}
|
||||
|
||||
export interface AgentProxyInfo {
|
||||
|
||||
Reference in New Issue
Block a user