Feature/agent1 adbist (#973)

* WIP

* wip

* SQL Agent wip

* wip

* Initial control host (wip)

* Initial hookup of SQL Agent service to job component

* Update agent package.json

* Hook up getJobs call

* A couple job view updates

* Add some more agent views

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* Rename some 'agent' classes to 'jobManagement'

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* job history page (#852)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* Switch back getJobs return type

* Make enum const

* Remove sqlops const

* WIP

* WIP

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* Feature/agent1 adbist (#899)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* made job history page css more specific

* Add visiblity check to job view

* added method signatures for job history with DMP

* Clean up jobs styling and call getJobHistory

* Add more Job Table styling

* Enable detail view in job table

* Use updated slickgrid repo

* vbumped slickgrid

* added methods for job running

* added job actions to sqlops

* Convert rowdetail slickgrid plug to TypeScript

* Feature/agent1 adbist (#945)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* added method signatures for job history with DMP

* added methods for job running

* added job actions to sqlops

* Refer to dataprotocol from feature/agentDmp1 branch

* Update SQL Tools version to 1.4.0-alpha.13

* Change Feb to March in release note prompt

* SQL Agent extension metadata

* add feature explicitly in client creation

* Update Agent job registration

* navigation works but is really slow to load data

* Update package.json

* fixed conflicts

* Feature/agent1 adbist (#955)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* added method signatures for job history with DMP

* added methods for job running

* added job actions to sqlops

* navigation works but is really slow to load data

* Add jobs view icon

* fixed bug where not all steps were being shown

* added more to history page

* added loadHistories and code review comments

* made the params standard

* fixed json local paths
This commit is contained in:
Aditya Bist
2018-03-23 16:38:48 -07:00
committed by GitHub
parent 5aedd96276
commit bd67006f63
6 changed files with 103 additions and 124 deletions

View File

@@ -15,10 +15,10 @@
<!-- Actions -->
<ul class="action-buttons">
<li>
<div class="icon-start" (click)="jobAction('start')">Run</div>
<div class="icon-start" (click)="jobAction('run', agentJobInfo.name)">Run</div>
</li>
<li>
<div class="icon-stop" (click)="jobAction('stop')">Stop</div>
<div class="icon-stop" (click)="jobAction('stop', agentJobInfo.name)">Stop</div>
</li>
</ul>
@@ -34,10 +34,10 @@
<table align='left'>
<tr>
<td id='col1'>
User:
Category:
</td>
<td id='col2'>
{{agentJobInfo.category}}
</td>
<td id='col3'>
Enabled:
@@ -48,30 +48,30 @@
</tr>
<tr>
<td id='col1'>
Alert:
Has Alert:
</td>
<td id='col2'>
{{agentJobInfo.hasTarget}}
</td>
<td id='col3'>
Notification:
Has Schedule:
</td>
<td id='col4'>
{{agentJobInfo.hasSchedule}}
</td>
</tr>
<tr>
<td id='col1'>
Schedule:
Last Run:
</td>
<td id='col2'>
{{agentJobInfo.lastRun}}
</td>
<td id='col3'>
Target Server:
Next Run:
</td>
<td id='col4'>
{{agentJobInfo.nextRun}}
</td>
</tr>
</table>
@@ -98,31 +98,31 @@
<!-- Job Steps -->
<div class="job-steps">
<h1 class="job-heading">
{{agentJobInfo.lastRun}}
{{agentJobHistoryInfo?.runDate}}
</h1>
<table class="step-list">
<tr class="step-row">
<td height="30">
<h3>Status:</h3>
</td>
<td>
<td height="30">
<h3></h3>
</td>
</tr>
<tr class="step-row">
<td height="30">
Error Message:
Message:
</td>
<td>
<td height="30">
{{agentJobHistoryInfo?.message}}
</td>
</tr>
<tr class="step-row">
<td height="30">
Duration:
</td>
<td>
<td height="30">
{{agentJobHistoryInfo?.runDuration}}
</td>
</tr>
<tr class="step-row">
@@ -137,7 +137,7 @@
<td height="30">
SQL message ID:
</td>
<td>
<td height="30">
</td>
</tr>
@@ -145,8 +145,8 @@
<td height="30">
Retries Attempted:
</td>
<td>
<td height="30">
{{agentJobHistoryInfo?.retriesAttempted}}
</td>
</tr>
</table>

View File

@@ -5,25 +5,20 @@
import 'vs/css!./jobHistory';
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Input } from '@angular/core';
import { ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults';
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Input, Injectable } from '@angular/core';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachListStyler } from 'vs/platform/theme/common/styler';
import { getContentHeight } from 'vs/base/browser/dom';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { PanelComponent } from 'sql/base/browser/ui/panel/panel.component';
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
import { IJobManagementService } from '../common/interfaces';
import { ExplorerDataSource } from 'sql/parts/dashboard/widgets/explorer/explorerTree';
import { TreeCreationUtils } from 'sql/parts/registeredServer/viewlet/treeCreationUtils';
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
import { JobHistoryController, JobHistoryDataSource,
JobHistoryRenderer, JobHistoryFilter, JobHistoryModel, JobHistoryRow } from 'sql/parts/jobManagement/views/jobHistoryTree';
import { AgentJobHistoryInfo, AgentJobInfo } from 'sqlops';
import { toDisposableSubscription } from '../../common/rxjsUtils';
export const DASHBOARD_SELECTOR: string = 'jobhistory-component';
@@ -46,9 +41,8 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
@Input() public agentJobInfo: AgentJobInfo = undefined;
@Input() public jobId: string = undefined;
@Input() public agentJobHistoryInfo: AgentJobHistoryInfo = undefined;
private prevJobId: string = undefined;
private jobName: string = undefined;
private prevJobId: string = undefined;
private isVisible: boolean = false;
@@ -65,8 +59,32 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
ngOnInit() {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this.loadHistory();
this._treeDataSource.data = [];
const self = this;
this._treeController.onClick = (tree, element, event, origin = 'mouse') => {
const payload = { origin: origin };
const isDoubleClick = (origin === 'mouse' && event.detail === 2);
// Cancel Event
const isMouseDown = event && event.browserEvent && event.browserEvent.type === 'mousedown';
if (!isMouseDown) {
event.preventDefault(); // we cannot preventDefault onMouseDown because this would break DND otherwise
}
event.stopPropagation();
tree.setFocus(element, payload);
if (element && isDoubleClick) {
event.preventDefault(); // focus moves to editor, we need to prevent default
} else {
tree.setFocus(element, payload);
tree.setSelection([element], payload);
self.agentJobHistoryInfo = self._treeController.jobHistories.filter(history => history.instanceId === element.instanceID)[0];
self.agentJobHistoryInfo.runDate = self.formatTime(self.agentJobHistoryInfo.runDate);
self._cd.detectChanges();
}
return true;
};
this._tree = new Tree(this._tableContainer.nativeElement, {
controller: this._treeController,
dataSource: this._treeDataSource,
@@ -75,7 +93,6 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
});
this._register(attachListStyler(this._tree, this.bootstrapService.themeService));
this._tree.layout(1024);
//this._tree.setInput(new JobHistoryModel());
}
ngOnDestroy() {
@@ -83,7 +100,7 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
ngAfterContentChecked() {
if (this.isVisible === false && this._tableContainer.nativeElement.offsetParent !== null) {
if (this.prevJobId !== undefined && this.prevJobId !== this.jobId) {
if (this.prevJobId !== this.jobId) {
this.loadHistory();
this.prevJobId = this.jobId;
}
@@ -91,12 +108,17 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
}
loadHistory() {
const self = this;
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._jobManagementService.getJobHistory(ownerUri, this.jobId).then((result) => {
if (result.jobs) {
let jobHistory = result.jobs;
this._treeDataSource.data = jobHistory.map(job => this.convertToJobHistoryRow(job));
this._tree.setInput(new JobHistoryModel());
self._treeController.jobHistories = result.jobs;
let jobHistoryRows = self._treeController.jobHistories.map(job => self.convertToJobHistoryRow(job));
self._treeDataSource.data = jobHistoryRows;
self._tree.setInput(new JobHistoryModel());
self.agentJobHistoryInfo = self._treeController.jobHistories[0];
self.agentJobHistoryInfo.runDate = self.formatTime(self.agentJobHistoryInfo.runDate);
self._cd.detectChanges();
}
});
}
@@ -111,22 +133,26 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
}
}
private jobAction(action: string): void {
private jobAction(action: string, jobName: string): void {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._jobManagementService.jobAction(ownerUri, 'jobName', action);
this._jobManagementService.jobAction(ownerUri, jobName, action);
}
private goToJobs(): void {
this.isVisible = false;
this._agentViewComponent.showHistory = false;
}
private convertToJobHistoryRow(historyInfo: AgentJobHistoryInfo): JobHistoryRow {
let jobHistoryRow = {
runDate: historyInfo.runDate,
runStatus: JobHistoryRow.convertToStatusString(historyInfo.runStatus),
jobID: historyInfo.jobID
};
let jobHistoryRow = new JobHistoryRow();
jobHistoryRow.runDate = historyInfo.runDate;
jobHistoryRow.runStatus = JobHistoryRow.convertToStatusString(historyInfo.runStatus);
jobHistoryRow.instanceID = historyInfo.instanceId;
return jobHistoryRow;
}
private formatTime(time: string): string {
return time.replace('T', ' ');
}
}

View File

@@ -158,7 +158,7 @@ input#accordion:checked ~ .accordion-content {
}
table.step-list tr.step-row td {
padding-right: 100px;
padding-right: 10px;
}
.history-details {

View File

@@ -26,11 +26,14 @@ import { generateUuid } from 'vs/base/common/uuid';
import * as DOM from 'vs/base/browser/dom';
import { OEAction } from 'sql/parts/registeredServer/viewlet/objectExplorerActions';
import { Builder, $, withElementById } from 'vs/base/browser/builder';
import { AgentJobHistoryInfo } from 'sqlops';
import { Agent } from 'vs/base/node/request';
export class JobHistoryRow {
runDate: string;
runStatus: string;
jobID: string;
instanceID: number;
rowID: string = generateUuid();
public static convertToStatusString(status: number): string {
switch(status) {
@@ -47,28 +50,9 @@ export class JobHistoryModel {
}
export class JobHistoryController extends TreeDefaults.DefaultController {
private _jobHistories: AgentJobHistoryInfo[];
protected onLeftClick(tree: tree.ITree, element: JobHistoryRow, event: IMouseEvent, origin: string = 'mouse'): boolean {
const payload = { origin: origin };
const isDoubleClick = (origin === 'mouse' && event.detail === 2);
// Cancel Event
const isMouseDown = event && event.browserEvent && event.browserEvent.type === 'mousedown';
if (!isMouseDown) {
event.preventDefault(); // we cannot preventDefault onMouseDown because this would break DND otherwise
}
event.stopPropagation();
tree.setFocus(element, payload);
if (element && isDoubleClick) {
event.preventDefault(); // focus moves to editor, we need to prevent default
} else {
tree.setFocus(element, payload);
tree.setSelection([element], payload);
}
return true;
}
@@ -76,6 +60,14 @@ export class JobHistoryController extends TreeDefaults.DefaultController {
return true;
}
public set jobHistories(value: AgentJobHistoryInfo[]) {
this._jobHistories = value;
}
public get jobHistories(): AgentJobHistoryInfo[] {
return this._jobHistories;
}
}
export class JobHistoryDataSource implements tree.IDataSource {
@@ -85,7 +77,7 @@ export class JobHistoryDataSource implements tree.IDataSource {
if (element instanceof JobHistoryModel) {
return JobHistoryModel.id;
} else {
return (element as JobHistoryRow).jobID;
return (element as JobHistoryRow).rowID;
}
}

View File

@@ -93,36 +93,6 @@ export class JobsViewComponent implements OnInit, OnDestroy {
}
}
loadJobHistories() {
if (this.jobs) {
this.jobs.forEach((job) => {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
if (result.jobs) {
this.jobHistories[job.jobId] = result.jobs;
this.expandJobsWithFailures();
}
});
});
}
}
private expandJobsWithFailures(): void {
for (let i: number = 0; i < this.jobs.length; ++i) {
let job = this.jobs[i];
let jobHistory = this.jobHistories[job.jobId];
if (jobHistory && jobHistory.length > 0) {
let latestExecution = jobHistory[jobHistory.length - 1];
if (latestExecution.runStatus !== 0) {
this.expandJobRowDetails(i);
}
}
}
}
private expandJobRowDetails(rowIdx: number): void {
}
onFirstVisible() {
let self = this;
let columns = this.columns.map((column) => {
@@ -157,11 +127,6 @@ export class JobsViewComponent implements OnInit, OnDestroy {
let job = self.getJob(args);
self._agentViewComponent.jobId = job.jobId;
self._agentViewComponent.agentJobInfo = job;
self.getJobHistoryInfo(ownerUri, job).then(result => {
if (result) {
this._agentViewComponent.agentJobHistoryInfo = result;
}
});
self.isVisible = false;
self._agentViewComponent.showHistory = true;
});
@@ -176,22 +141,6 @@ export class JobsViewComponent implements OnInit, OnDestroy {
});
}
getJobHistoryInfo(ownerUri: string, job: any): Thenable<sqlops.AgentJobHistoryInfo[]> {
return new Promise<sqlops.AgentJobHistoryInfo[]>((resolve, reject) => {
if (this.jobHistories[job.jobId]){
Promise.resolve(this.jobHistories[job.jobId]);
} else {
this._jobManagementService.getJobHistory(ownerUri, job.jobId).then(result => {
if (result && result.jobs) {
Promise.resolve(result.jobs);
} else {
Promise.reject(undefined);
}
});
}
});
}
onJobsAvailable(jobs: sqlops.AgentJobInfo[]) {
let jobViews = jobs.map((job) => {
return {
@@ -225,7 +174,6 @@ export class JobsViewComponent implements OnInit, OnDestroy {
this._table.resizeCanvas();
this._table.autosizeColumns();
this.loadJobHistories();
}
@@ -246,6 +194,19 @@ export class JobsViewComponent implements OnInit, OnDestroy {
'</tr></table>';
}
loadJobHistories() {
if (this.jobs) {
this.jobs.forEach((job) => {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
if (result.jobs) {
this.jobHistories[job.jobId] = result.jobs;
}
});
});
}
}
private getJob(args: Slick.OnClickEventArgs<any>): sqlops.AgentJobInfo {
let cell = args.cell;
let jobName = args.grid.getCellNode(1, cell).innerText.trim();

10
src/sql/sqlops.d.ts vendored
View File

@@ -1061,13 +1061,13 @@ declare module 'sqlops' {
}
export interface AgentJobHistoryInfo {
instanceID: number;
sqlMessageID: number;
instanceId: number;
sqlMessageId: number;
message: string;
stepID: number;
stepId: number;
stepName: string;
sqlSeverity: number;
jobID: string;
jobId: string;
jobName: string;
runStatus: number;
runDate: string;
@@ -1081,7 +1081,7 @@ declare module 'sqlops' {
export interface AgentServicesProvider extends DataProvider {
getJobs(connectionUri: string): Thenable<AgentJobsResult>;
getJobHistory(connectionUri: string, jobID: string): Thenable<AgentJobHistoryResult>;
getJobHistory(connectionUri: string, jobId: string): Thenable<AgentJobHistoryResult>;
jobAction(connectionUri: string, jobName: string, action: string): Thenable<AgentJobActionResult>;
}