mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
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:
@@ -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'):
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -245,6 +245,3 @@ jobhistory-component > .actionbar-container .monaco-action-bar > ul.actions-cont
|
||||
border-top: 3px solid #444444;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user