Agent: Previous Runs chart functionality (#1564)

* added basic prev run chart functionality

* removed dead code

* resizing columns generates charts again
This commit is contained in:
Aditya Bist
2018-06-12 09:28:40 -07:00
committed by GitHub
parent 733bb69d25
commit 6d89b9e203
5 changed files with 110 additions and 15 deletions

View File

@@ -86,7 +86,7 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
}).filter(i => !!i);
}
this._tasks = tasks.map(i => MenuRegistry.getCommand(i));
this._tasks = tasks.map(i => MenuRegistry.getCommand(i)).filter(v => !!v);
}
ngOnInit() {

View File

@@ -93,6 +93,12 @@ export class AgentJobUtilities {
}
}
public static convertDurationToSeconds(duration: string): number {
let split = duration.split(':');
let seconds = (+split[0]) * 60 * 60 + (+split[1]) * 60 + (+split[2]);
return seconds;
}
public static convertColFieldToName(colField: string) {
switch(colField) {
case('name'):

View File

@@ -205,4 +205,25 @@ agentview-component .jobview-grid .grid-canvas > .ui-widget-content.slick-row.od
#jobsDiv jobsview-component .jobview-grid .slick-cell.l1.r1.error-row td.jobview-jobnameindicatorfailure {
width: 0;
background: none;
}
table.jobprevruns div.bar1, table.jobprevruns div.bar2, table.jobprevruns div.bar3,
table.jobprevruns div.bar4, table.jobprevruns div.bar5 {
padding-top: 3px;
padding-left: 5px;
width: 10px;
}
.jobview-grid .slick-cell.l10.r10 {
text-align: center;
display: inline-flex;
}
table.jobprevruns {
margin: auto;
height: 100%;
}
table.jobprevruns > tbody {
vertical-align: bottom;
}

View File

@@ -245,6 +245,3 @@ jobhistory-component > .actionbar-container .monaco-action-bar > ul.actions-cont
border-top: 3px solid #444444;
}

View File

