Agent work (WIP) (#1012)

* 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

* Misc. cleanups

* added more to history page

* added loadHistories and code review comments

* made the params standard

* fixed json local paths

* added step implementation

* fixed conflict

* cleaned up code

* removed extension-modules

* CR comments

* fix css

* fixed data injection

* steps now support big messages

* improve history page UX
This commit is contained in:
Aditya Bist
2018-03-29 12:41:31 -07:00
committed by GitHub
parent c45c634938
commit 916598e029
12 changed files with 424 additions and 33 deletions

View File

@@ -51,7 +51,7 @@ import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.co
let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer,
DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, WebviewContent, WidgetContent,
ComponentHostDirective, BreadcrumbComponent, ControlHostContent, DashboardControlHostContainer,
JobsViewComponent, AgentViewComponent, JobHistoryComponent];
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent];
/* Panel */
import { PanelModule } from 'sql/base/browser/ui/panel/panel.module';
@@ -68,6 +68,7 @@ import { ExplorerWidget } from 'sql/parts/dashboard/widgets/explorer/explorerWid
import { TasksWidget } from 'sql/parts/dashboard/widgets/tasks/tasksWidget.component';
import { InsightsWidget } from 'sql/parts/dashboard/widgets/insights/insightsWidget.component';
import { WebviewWidget } from 'sql/parts/dashboard/widgets/webview/webviewWidget.component';
import { JobStepsViewComponent } from '../jobManagement/views/jobStepsView.component';
let widgetComponents = [
PropertiesWidgetComponent,

View File

@@ -106,7 +106,15 @@
<h3>Status:</h3>
</td>
<td height="30">
<h3></h3>
<h3>{{_runStatus}}</h3>
</td>
</tr>
<tr class="step-row">
<td height="30">
Job ID:
</td>
<td height="30">
{{agentJobHistoryInfo?.jobId}}
</td>
</tr>
<tr class="step-row">
@@ -127,10 +135,10 @@
</tr>
<tr class="step-row">
<td height="30">
Log:
Server:
</td>
<td>
{{agentJobHistoryInfo?.server}}
</td>
</tr>
<tr class="step-row">
@@ -138,7 +146,7 @@
SQL message ID:
</td>
<td height="30">
{{agentJobHistoryInfo?.sqlMessageId}}
</td>
</tr>
<tr class="step-row">
@@ -150,6 +158,7 @@
</td>
</tr>
</table>
<jobstepsview-component *ngIf="showSteps() === true" [stepRows]="_stepRows"></jobstepsview-component>
</div>
</div>

View File

@@ -5,7 +5,8 @@
import 'vs/css!./jobHistory';
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Input, Injectable } from '@angular/core';
import { OnInit, OnChanges, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Input, Injectable } from '@angular/core';
import { AgentJobHistoryInfo, AgentJobInfo } from 'sqlops';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachListStyler } from 'vs/platform/theme/common/styler';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
@@ -18,8 +19,8 @@ import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboar
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 { JobStepsViewComponent } from 'sql/parts/jobManagement/views/jobStepsView.component';
import { JobStepsViewRow } from './jobStepsViewTree';
export const DASHBOARD_SELECTOR: string = 'jobhistory-component';
@@ -27,7 +28,7 @@ export const DASHBOARD_SELECTOR: string = 'jobhistory-component';
selector: DASHBOARD_SELECTOR,
templateUrl: decodeURI(require.toUrl('./jobHistory.component.html'))
})
export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy {
export class JobHistoryComponent extends Disposable implements OnInit {
private _jobManagementService: IJobManagementService;
private _tree: Tree;
@@ -42,8 +43,11 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
@Input() public jobId: string = undefined;
@Input() public agentJobHistoryInfo: AgentJobHistoryInfo = undefined;
private prevJobId: string = undefined;
private isVisible: boolean = false;
private _prevJobId: string = undefined;
private _isVisible: boolean = false;
private _stepRows: JobStepsViewRow[] = [];
private _showSteps: boolean = false;
private _runStatus: string = undefined;
constructor(
@@ -65,23 +69,31 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
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();
if (self.agentJobHistoryInfo) {
self.agentJobHistoryInfo.runDate = self.formatTime(self.agentJobHistoryInfo.runDate);
self._stepRows = self.agentJobHistoryInfo.steps.map(step => {
let stepViewRow = new JobStepsViewRow();
stepViewRow.message = step.message;
stepViewRow.runStatus = JobHistoryRow.convertToStatusString(self.agentJobHistoryInfo.runStatus);
self._runStatus = stepViewRow.runStatus;
stepViewRow.stepName = step.stepName;
stepViewRow.stepID = step.stepId.toString();
return stepViewRow;
});
this._showSteps = true;
self._cd.detectChanges();
}
}
return true;
};
@@ -95,14 +107,11 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
this._tree.layout(1024);
}
ngOnDestroy() {
}
ngAfterContentChecked() {
if (this.isVisible === false && this._tableContainer.nativeElement.offsetParent !== null) {
if (this.prevJobId !== this.jobId) {
if (this._isVisible === false && this._tableContainer.nativeElement.offsetParent !== null) {
if (this._prevJobId !== this.jobId) {
this.loadHistory();
this.prevJobId = this.jobId;
this._prevJobId = this.jobId;
}
}
}
@@ -139,7 +148,7 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
}
private goToJobs(): void {
this.isVisible = false;
this._isVisible = false;
this._agentViewComponent.showHistory = false;
}
@@ -154,5 +163,9 @@ export class JobHistoryComponent extends Disposable implements OnInit, OnDestroy
private formatTime(time: string): string {
return time.replace('T', ' ');
}
public showSteps(): boolean {
return this._showSteps;
}
}

