From 89e959c2e30cc45d485a851b4992b0064ab45a58 Mon Sep 17 00:00:00 2001 From: Aditya Bist Date: Tue, 23 Oct 2018 14:42:31 -0700 Subject: [PATCH] Agent/alerts (#2943) * alerts view is now cached * added styling to alerts page * fixed row detail view import --- .../parts/jobManagement/common/interfaces.ts | 5 +- .../common/jobManagementService.ts | 53 +++++++++- .../parts/jobManagement/common/media/jobs.css | 6 +- .../views/alertsView.component.ts | 99 ++++++++++++++----- .../views/jobHistory.component.ts | 1 - .../jobManagement/views/jobManagementView.ts | 2 + .../jobManagement/views/jobsView.component.ts | 2 - .../views/operatorsView.component.ts | 1 - .../views/proxiesView.component.ts | 1 - 9 files changed, 135 insertions(+), 35 deletions(-) diff --git a/src/sql/parts/jobManagement/common/interfaces.ts b/src/sql/parts/jobManagement/common/interfaces.ts index 6f60c8cd87..589f5bb335 100644 --- a/src/sql/parts/jobManagement/common/interfaces.ts +++ b/src/sql/parts/jobManagement/common/interfaces.ts @@ -7,7 +7,7 @@ import * as sqlops from 'sqlops'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { JobCacheObject, ProxiesCacheObject } from './jobManagementService'; +import { JobCacheObject, AlertsCacheObject, ProxiesCacheObject } from './jobManagementService'; import { Event } from 'vs/base/common/event'; export const SERVICE_ID = 'jobManagementService'; @@ -39,7 +39,8 @@ export interface IJobManagementService { getCredentials(connectionUri: string): Thenable; jobAction(connectionUri: string, jobName: string, action: string): Thenable; - addToCache(server: string, cache: JobCacheObject | ProxiesCacheObject); jobCacheObjectMap: { [server: string]: JobCacheObject; }; + alertsCacheObjectMap: { [server: string]: AlertsCacheObject; }; proxiesCacheObjectMap: {[server: string]: ProxiesCacheObject }; + addToCache(server: string, cache: JobCacheObject | ProxiesCacheObject | AlertsCacheObject); } \ No newline at end of file diff --git a/src/sql/parts/jobManagement/common/jobManagementService.ts b/src/sql/parts/jobManagement/common/jobManagementService.ts index edd8a07039..acbf3fe9cf 100644 --- a/src/sql/parts/jobManagement/common/jobManagementService.ts +++ b/src/sql/parts/jobManagement/common/jobManagementService.ts @@ -20,6 +20,7 @@ export class JobManagementService implements IJobManagementService { private _providers: { [handle: string]: sqlops.AgentServicesProvider; } = Object.create(null); private _jobCacheObjectMap : {[server: string]: JobCacheObject; } = {}; + private _alertsCacheObject: {[server: string]: AlertsCacheObject; } = {}; private _proxiesCacheObjectMap: {[server: string]: ProxiesCacheObject; } = {}; constructor( @@ -131,13 +132,19 @@ export class JobManagementService implements IJobManagementService { return this._jobCacheObjectMap; } + public get alertsCacheObjectMap(): {[server: string]: AlertsCacheObject; } { + return this._alertsCacheObject; + } + public get proxiesCacheObjectMap(): {[server: string]: ProxiesCacheObject; } { return this._proxiesCacheObjectMap; } - public addToCache(server: string, cacheObject: JobCacheObject | ProxiesCacheObject) { + public addToCache(server: string, cacheObject: JobCacheObject | AlertsCacheObject | ProxiesCacheObject) { if (cacheObject instanceof JobCacheObject) { - this._jobCacheObjectMap[server] = cacheObject; + this._jobCacheObjectMap[server] = cacheObject;; + } else if (cacheObject instanceof AlertsCacheObject) { + this._alertsCacheObject[server] = cacheObject; } else if (cacheObject instanceof ProxiesCacheObject) { this._proxiesCacheObjectMap[server] = cacheObject; } @@ -145,7 +152,7 @@ export class JobManagementService implements IJobManagementService { } /** - * Server level caching of jobs/job histories + * Server level caching of jobs/job histories and their views */ export class JobCacheObject { _serviceBrand: any; @@ -242,6 +249,44 @@ export class JobCacheObject { } } +/** + * Server level caching of job alerts and the alerts view + */ +export class AlertsCacheObject { + _serviceBrand: any; + private _alerts: sqlops.AgentAlertInfo[]; + private _dataView: Slick.Data.DataView; + private _serverName: string; + + /** Getters */ + public get alerts(): sqlops.AgentAlertInfo[] { + return this._alerts; + } + + public get dataview(): Slick.Data.DataView { + return this._dataView; + } + + public get serverName(): string { + return this._serverName; + } + + /** Setters */ + + public set alerts(value: sqlops.AgentAlertInfo[]) { + this._alerts = value; + } + + public set dataview(value: Slick.Data.DataView) { + this._dataView = value; + } + + public set serverName(value: string) { + this._serverName = value; + } +} + + /** * Server level caching of job proxies and proxies view */ @@ -267,6 +312,7 @@ export class ProxiesCacheObject { } /** Setters */ + public set proxies(value: sqlops.AgentProxyInfo[]) { this._proxies = value; } @@ -278,5 +324,4 @@ export class ProxiesCacheObject { public set serverName(value: string) { this._serverName = value; } - } \ No newline at end of file diff --git a/src/sql/parts/jobManagement/common/media/jobs.css b/src/sql/parts/jobManagement/common/media/jobs.css index fcf43edc72..03bc804c9a 100644 --- a/src/sql/parts/jobManagement/common/media/jobs.css +++ b/src/sql/parts/jobManagement/common/media/jobs.css @@ -104,6 +104,7 @@ jobhistory-component { display: inline-block; } +#alertsDiv .jobalertsview-grid .slick-cell.l1.r1 .alertview-alertnametext, #proxiesDiv .jobproxiesview-grid .slick-cell.l1.r1 .proxyview-proxynametext { text-overflow: ellipsis; width: 100%; @@ -400,11 +401,14 @@ jobsview-component .jobview-grid .slick-cell.error-row { margin-bottom: 0px; } +#alertsDiv .alertview-alertnameindicatorenabled, #proxiesDiv .proxyview-proxynameindicatorenabled { width: 5px; background: green; } - #proxiesDiv .proxyview-proxynameindicatordisabled { + +#alertsDiv .alertview-alertnameindicatordisabled, +#proxiesDiv .proxyview-proxynameindicatordisabled { width: 5px; background: red; } \ No newline at end of file diff --git a/src/sql/parts/jobManagement/views/alertsView.component.ts b/src/sql/parts/jobManagement/views/alertsView.component.ts index 989cd282bf..682fde78b3 100644 --- a/src/sql/parts/jobManagement/views/alertsView.component.ts +++ b/src/sql/parts/jobManagement/views/alertsView.component.ts @@ -30,9 +30,11 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDashboardService } from 'sql/services/dashboard/common/dashboardService'; +import { AlertsCacheObject } from 'sql/parts/jobManagement/common/jobManagementService'; +import { RowDetailView } from 'sql/base/browser/ui/table/plugins/rowdetailview'; export const VIEW_SELECTOR: string = 'jobalertsview-component'; -export const ROW_HEIGHT: number = 30; +export const ROW_HEIGHT: number = 45; @Component({ selector: VIEW_SELECTOR, @@ -42,11 +44,17 @@ export const ROW_HEIGHT: number = 30; export class AlertsViewComponent extends JobManagementView implements OnInit { private columns: Array> = [ - { name: nls.localize('jobAlertColumns.name', 'Name'), field: 'name', width: 200, id: 'name' }, - { name: nls.localize('jobAlertColumns.lastOccurrenceDate', 'Last Occurrence'), field: 'lastOccurrenceDate', width: 200, id: 'lastOccurrenceDate' }, - { name: nls.localize('jobAlertColumns.enabled', 'Enabled'), field: 'enabled', width: 200, id: 'enabled' }, - { name: nls.localize('jobAlertColumns.databaseName', 'Database Name'), field: 'databaseName', width: 200, id: 'databaseName' }, - { name: nls.localize('jobAlertColumns.categoryName', 'Category Name'), field: 'categoryName', width: 200, id: 'categoryName' }, + { + name: nls.localize('jobAlertColumns.name', 'Name'), + field: 'name', + formatter: (row, cell, value, columnDef, dataContext) => this.renderName(row, cell, value, columnDef, dataContext), + width: 500, + id: 'name' + }, + { name: nls.localize('jobAlertColumns.lastOccurrenceDate', 'Last Occurrence'), field: 'lastOccurrenceDate', width: 150, id: 'lastOccurrenceDate' }, + { name: nls.localize('jobAlertColumns.enabled', 'Enabled'), field: 'enabled', width: 80, id: 'enabled' }, + { name: nls.localize('jobAlertColumns.delayBetweenResponses', 'Delay Between Responses (in secs)'), field: 'delayBetweenResponses', width: 200, id: 'delayBetweenResponses' }, + { name: nls.localize('jobAlertColumns.categoryName', 'Category Name'), field: 'categoryName', width: 250, id: 'categoryName' }, ]; private options: Slick.GridOptions = { @@ -59,6 +67,7 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { private dataView: any; private _isCloud: boolean; + private _alertsCacheObject: AlertsCacheObject; @ViewChild('jobalertsgrid') _gridEl: ElementRef; @@ -78,6 +87,15 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { @Inject(IDashboardService) _dashboardService: IDashboardService) { super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService); this._isCloud = commonService.connectionManagementService.connectionInfo.serverInfo.isCloud; + let alertsCacheObjectMap = this._jobManagementService.alertsCacheObjectMap; + let alertsCache = alertsCacheObjectMap[this._serverName]; + if (alertsCache) { + this._alertsCacheObject = alertsCache; + } else { + this._alertsCacheObject = new AlertsCacheObject(); + this._alertsCacheObject.serverName = this._serverName; + this._jobManagementService.addToCache(this._serverName, this._alertsCacheObject); + } } ngOnInit(){ @@ -92,44 +110,67 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { height = 0; } - this._table.layout(new dom.Dimension( - dom.getContentWidth(this._gridEl.nativeElement), - height)); + if (this._table) { + this._table.layout(new dom.Dimension( + dom.getContentWidth(this._gridEl.nativeElement), + height)); + } } onFirstVisible() { let self = this; + let cached: boolean = false; + if (this._alertsCacheObject.serverName === this._serverName) { + if (this._alertsCacheObject.alerts && this._alertsCacheObject.alerts.length > 0) { + cached = true; + this.alerts = this._alertsCacheObject.alerts; + } + } + let columns = this.columns.map((column) => { column.rerenderOnResize = true; return column; }); - this.dataView = new Slick.Data.DataView(); - + this.dataView = new Slick.Data.DataView({ inlineFilters: false }); + let rowDetail = new RowDetailView({ + cssClass: '_detail_selector', + useRowClick: false, + panelRows: 1 + }); + columns.unshift(rowDetail.getColumnDefinition()); $(this._gridEl.nativeElement).empty(); $(this.actionBarContainer.nativeElement).empty(); this.initActionBar(); this._table = new Table(this._gridEl.nativeElement, {columns}, this.options); this._table.grid.setData(this.dataView, true); - this._register(this._table.onContextMenu(e => { self.openContextMenu(e); })); - let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri; - this._jobManagementService.getAlerts(ownerUri).then((result) => { - if (result && result.alerts) { - self.alerts = result.alerts; - self.onAlertsAvailable(result.alerts); - } else { - // TODO: handle error - } - + // check for cached state + if (cached && this._agentViewComponent.refresh !== true) { + self.onAlertsAvailable(this.alerts); this._showProgressWheel = false; if (this.isVisible) { this._cd.detectChanges(); } - }); + } else { + let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri; + this._jobManagementService.getAlerts(ownerUri).then((result) => { + if (result && result.alerts) { + self.alerts = result.alerts; + self._alertsCacheObject.alerts = result.alerts; + self.onAlertsAvailable(result.alerts); + } else { + // TODO: handle error + } + this._showProgressWheel = false; + if (this.isVisible) { + this._cd.detectChanges(); + } + }); + } } private onAlertsAvailable(alerts: sqlops.AgentAlertInfo[]) { @@ -139,7 +180,7 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { name: item.name, lastOccurrenceDate: item.lastOccurrenceDate, enabled: item.isEnabled, - databaseName: item.databaseName, + delayBetweenResponses: item.delayBetweenResponses, categoryName: item.categoryName }; }); @@ -147,6 +188,7 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { this.dataView.beginUpdate(); this.dataView.setItems(items); this.dataView.endUpdate(); + this._alertsCacheObject.dataview = this.dataView; this._table.autosizeColumns(); this._table.resizeCanvas(); } @@ -164,6 +206,17 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { : undefined; } + + private renderName(row, cell, value, columnDef, dataContext) { + let resultIndicatorClass = dataContext.enabled ? 'alertview-alertnameindicatorenabled' : + 'alertview-alertnameindicatordisabled'; + + return '' + + '' + + '' + + '
' + dataContext.name + '
'; + } + public openCreateAlertDialog() { let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri; this._jobManagementService.getJobs(ownerUri).then((result) => { diff --git a/src/sql/parts/jobManagement/views/jobHistory.component.ts b/src/sql/parts/jobManagement/views/jobHistory.component.ts index 57662d387e..f5b7fe33df 100644 --- a/src/sql/parts/jobManagement/views/jobHistory.component.ts +++ b/src/sql/parts/jobManagement/views/jobHistory.component.ts @@ -63,7 +63,6 @@ export class JobHistoryComponent extends JobManagementView implements OnInit { private _jobCacheObject: JobCacheObject; private _agentJobInfo: sqlops.AgentJobInfo; private _noJobsAvailable: boolean = false; - private _serverName: string; private static readonly INITIAL_TREE_HEIGHT: number = 780; private static readonly HEADING_HEIGHT: number = 24; diff --git a/src/sql/parts/jobManagement/views/jobManagementView.ts b/src/sql/parts/jobManagement/views/jobManagementView.ts index e1b04e2b08..5f9a3e241c 100644 --- a/src/sql/parts/jobManagement/views/jobManagementView.ts +++ b/src/sql/parts/jobManagement/views/jobManagementView.ts @@ -28,6 +28,7 @@ export abstract class JobManagementView extends TabChild implements AfterContent protected _parentComponent: AgentViewComponent; protected _table: Table; protected _actionBar: Taskbar; + protected _serverName: string; public contextAction: any; @ViewChild('actionbarContainer') protected actionBarContainer: ElementRef; @@ -41,6 +42,7 @@ export abstract class JobManagementView extends TabChild implements AfterContent super(); let self = this; + this._serverName = this._commonService.connectionManagementService.connectionInfo.connectionProfile.serverName; this._dashboardService.onLayout((d) => { self.layout(); }); diff --git a/src/sql/parts/jobManagement/views/jobsView.component.ts b/src/sql/parts/jobManagement/views/jobsView.component.ts index eb96c1830e..e6e61ba465 100644 --- a/src/sql/parts/jobManagement/views/jobsView.component.ts +++ b/src/sql/parts/jobManagement/views/jobsView.component.ts @@ -78,7 +78,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit { private rowDetail: RowDetailView; private filterPlugin: any; private dataView: any; - private _serverName: string; private _isCloud: boolean; private filterStylingMap: { [columnName: string]: [any]; } = {}; private filterStack = ['start']; @@ -109,7 +108,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit { ) { super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService); let jobCacheObjectMap = this._jobManagementService.jobCacheObjectMap; - this._serverName = commonService.connectionManagementService.connectionInfo.connectionProfile.serverName; let jobCache = jobCacheObjectMap[this._serverName]; if (jobCache) { this._jobCacheObject = jobCache; diff --git a/src/sql/parts/jobManagement/views/operatorsView.component.ts b/src/sql/parts/jobManagement/views/operatorsView.component.ts index 6cfbdb73c8..a50e2e1ddc 100644 --- a/src/sql/parts/jobManagement/views/operatorsView.component.ts +++ b/src/sql/parts/jobManagement/views/operatorsView.component.ts @@ -57,7 +57,6 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit }; private dataView: any; - private _serverName: string; private _isCloud: boolean; @ViewChild('operatorsgrid') _gridEl: ElementRef; diff --git a/src/sql/parts/jobManagement/views/proxiesView.component.ts b/src/sql/parts/jobManagement/views/proxiesView.component.ts index e9697bc451..9ebdf0ab5f 100644 --- a/src/sql/parts/jobManagement/views/proxiesView.component.ts +++ b/src/sql/parts/jobManagement/views/proxiesView.component.ts @@ -69,7 +69,6 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit { }; private dataView: any; - private _serverName: string; private _isCloud: boolean; private _proxiesCacheObject: ProxiesCacheObject;