diff --git a/src/sql/parts/jobManagement/views/jobHistory.component.ts b/src/sql/parts/jobManagement/views/jobHistory.component.ts index d0b1976c29..eaa35f99ca 100644 --- a/src/sql/parts/jobManagement/views/jobHistory.component.ts +++ b/src/sql/parts/jobManagement/views/jobHistory.component.ts @@ -111,7 +111,7 @@ export class JobHistoryComponent extends Disposable implements OnInit { } else { tree.setFocus(element, payload); tree.setSelection([element], payload); - self.setStepsTree(element); + self.setStepsTree(element); } return true; }; @@ -192,7 +192,8 @@ export class JobHistoryComponent extends Disposable implements OnInit { private setStepsTree(element: any) { const self = this; - self.agentJobHistoryInfo = self._treeController.jobHistories.filter(history => history.instanceId === element.instanceID)[0]; + self.agentJobHistoryInfo = self._treeController.jobHistories.find( + history => self.formatTime(history.runDate) === self.formatTime(element.runDate)); if (self.agentJobHistoryInfo) { self.agentJobHistoryInfo.runDate = self.formatTime(self.agentJobHistoryInfo.runDate); if (self.agentJobHistoryInfo.steps) { @@ -242,7 +243,7 @@ export class JobHistoryComponent extends Disposable implements OnInit { private convertToJobHistoryRow(historyInfo: AgentJobHistoryInfo): JobHistoryRow { let jobHistoryRow = new JobHistoryRow(); - jobHistoryRow.runDate = historyInfo.runDate; + jobHistoryRow.runDate = this.formatTime(historyInfo.runDate); jobHistoryRow.runStatus = AgentJobUtilities.convertToStatusString(historyInfo.runStatus); jobHistoryRow.instanceID = historyInfo.instanceId; return jobHistoryRow; diff --git a/src/sql/parts/jobManagement/views/jobHistoryTree.ts b/src/sql/parts/jobManagement/views/jobHistoryTree.ts index 79c91e51b7..501c603857 100644 --- a/src/sql/parts/jobManagement/views/jobHistoryTree.ts +++ b/src/sql/parts/jobManagement/views/jobHistoryTree.ts @@ -60,9 +60,11 @@ export class JobHistoryController extends TreeDefaults.DefaultController { public onKeyDownWrapper(tree: tree.ITree, event: IKeyboardEvent): boolean { if (event.code === 'ArrowDown' || event.keyCode === 40) { - return super.onDown(tree, event); + super.onDown(tree, event); + return super.onEnter(tree, event); } else if (event.code === 'ArrowUp' || event.keyCode === 38) { - return super.onUp(tree, event); + super.onUp(tree, event); + return super.onEnter(tree, event); } else { event.preventDefault(); event.stopPropagation(); diff --git a/src/sql/parts/jobManagement/views/jobsView.component.ts b/src/sql/parts/jobManagement/views/jobsView.component.ts index 016e66b479..2253557377 100644 --- a/src/sql/parts/jobManagement/views/jobsView.component.ts +++ b/src/sql/parts/jobManagement/views/jobsView.component.ts @@ -157,9 +157,7 @@ export class JobsViewComponent implements AfterContentChecked { let job = self.getJob(args); self._agentViewComponent.jobId = job.jobId; self._agentViewComponent.agentJobInfo = job; - setTimeout(() => { - self._agentViewComponent.showHistory = true; - }, 500); + self._agentViewComponent.showHistory = true; }); if (cached && this._agentViewComponent.refresh !== true) { this.onJobsAvailable(this._jobCacheObject.jobs); @@ -290,44 +288,69 @@ export class JobsViewComponent implements AfterContentChecked { this.rowDetail.applyTemplateNewLineHeight(item, true); } - private loadJobHistories() { - const self = this; + private loadJobHistories(): void { if (this.jobs) { let erroredJobs = 0; - for (let i = 0; i < this.jobs.length; i++) { - let job = this.jobs[i]; - let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri; - this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => { - if (result.jobs) { - self.jobHistories[job.jobId] = result.jobs; - self._jobCacheObject.setJobHistory(job.jobId, result.jobs); - if (self._agentViewComponent.expanded.has(job.jobId)) { - let jobHistory = self._jobCacheObject.getJobHistory(job.jobId)[0]; - 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; - item['name'] = nls.localize('jobsView.error', 'Error: ') + errorMessage; - self._agentViewComponent.setExpanded(job.jobId, errorMessage); - self.dataView.updateItem(job.jobId + '.error', item); - - } - } - }); - } + let ownerUri: string = this._dashboardService.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); } } - private isErrorRow(jobName: string) { - return jobName.includes('Error'); + private separateFailingJobs(): sqlops.AgentJobInfo[][] { + let failing = []; + let nonFailing = []; + for (let i = 0; i < this.jobs.length; i++) { + if (this.jobs[i].lastRunOutcome === 0) { + failing.push(this.jobs[i]); + } else { + nonFailing.push(this.jobs[i]); + } + } + return [failing, nonFailing]; + } + + private isErrorRow(cell: HTMLElement) { + return cell.classList.contains('error-row'); } private getJob(args: Slick.OnClickEventArgs): sqlops.AgentJobInfo { let row = args.row; - let jobName = args.grid.getCellNode(row, 1).innerText.trim(); - if (this.isErrorRow(jobName)) { + let jobName: string; + let cell = args.grid.getCellNode(row, 1); + if (this.isErrorRow(cell)) { jobName = args.grid.getCellNode(row-1, 1).innerText.trim(); + } else { + jobName = cell.innerText.trim(); } let job = this.jobs.filter(job => job.name === jobName)[0]; return job; } + + private 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) => { + if (result && result.jobs) { + self.jobHistories[job.jobId] = result.jobs; + self._jobCacheObject.setJobHistory(job.jobId, result.jobs); + if (self._agentViewComponent.expanded.has(job.jobId)) { + let jobHistory = self._jobCacheObject.getJobHistory(job.jobId)[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; + item['name'] = nls.localize('jobsView.error', 'Error: ') + errorMessage; + self._agentViewComponent.setExpanded(job.jobId, item['name']); + self.dataView.updateItem(job.jobId + '.error', item); + } + } + }); + } + } } \ No newline at end of file diff --git a/src/sql/sqlops.d.ts b/src/sql/sqlops.d.ts index aa296760dc..1d00285dd9 100644 --- a/src/sql/sqlops.d.ts +++ b/src/sql/sqlops.d.ts @@ -1061,7 +1061,7 @@ declare module 'sqlops' { } export interface AgentJobStep { - stepId: number; + stepId: string; stepName: string; message: string; runDate: string; @@ -1070,20 +1070,20 @@ declare module 'sqlops' { export interface AgentJobHistoryInfo { instanceId: number; - sqlMessageId: number; + sqlMessageId: string; message: string; - stepId: number; + stepId: string; stepName: string; - sqlSeverity: number; + sqlSeverity: string; jobId: string; jobName: string; runStatus: number; runDate: string; - runDuration: number; + runDuration: string; operatorEmailed: string; operatorNetsent: string; operatorPaged: string; - retriesAttempted: number; + retriesAttempted: string; server: string; steps: AgentJobStep[]; }