@@ -55,16 +55,18 @@ export class JobsViewComponent implements AfterContentChecked {
private columns: Array<Slick.Column<any>> = [
{ name: nls.localize('jobColumns.name','Name'), field: 'name', formatter: (row, cell, value, columnDef, dataContext) => this.renderName(row, cell, value, columnDef, dataContext), width: 200 , id: 'name' },
{ name: nls.localize('jobColumns.lastRun','Last Run'), field: 'lastRun', minWidth: 150, id: 'lastRun' },
{ name: nls.localize('jobColumns.nextRun','Next Run'), field: 'nextRun', minWidth: 150, id: 'nextRun' },
{ name: nls.localize('jobColumns.enabled','Enabled'), field: 'enabled', minWidth: 70, id: 'enabled' },
{ name: nls.localize('jobColumns.status','Status'), field: 'currentExecutionStatus', minWidth: 60, id: 'currentExecutionStatus' },
{ name: nls.localize('jobColumns.category','Category'), field: 'category', minWidth: 150, id: 'category' },
{ name: nls.localize('jobColumns.runnable','Runnable'), field: 'runnable', minWidth: 50, id: 'runnable' },
{ name: nls.localize('jobColumns.schedule','Schedule'), field: 'hasSchedule', minWidth: 50, id: 'hasSchedule' },
{ name: nls.localize('jobColumns.lastRunOutcome', 'Last Run Outcome'), field: 'lastRunOutcome', minWidth: 150, id: 'lastRunOutcome'},
{ name: nls.localize('jobColumns.lastRun','Last Run'), field: 'lastRun', width: 120, id: 'lastRun' },
{ name: nls.localize('jobColumns.nextRun','Next Run'), field: 'nextRun', width: 120, id: 'nextRun' },
{ name: nls.localize('jobColumns.enabled','Enabled'), field: 'enabled', width: 50, id: 'enabled' },
{ name: nls.localize('jobColumns.status','Status'), field: 'currentExecutionStatus', width: 60, id: 'currentExecutionStatus' },
{ name: nls.localize('jobColumns.category','Category'), field: 'category', width: 120, id: 'category' },
{ name: nls.localize('jobColumns.runnable','Runnable'), field: 'runnable', width: 70, id: 'runnable' },
{ name: nls.localize('jobColumns.schedule','Schedule'), field: 'hasSchedule', width: 60, id: 'hasSchedule' },
{ name: nls.localize('jobColumns.lastRunOutcome', 'Last Run Outcome'), field: 'lastRunOutcome', width: 120, id: 'lastRunOutcome' },
{ name: nls.localize('jobColumns.previousRuns', 'Previous Runs'), formatter: this.renderChartsPostHistory, field: 'previousRuns', width: 80, id: 'previousRuns'}
];
private options: Slick.GridOptions<any> = {
syncColumnCellResize: true,
enableColumnReorder: false,
@@ -349,6 +351,14 @@ export class JobsViewComponent implements AfterContentChecked {
$('#jobsDiv .jobview-grid .slick-cell.l1.r1 .jobview-jobnametext').css('width', `${nameWidth - 10}px`);
// adjust error message when resized
$('#jobsDiv .jobview-grid .slick-cell.l1.r1.error-row .jobview-jobnametext').css('width', '100%');
// generate job charts again
self.jobs.forEach(job => {
let jobId = job.jobId;
let jobHistories = self._jobCacheObject.getJobHistory(job.jobId);
let previousRuns = jobHistories.slice(jobHistories.length-5, jobHistories.length);
self.createJobChart(job.jobId, previousRuns);
});
});
// cache the dataview for future use
this._jobCacheObject.dataView = this.dataView;
@@ -369,7 +379,8 @@ export class JobsViewComponent implements AfterContentChecked {
'category': errorClass,
'runnable': errorClass,
'hasSchedule': errorClass,
'lastRunOutcome': errorClass
'lastRunOutcome': errorClass,
'previousRuns': errorClass
};
return hash;
}
@@ -424,6 +435,17 @@ export class JobsViewComponent implements AfterContentChecked {
'</tr></table>';
}
private renderChartsPostHistory(row, cell, value, columnDef, dataContext) {
return `<table class="jobprevruns" id="${dataContext.id}">
<tr>
<td><div class="bar1"></div></td>
<td><div class="bar2"></div></td>
<td><div class="bar3"></div></td>
<td><div class="bar4"></div></td>
</tr>
</table>`;
}
private expandJobRowDetails(rowIdx: number, message?: string): void {
let item = this.dataView.getItemByIdx(rowIdx);
item.message = this._agentViewComponent.expanded.get(item.jobId);
@@ -493,11 +515,14 @@ export class JobsViewComponent implements AfterContentChecked {
if (result && result.jobs) {
self.jobHistories[job.jobId] = result.jobs;
self._jobCacheObject.setJobHistory(job.jobId, result.jobs);
let jobHistories = self._jobCacheObject.getJobHistory(job.jobId);
let previousRuns = jobHistories.slice(jobHistories.length-5, jobHistories.length);
self.createJobChart(job.jobId, previousRuns);
if (self._agentViewComponent.expanded.has(job.jobId)) {
let jobHistory = self._jobCacheObject.getJobHistory(job.jobId)[result.jobs.length - 1];
let lastJobHistory = jobHistories[result.jobs.length-1];
let item = self.dataView.getItemById(job.jobId + '.error');
let noStepsMessage = nls.localize('jobsView.noSteps', 'No Steps available for this job.');
let errorMessage = jobHistory ? jobHistory.message : noStepsMessage;
let errorMessage = lastJobHistory ? lastJobHistory.message: noStepsMessage;
item['name'] = nls.localize('jobsView.error', 'Error: ') + errorMessage;
self._agentViewComponent.setExpanded(job.jobId, item['name']);
self.dataView.updateItem(job.jobId + '.error', item);
@@ -507,6 +532,52 @@ export class JobsViewComponent implements AfterContentChecked {
}
}
private createJobChart(jobId: string, jobHistories: sqlops.AgentJobHistoryInfo[]): void {
let chartHeights = this.getChartHeights(jobHistories);
for (let i = 0; i < jobHistories.length; i++) {
let runGraph = $(`table#${jobId}.jobprevruns > tbody > tr > td > div.bar${i+1}`);
if (jobHistories && jobHistories.length > 0) {
runGraph.css('height', chartHeights[i]);
let bgColor = jobHistories[i].runStatus === 0 ? 'red' : 'green';
runGraph.css('background', bgColor);
runGraph.hover((e) => {
let currentTarget = e.currentTarget;
currentTarget.title = jobHistories[i].runDuration;
});
} else {
runGraph.css('height', '5px');
runGraph.css('background', 'red');
runGraph.hover((e) => {
let currentTarget = e.currentTarget;
currentTarget.title = 'Job not run.';
});
}
}
}
// chart height normalization logic
private getChartHeights(jobHistories: sqlops.AgentJobHistoryInfo[]): string[] {
if (!jobHistories || jobHistories.length === 0) {
return ['5px','5px','5px','5px','5px'];
}
let maxDuration: number = 0;
jobHistories.forEach(history => {
let historyDuration = AgentJobUtilities.convertDurationToSeconds(history.runDuration) ;
if (historyDuration > maxDuration) {
maxDuration = historyDuration;
}
});
maxDuration = maxDuration === 0 ? 1 : maxDuration;
let maxBarHeight: number = 24;
let chartHeights = [];
for (let i = 0; i < jobHistories.length; i++) {
let duration = jobHistories[i].runDuration;
let chartHeight = (maxBarHeight * AgentJobUtilities.convertDurationToSeconds(duration))/maxDuration;
chartHeights.push(`${chartHeight}px`);
}
return chartHeights;
}
private expandJobs(start: boolean): void {
let expandedJobs = this._agentViewComponent.expanded;
let expansions = 0;