View File

@@ -153,6 +153,11 @@ input#accordion:checked ~ .accordion-content {
padding: 10px;
}
.accordion-content #col1,
.accordion-content #col3 {
font-weight: bold;
}
.accordion-content #col2 {
padding-right: 300px;
}
@@ -171,6 +176,7 @@ table.step-list tr.step-row td {
border-left: 3px solid #444444;
padding-left: 10px;
height: 100%;
width: 90%;
}
.history-details > .job-steps {
@@ -203,15 +209,15 @@ table.step-list tr.step-row td {
display: inline-block;
}
.passed {
.job-passed {
background: green;
}
.failed {
.job-failed {
background: red;
}
.unknown {
.job-unknown {
background: yellow;
}
@@ -219,3 +225,8 @@ table.step-list tr.step-row td {
padding-left: 50px;
width: 140px;
}
.steps-tree .monaco-tree .monaco-tree-row {
white-space: normal;
height: 40px !important;
}

View File

@@ -145,11 +145,11 @@ export class JobHistoryRenderer implements tree.IRenderer {
templateData.label.innerText = element.runDate + '\t\t\t' + element.runStatus;
let statusClass: string;
if (element.runStatus === 'Succeeded') {
statusClass = ' passed';
statusClass = ' job-passed';
} else if (element.runStatus === 'Failed') {
statusClass = ' failed';
statusClass = ' job-failed';
} else {
statusClass = ' unknown';
statusClass = ' job-unknown';
}
this._statusIcon.className += statusClass;
}

View File

@@ -0,0 +1,22 @@
<!--
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-->
<h1>Steps</h1>
<table class='step-columns'>
<tr>
<td class='step-id-col'>
<b>Step ID</b>
</td>
<td class='step-name-col'>
<b>Step Name</b>
</td>
<td class='step-message-col'>
<b>Message</b>
</td>
</tr>
</table>
<div class='steps-tree' #table style="height: 100%; width: 100%"></div>

View File

@@ -0,0 +1,80 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./jobStepsView';
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnChanges, ViewChild, Input, Injectable } from '@angular/core';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachListStyler } from 'vs/platform/theme/common/styler';
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 { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
import { IJobManagementService } from '../common/interfaces';
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
import { AgentJobHistoryInfo } from 'sqlops';
import { JobStepsViewController, JobStepsViewDataSource, JobStepsViewFilter,
JobStepsViewRenderer, JobStepsViewRow, JobStepsViewModel} from 'sql/parts/jobManagement/views/jobStepsViewTree';
export const JOBSTEPSVIEW_SELECTOR: string = 'jobstepsview-component';
@Component({
selector: JOBSTEPSVIEW_SELECTOR,
templateUrl: decodeURI(require.toUrl('./jobStepsView.component.html'))
})
export class JobStepsViewComponent extends Disposable implements OnInit, OnChanges {
private _jobManagementService: IJobManagementService;
private _tree: Tree;
private _treeController = new JobStepsViewController();
private _treeDataSource = new JobStepsViewDataSource();
private _treeRenderer = new JobStepsViewRenderer();
private _treeFilter = new JobStepsViewFilter();
private static _pageSize = 1024;
@ViewChild('table') private _tableContainer: ElementRef;
@Input() public stepRows: JobStepsViewRow[] = [];
constructor(
@Inject(BOOTSTRAP_SERVICE_ID) private bootstrapService: IBootstrapService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
@Inject(forwardRef(() => DashboardServiceInterface)) private _dashboardService: DashboardServiceInterface
) {
super();
this._jobManagementService = bootstrapService.jobManagementService;
}
ngOnInit() {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._tree = new Tree(this._tableContainer.nativeElement, {
controller: this._treeController,
dataSource: this._treeDataSource,
filter: this._treeFilter,
renderer: this._treeRenderer
});
}
ngOnChanges() {
if (this.stepRows.length > 0) {
this._treeDataSource.data = this.stepRows;
if (!this._tree) {
this._tree = new Tree(this._tableContainer.nativeElement, {
controller: this._treeController,
dataSource: this._treeDataSource,
filter: this._treeFilter,
renderer: this._treeRenderer
});
}
this._tree.layout(JobStepsViewComponent._pageSize);
this._tree.setInput(new JobStepsViewModel());
}
}
ngAfterContentChecked() {
}
}

View File

@@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.steps-tree .list-row .status-icon {
height: 10px;
width: 10px;
display: inline-block;
margin-top: 4px;
}
.list-row .label {
padding-left: 10px;
display: flex;
text-align: center;
}
.step-passed {
background: green;
}
.step-failed {
background: red;
}
.step-unknown {
background: yellow;
}
.steps-tree .list-row {
display: inline-flex;
height: 20px
}
.step-columns {
padding-left: 50px;
}
.step-id-col, .tree-id-col {
padding-left: 10px;
white-space: normal;
text-align: center;
width: 60px;
}
.step-name-col, .tree-name-col {
padding-right: 10px;
white-space: normal;
text-align: center;
width: 350px;
}
.step-message-col, .tree-message-col {
padding-right: 10px;
white-space: normal;
text-align: center;
width: 680px;
height:
}

View File

@@ -0,0 +1,186 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Router } from '@angular/router';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { MetadataType } from 'sql/parts/connection/common/connectionManagement';
import { SingleConnectionManagementService } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
import {
NewQueryAction, ScriptSelectAction, EditDataAction, ScriptCreateAction, ScriptExecuteAction, ScriptAlterAction,
BackupAction, ManageActionContext, BaseActionContext, ManageAction, RestoreAction
} from 'sql/workbench/common/actions';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
import * as Constants from 'sql/parts/connection/common/constants';
import * as tree from 'vs/base/parts/tree/browser/tree';
import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults';
import { Promise, TPromise } from 'vs/base/common/winjs.base';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IAction } from 'vs/base/common/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
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 JobStepsViewRow {
public stepID: string;
public stepName: string;
public message: string;
public rowID: string = generateUuid();
public runStatus: string;
}
// Empty class just for tree input
export class JobStepsViewModel {
public static readonly id = generateUuid();
}
export class JobStepsViewController extends TreeDefaults.DefaultController {
private _jobHistories: AgentJobHistoryInfo[];
protected onLeftClick(tree: tree.ITree, element: JobStepsViewRow, event: IMouseEvent, origin: string = 'mouse'): boolean {
return true;
}
public onContextMenu(tree: tree.ITree, element: JobStepsViewRow, event: tree.ContextMenuEvent): boolean {
return true;
}
public set jobHistories(value: AgentJobHistoryInfo[]) {
this._jobHistories = value;
}
public get jobHistories(): AgentJobHistoryInfo[] {
return this._jobHistories;
}
}
export class JobStepsViewDataSource implements tree.IDataSource {
private _data: JobStepsViewRow[];
public getId(tree: tree.ITree, element: JobStepsViewRow | JobStepsViewModel): string {
if (element instanceof JobStepsViewModel) {
return JobStepsViewModel.id;
} else {
return (element as JobStepsViewRow).rowID;
}
}
public hasChildren(tree: tree.ITree, element: JobStepsViewRow | JobStepsViewModel): boolean {
if (element instanceof JobStepsViewModel) {
return true;
} else {
return false;
}
}
public getChildren(tree: tree.ITree, element: JobStepsViewRow | JobStepsViewModel): Promise {
if (element instanceof JobStepsViewModel) {
return TPromise.as(this._data);
} else {
return TPromise.as(undefined);
}
}
public getParent(tree: tree.ITree, element: JobStepsViewRow | JobStepsViewModel): Promise {
if (element instanceof JobStepsViewModel) {
return TPromise.as(undefined);
} else {
return TPromise.as(new JobStepsViewModel());
}
}
public set data(data: JobStepsViewRow[]) {
this._data = data;
}
}
export interface IListTemplate {
statusIcon: HTMLElement;
label: HTMLElement;
}
export class JobStepsViewRenderer implements tree.IRenderer {
private _statusIcon: HTMLElement;
public getHeight(tree: tree.ITree, element: JobStepsViewRow): number {
return 22;
}
public getTemplateId(tree: tree.ITree, element: JobStepsViewRow | JobStepsViewModel): string {
if (element instanceof JobStepsViewModel) {
return 'jobStepsViewModel';
} else {
return 'jobStepsViewRow';
}
}
public renderTemplate(tree: tree.ITree, templateId: string, container: HTMLElement): IListTemplate {
let row = DOM.$('.list-row');
let label = DOM.$('.label');
this._statusIcon = this.createStatusIcon();
row.appendChild(this._statusIcon);
row.appendChild(label);
container.appendChild(row);
let statusIcon = this._statusIcon;
return { statusIcon, label };
}
public renderElement(tree: tree.ITree, element: JobStepsViewRow, templateId: string, templateData: IListTemplate): void {
let stepIdCol: HTMLElement = DOM.$('div');
stepIdCol.className = 'tree-id-col';
stepIdCol.innerText = element.stepID;
let stepNameCol: HTMLElement = DOM.$('div');
stepNameCol.className = 'tree-name-col';
stepNameCol.innerText = element.stepName;
let stepMessageCol: HTMLElement = DOM.$('div');
stepMessageCol.className = 'tree-message-col';
stepMessageCol.innerText = element.message;
templateData.label.appendChild(stepIdCol);
templateData.label.appendChild(stepNameCol);
templateData.label.appendChild(stepMessageCol);
let statusClass: string;
if (element.runStatus === 'Succeeded') {
statusClass = ' step-passed';
} else if (element.runStatus === 'Failed') {
statusClass = ' step-failed';
} else {
statusClass = ' step-unknown';
}
this._statusIcon.className += statusClass;
}
public disposeTemplate(tree: tree.ITree, templateId: string, templateData: IListTemplate): void {
// no op
}
private createStatusIcon(): HTMLElement {
let statusIcon: HTMLElement = DOM.$('div');
statusIcon.className += ' status-icon';
return statusIcon;
}
}
export class JobStepsViewFilter implements tree.IFilter {
private _filterString: string;
public isVisible(tree: tree.ITree, element: JobStepsViewRow): boolean {
return this._isJobVisible();
}
private _isJobVisible(): boolean {
return true;
}
public set filterString(val: string) {
this._filterString = val;
}
}

View File

@@ -208,8 +208,8 @@ export class JobsViewComponent implements OnInit, OnDestroy {
}
private getJob(args: Slick.OnClickEventArgs<any>): sqlops.AgentJobInfo {
let cell = args.cell;
let jobName = args.grid.getCellNode(1, cell).innerText.trim();
let row = args.row;
let jobName = args.grid.getCellNode(row, 1).innerText.trim();
let job = this.jobs.filter(job => job.name === jobName)[0];
return job;
}

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

@@ -1060,6 +1060,13 @@ declare module 'sqlops' {
jobId: string;
}
export interface AgentJobStep {
stepId: number;
stepName: string;
message: string;
runDate: string;
}
export interface AgentJobHistoryInfo {
instanceId: number;
sqlMessageId: number;
@@ -1077,6 +1084,7 @@ declare module 'sqlops' {
operatorPaged: string;
retriesAttempted: number;
server: string;
steps: AgentJobStep[];
}
export interface AgentServicesProvider extends DataProvider {