mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -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:
@@ -59,6 +59,9 @@ export class JobData implements IAgentDialogData {
|
|||||||
this.category = jobInfo.category;
|
this.category = jobInfo.category;
|
||||||
this.description = jobInfo.description;
|
this.description = jobInfo.description;
|
||||||
this.enabled = jobInfo.enabled;
|
this.enabled = jobInfo.enabled;
|
||||||
|
this.jobSteps = jobInfo.JobSteps;
|
||||||
|
this.jobSchedules = jobInfo.JobSchedules;
|
||||||
|
this.alerts = jobInfo.Alerts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,8 +108,6 @@ export class JobData implements IAgentDialogData {
|
|||||||
displayName: this.JobCompletionActionCondition_Always,
|
displayName: this.JobCompletionActionCondition_Always,
|
||||||
name: sqlops.JobCompletionActionCondition.Always.toString()
|
name: sqlops.JobCompletionActionCondition.Always.toString()
|
||||||
}];
|
}];
|
||||||
|
|
||||||
this.jobSchedules = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async save() {
|
public async save() {
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
private readonly AlertsTopLabelString: string = localize('jobDialog.alertsList', 'Alerts list');
|
private readonly AlertsTopLabelString: string = localize('jobDialog.alertsList', 'Alerts list');
|
||||||
private readonly NewAlertButtonString: string = localize('jobDialog.newAlert', 'New Alert');
|
private readonly NewAlertButtonString: string = localize('jobDialog.newAlert', 'New Alert');
|
||||||
private readonly AlertNameLabelString: string = localize('jobDialog.alertNameLabel', 'Alert Name');
|
private readonly AlertNameLabelString: string = localize('jobDialog.alertNameLabel', 'Alert Name');
|
||||||
|
private readonly AlertEnabledLabelString: string = localize('jobDialog.alertEnabledLabel', 'Enabled');
|
||||||
|
private readonly AlertTypeLabelString: string = localize('jobDialog.alertTypeLabel', 'Type');
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||||
@@ -197,6 +199,8 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
.withProperties({
|
.withProperties({
|
||||||
value: 'Feature Preview'
|
value: 'Feature Preview'
|
||||||
}).component();
|
}).component();
|
||||||
|
let steps = this.model.jobSteps ? this.model.jobSteps : [];
|
||||||
|
let data = this.convertStepsToData(steps);
|
||||||
this.stepsTable = view.modelBuilder.table()
|
this.stepsTable = view.modelBuilder.table()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
columns: [
|
columns: [
|
||||||
@@ -206,8 +210,8 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
this.StepsTable_SuccessColumnString,
|
this.StepsTable_SuccessColumnString,
|
||||||
this.StepsTable_FailureColumnString
|
this.StepsTable_FailureColumnString
|
||||||
],
|
],
|
||||||
data: [],
|
data: data,
|
||||||
height: 430
|
height: 750
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.moveStepUpButton = view.modelBuilder.button()
|
this.moveStepUpButton = view.modelBuilder.button()
|
||||||
@@ -250,6 +254,31 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.stepsTable.enabled = false;
|
this.stepsTable.enabled = false;
|
||||||
|
this.editStepButton.enabled = false;
|
||||||
|
this.deleteStepButton.enabled = false;
|
||||||
|
|
||||||
|
this.stepsTable.onRowSelected(() => {
|
||||||
|
// only let edit or delete steps if there's
|
||||||
|
// one step selection
|
||||||
|
if (this.stepsTable.selectedRows.length === 1) {
|
||||||
|
let rowNumber = this.stepsTable.selectedRows[0];
|
||||||
|
let stepData = steps[rowNumber];
|
||||||
|
this.deleteStepButton.enabled = true;
|
||||||
|
this.editStepButton.enabled = true;
|
||||||
|
this.editStepButton.onDidClick((e) => {
|
||||||
|
// implement edit steps
|
||||||
|
|
||||||
|
// let stepDialog = new JobStepDialog(this.model.ownerUri, this.nameTextBox.value, '' , 1, this.model);
|
||||||
|
// stepDialog.openNewStepDialog();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.deleteStepButton.onDidClick((e) => {
|
||||||
|
// implement delete steps
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let formModel = view.modelBuilder.formContainer()
|
let formModel = view.modelBuilder.formContainer()
|
||||||
.withFormItems([{
|
.withFormItems([{
|
||||||
@@ -271,12 +300,16 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
.withProperties({
|
.withProperties({
|
||||||
value: 'Feature Preview'
|
value: 'Feature Preview'
|
||||||
}).component();
|
}).component();
|
||||||
|
let alerts = this.model.alerts ? this.model.alerts : [];
|
||||||
|
let data = this.convertAlertsToData(alerts);
|
||||||
this.alertsTable = view.modelBuilder.table()
|
this.alertsTable = view.modelBuilder.table()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
columns: [
|
columns: [
|
||||||
this.AlertNameLabelString
|
this.AlertNameLabelString,
|
||||||
|
this.AlertEnabledLabelString,
|
||||||
|
this.AlertTypeLabelString
|
||||||
],
|
],
|
||||||
data: [],
|
data: data,
|
||||||
height: 430,
|
height: 430,
|
||||||
width: 400
|
width: 400
|
||||||
}).component();
|
}).component();
|
||||||
@@ -312,10 +345,12 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
this.schedulesTable = view.modelBuilder.table()
|
this.schedulesTable = view.modelBuilder.table()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
columns: [
|
columns: [
|
||||||
this.ScheduleNameLabelString
|
PickScheduleDialog.SchedulesIDText,
|
||||||
|
PickScheduleDialog.ScheduleNameLabelText,
|
||||||
|
PickScheduleDialog.ScheduleDescription
|
||||||
],
|
],
|
||||||
data: [],
|
data: [],
|
||||||
height: 430,
|
height: 750,
|
||||||
width: 420
|
width: 420
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
@@ -350,13 +385,11 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private populateScheduleTable() {
|
private populateScheduleTable() {
|
||||||
if (this.model.jobSchedules) {
|
let schedules = this.model.jobSchedules ? this.model.jobSchedules : [];
|
||||||
let data: any[][] = [];
|
let data = this.convertSchedulesToData(schedules);
|
||||||
for (let i = 0; i < this.model.jobSchedules.length; ++i) {
|
if (data.length > 0) {
|
||||||
let schedule = this.model.jobSchedules[i];
|
|
||||||
data[i] = [ schedule.name ];
|
|
||||||
}
|
|
||||||
this.schedulesTable.data = data;
|
this.schedulesTable.data = data;
|
||||||
|
this.schedulesTable.height = 750;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +499,45 @@ export class JobDialog extends AgentDialog<JobData> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private convertStepsToData(jobSteps: sqlops.AgentJobStepInfo[]): any[][] {
|
||||||
|
let result = [];
|
||||||
|
jobSteps.forEach(jobStep => {
|
||||||
|
let cols = [];
|
||||||
|
cols.push(jobStep.id);
|
||||||
|
cols.push(jobStep.stepName);
|
||||||
|
cols.push(jobStep.subSystem);
|
||||||
|
cols.push(jobStep.successAction);
|
||||||
|
cols.push(jobStep.failureAction);
|
||||||
|
result.push(cols);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertSchedulesToData(jobSchedules: sqlops.AgentJobScheduleInfo[]): any[][] {
|
||||||
|
let result = [];
|
||||||
|
jobSchedules.forEach(schedule => {
|
||||||
|
let cols = [];
|
||||||
|
cols.push(schedule.id);
|
||||||
|
cols.push(schedule.name);
|
||||||
|
cols.push(schedule.description);
|
||||||
|
result.push(cols);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertAlertsToData(alerts: sqlops.AgentAlertInfo[]): any[][] {
|
||||||
|
let result = [];
|
||||||
|
alerts.forEach(alert => {
|
||||||
|
let cols = [];
|
||||||
|
console.log(alert);
|
||||||
|
cols.push(alert.name);
|
||||||
|
cols.push(alert.isEnabled);
|
||||||
|
cols.push(alert.alertType.toString());
|
||||||
|
result.push(cols);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
protected updateModel() {
|
protected updateModel() {
|
||||||
this.model.name = this.nameTextBox.value;
|
this.model.name = this.nameTextBox.value;
|
||||||
this.model.owner = this.ownerTextBox.value;
|
this.model.owner = this.ownerTextBox.value;
|
||||||
|
|||||||
@@ -18,8 +18,11 @@ export class PickScheduleDialog {
|
|||||||
private readonly DialogTitle: string = localize('pickSchedule.jobSchedules', 'Job Schedules');
|
private readonly DialogTitle: string = localize('pickSchedule.jobSchedules', 'Job Schedules');
|
||||||
private readonly OkButtonText: string = localize('pickSchedule.ok', 'OK');
|
private readonly OkButtonText: string = localize('pickSchedule.ok', 'OK');
|
||||||
private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel');
|
private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel');
|
||||||
private readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Schedule Name');
|
private readonly SchedulesLabelText: string = localize('pickSchedule.availableSchedules', 'Available Schedules:');
|
||||||
private readonly SchedulesLabelText: string = localize('pickSchedule.schedules', 'Schedules');
|
public static readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Name');
|
||||||
|
public static readonly SchedulesIDText: string = localize('pickSchedule.scheduleID','ID');
|
||||||
|
public static readonly ScheduleDescription: string = localize('pickSchedule.description','Description');
|
||||||
|
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
private dialog: sqlops.window.modelviewdialog.Dialog;
|
private dialog: sqlops.window.modelviewdialog.Dialog;
|
||||||
@@ -50,11 +53,13 @@ export class PickScheduleDialog {
|
|||||||
this.schedulesTable = view.modelBuilder.table()
|
this.schedulesTable = view.modelBuilder.table()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
columns: [
|
columns: [
|
||||||
this.ScheduleNameLabelText
|
PickScheduleDialog.SchedulesIDText,
|
||||||
|
PickScheduleDialog.ScheduleNameLabelText,
|
||||||
|
PickScheduleDialog.ScheduleDescription
|
||||||
],
|
],
|
||||||
data: [],
|
data: [],
|
||||||
height: '80em',
|
height: 750,
|
||||||
width: '40em'
|
width: 430
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
let formModel = view.modelBuilder.formContainer()
|
let formModel = view.modelBuilder.formContainer()
|
||||||
@@ -69,7 +74,8 @@ export class PickScheduleDialog {
|
|||||||
let data: any[][] = [];
|
let data: any[][] = [];
|
||||||
for (let i = 0; i < this.model.schedules.length; ++i) {
|
for (let i = 0; i < this.model.schedules.length; ++i) {
|
||||||
let schedule = this.model.schedules[i];
|
let schedule = this.model.schedules[i];
|
||||||
data[i] = [ schedule.name ];
|
console.log(schedule);
|
||||||
|
data[i] = [ schedule.id, schedule.name, schedule.description ];
|
||||||
}
|
}
|
||||||
this.schedulesTable.data = data;
|
this.schedulesTable.data = data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,16 +39,26 @@ export class HeaderFilter {
|
|||||||
this.handler.subscribe(this.grid.onHeaderCellRendered, (e, args) => this.handleHeaderCellRendered(e , args))
|
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.onBeforeHeaderCellDestroy, (e, args) => this.handleBeforeHeaderCellDestroy(e, args))
|
||||||
.subscribe(this.grid.onClick, (e) => this.handleBodyMouseDown)
|
.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());
|
this.grid.setColumns(this.grid.getColumns());
|
||||||
|
|
||||||
$(document.body).bind('mousedown', this.handleBodyMouseDown);
|
$(document.body).bind('mousedown', this.handleBodyMouseDown);
|
||||||
|
$(document.body).bind('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this.handler.unsubscribeAll();
|
this.handler.unsubscribeAll();
|
||||||
$(document.body).unbind('mousedown', this.handleBodyMouseDown);
|
$(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) => {
|
private handleBodyMouseDown = (e) => {
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ export class JobManagementUtilities {
|
|||||||
switch(status) {
|
switch(status) {
|
||||||
case(0): return nls.localize('agentUtilities.failed','Failed');
|
case(0): return nls.localize('agentUtilities.failed','Failed');
|
||||||
case(1): return nls.localize('agentUtilities.succeeded', 'Succeeded');
|
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');
|
case(5): return nls.localize('agentUtilities.statusUnknown', 'Status Unknown');
|
||||||
default: 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) :
|
stepViewRow.runStatus = jobStepStatus ? JobManagementUtilities.convertToStatusString(0) :
|
||||||
JobManagementUtilities.convertToStatusString(step.runStatus);
|
JobManagementUtilities.convertToStatusString(step.runStatus);
|
||||||
self._runStatus = JobManagementUtilities.convertToStatusString(self.agentJobHistoryInfo.runStatus);
|
self._runStatus = JobManagementUtilities.convertToStatusString(self.agentJobHistoryInfo.runStatus);
|
||||||
stepViewRow.stepName = step.stepName;
|
stepViewRow.stepName = step.stepDetails.stepName;
|
||||||
stepViewRow.stepID = step.stepId.toString();
|
stepViewRow.stepId = step.stepDetails.id.toString();
|
||||||
return stepViewRow;
|
return stepViewRow;
|
||||||
});
|
});
|
||||||
this._showSteps = self._stepRows.length > 0;
|
this._showSteps = self._stepRows.length > 0;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
|||||||
}, { verticalScrollMode: ScrollbarVisibility.Visible });
|
}, { verticalScrollMode: ScrollbarVisibility.Visible });
|
||||||
this._register(attachListStyler(this._tree, this.themeService));
|
this._register(attachListStyler(this._tree, this.themeService));
|
||||||
}
|
}
|
||||||
this._tree.layout(JobStepsViewComponent._pageSize);
|
this._tree.layout(500);
|
||||||
this._tree.setInput(new JobStepsViewModel());
|
this._tree.setInput(new JobStepsViewModel());
|
||||||
$('jobstepsview-component .steps-tree .monaco-tree').attr('tabIndex', '-1');
|
$('jobstepsview-component .steps-tree .monaco-tree').attr('tabIndex', '-1');
|
||||||
$('jobstepsview-component .steps-tree .monaco-tree-row').attr('tabIndex', '0');
|
$('jobstepsview-component .steps-tree .monaco-tree-row').attr('tabIndex', '0');
|
||||||
@@ -74,8 +74,6 @@ export class JobStepsViewComponent extends JobManagementView implements OnInit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|
||||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
|
||||||
this._tree = new Tree(this._tableContainer.nativeElement, {
|
this._tree = new Tree(this._tableContainer.nativeElement, {
|
||||||
controller: this._treeController,
|
controller: this._treeController,
|
||||||
dataSource: this._treeDataSource,
|
dataSource: this._treeDataSource,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { AgentJobHistoryInfo } from 'sqlops';
|
|||||||
import { JobManagementUtilities } from 'sql/parts/jobManagement/common/jobManagementUtilities';
|
import { JobManagementUtilities } from 'sql/parts/jobManagement/common/jobManagementUtilities';
|
||||||
|
|
||||||
export class JobStepsViewRow {
|
export class JobStepsViewRow {
|
||||||
public stepID: string;
|
public stepId: string;
|
||||||
public stepName: string;
|
public stepName: string;
|
||||||
public message: string;
|
public message: string;
|
||||||
public rowID: string = generateUuid();
|
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 {
|
public renderElement(tree: tree.ITree, element: JobStepsViewRow, templateId: string, templateData: IListTemplate): void {
|
||||||
let stepIdCol: HTMLElement = DOM.$('div');
|
let stepIdCol: HTMLElement = DOM.$('div');
|
||||||
stepIdCol.className = 'tree-id-col';
|
stepIdCol.className = 'tree-id-col';
|
||||||
stepIdCol.innerText = element.stepID;
|
stepIdCol.innerText = element.stepId;
|
||||||
let stepNameCol: HTMLElement = DOM.$('div');
|
let stepNameCol: HTMLElement = DOM.$('div');
|
||||||
stepNameCol.className = 'tree-name-col';
|
stepNameCol.className = 'tree-name-col';
|
||||||
stepNameCol.innerText = element.stepName;
|
stepNameCol.innerText = element.stepName;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { IDashboardService } from 'sql/services/dashboard/common/dashboardServic
|
|||||||
import { escape } from 'sql/base/common/strings';
|
import { escape } from 'sql/base/common/strings';
|
||||||
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { tableBackground, cellBackground, tableHoverBackground, jobsHeadingBackground, cellBorderColor } from 'sql/common/theme/colors';
|
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 JOBSVIEW_SELECTOR: string = 'jobsview-component';
|
||||||
export const ROW_HEIGHT: number = 45;
|
export const ROW_HEIGHT: number = 45;
|
||||||
@@ -171,7 +172,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
|||||||
});
|
});
|
||||||
this.rowDetail = rowDetail;
|
this.rowDetail = rowDetail;
|
||||||
columns.unshift(this.rowDetail.getColumnDefinition());
|
columns.unshift(this.rowDetail.getColumnDefinition());
|
||||||
|
|
||||||
let filterPlugin = new HeaderFilter({}, this._themeService);
|
let filterPlugin = new HeaderFilter({}, this._themeService);
|
||||||
this.filterPlugin = filterPlugin;
|
this.filterPlugin = filterPlugin;
|
||||||
$(this._gridEl.nativeElement).empty();
|
$(this._gridEl.nativeElement).empty();
|
||||||
@@ -475,7 +475,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
|||||||
case ('Failed'):
|
case ('Failed'):
|
||||||
resultIndicatorClass = 'jobview-jobnameindicatorfailure';
|
resultIndicatorClass = 'jobview-jobnameindicatorfailure';
|
||||||
break;
|
break;
|
||||||
case ('Canceled'):
|
case ('Cancelled'):
|
||||||
resultIndicatorClass = 'jobview-jobnameindicatorcancel';
|
resultIndicatorClass = 'jobview-jobnameindicatorcancel';
|
||||||
break;
|
break;
|
||||||
case ('Status Unknown'):
|
case ('Status Unknown'):
|
||||||
@@ -523,17 +523,15 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
|||||||
this.rowDetail.applyTemplateNewLineHeight(item, true);
|
this.rowDetail.applyTemplateNewLineHeight(item, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadJobHistories(): void {
|
private async loadJobHistories() {
|
||||||
if (this.jobs) {
|
if (this.jobs) {
|
||||||
let erroredJobs = 0;
|
|
||||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||||
let separatedJobs = this.separateFailingJobs();
|
let separatedJobs = this.separateFailingJobs();
|
||||||
// grab histories of the failing jobs first
|
// grab histories of the failing jobs first
|
||||||
// so they can be expanded quicker
|
// so they can be expanded quicker
|
||||||
let failing = separatedJobs[0];
|
let failing = separatedJobs[0];
|
||||||
this.curateJobHistory(failing, ownerUri);
|
|
||||||
let passing = separatedJobs[1];
|
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;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
private curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
|
private async curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
|
||||||
const self = this;
|
const self = this;
|
||||||
for (let i = 0; i < jobs.length; i++) {
|
jobs.forEach(async (job) => {
|
||||||
let job = jobs[i];
|
await this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
|
||||||
this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
|
|
||||||
if (result && result.jobs) {
|
if (result && result.jobs) {
|
||||||
self.jobHistories[job.jobId] = result.jobs;
|
self.jobHistories[job.jobId] = result.jobs;
|
||||||
self._jobCacheObject.setJobHistory(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 {
|
private createJobChart(jobId: string, jobHistories: sqlops.AgentJobHistoryInfo[]): void {
|
||||||
@@ -848,6 +845,40 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
|||||||
return TPromise.as(actions);
|
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 {
|
protected getCurrentTableObject(rowIndex: number): any {
|
||||||
let data = this._table.grid.getData();
|
let data = this._table.grid.getData();
|
||||||
if (!data || rowIndex >= data.getLength()) {
|
if (!data || rowIndex >= data.getLength()) {
|
||||||
@@ -855,10 +886,60 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let jobId = data.getItem(rowIndex).jobId;
|
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;
|
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;
|
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;
|
jobCount: number;
|
||||||
activeEndDate: string;
|
activeEndDate: string;
|
||||||
scheduleUid: string;
|
scheduleUid: string;
|
||||||
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentJobStep {
|
export interface AgentJobStep {
|
||||||
@@ -1322,6 +1323,7 @@ declare module 'sqlops' {
|
|||||||
message: string;
|
message: string;
|
||||||
runDate: string;
|
runDate: string;
|
||||||
runStatus: number;
|
runStatus: number;
|
||||||
|
stepDetails: AgentJobStepInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentJobStepInfo {
|
export interface AgentJobStepInfo {
|
||||||
@@ -1369,6 +1371,8 @@ declare module 'sqlops' {
|
|||||||
retriesAttempted: string;
|
retriesAttempted: string;
|
||||||
server: string;
|
server: string;
|
||||||
steps: AgentJobStep[];
|
steps: AgentJobStep[];
|
||||||
|
schedules: AgentJobScheduleInfo[];
|
||||||
|
alerts: AgentAlertInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentProxyInfo {
|
export interface AgentProxyInfo {
|
||||||
|
|||||||
Reference in New Issue
Block a user