Add Alert, Operator and Proxy panel tabs (#1811)

* Add Create Alert dialog

* Add Job Alerts view

* Stage WIP

* Add Proxy View component

* Hook up proxy and operator view callbacks

* Style cleanup

* Add additonal columns to views
This commit is contained in:
Karl Burtram
2018-06-30 15:31:40 -07:00
committed by GitHub
parent 0cd47bc328
commit 8cb67b4f9d
33 changed files with 1079 additions and 55 deletions

View File

@@ -0,0 +1,17 @@
<!--
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-->
<div class="job-heading-container">
<h1 class="job-heading" *ngIf="_isCloud === false">Alerts</h1>
<h1 class="job-heading" *ngIf="_isCloud === true">No Alerts Available</h1>
<div class="icon in-progress" *ngIf="_showProgressWheel === true"></div>
</div>
<div class="jobs-view-toolbar">
<div (click)="refreshJobs()" tabindex="0"><div class="small icon refresh"></div><span>{{RefreshText}}</span></div>
<div (click)="openCreateJobDialog()" tabindex="0"><div class="small icon new"></div><span>{{NewAlertText}}</span></div>
</div>
<div #jobalertsgrid class="jobview-grid"></div>

View File

@@ -0,0 +1,160 @@
/*---------------------------------------------------------------------------------------------
* 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!sql/parts/grid/media/slickColorTheme';
import 'vs/css!sql/parts/grid/media/flexbox';
import 'vs/css!sql/parts/grid/media/styles';
import 'vs/css!sql/parts/grid/media/slick.grid';
import 'vs/css!sql/parts/grid/media/slickGrid';
import 'vs/css!../common/media/jobs';
import 'vs/css!sql/media/icons/common-icons';
import 'vs/css!sql/base/browser/ui/table/media/table';
import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, AfterContentChecked } from '@angular/core';
import * as sqlops from 'sqlops';
import * as nls from 'vs/nls';
import { Table } from 'sql/base/browser/ui/table/table';
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
import * as dom from 'vs/base/browser/dom';
import { IJobManagementService } from '../common/interfaces';
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
import { ICommandService } from 'vs/platform/commands/common/commands';
export const VIEW_SELECTOR: string = 'jobalertsview-component';
export const ROW_HEIGHT: number = 45;
@Component({
selector: VIEW_SELECTOR,
templateUrl: decodeURI(require.toUrl('./alertsView.component.html')),
providers: [{ provide: TabChild, useExisting: forwardRef(() => AlertsViewComponent) }],
})
export class AlertsViewComponent implements AfterContentChecked {
private columns: Array<Slick.Column<any>> = [
{ 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' },
];
private options: Slick.GridOptions<any> = {
syncColumnCellResize: true,
enableColumnReorder: false,
rowHeight: 45,
enableCellNavigation: true,
editable: false
};
private dataView: any;
@ViewChild('jobalertsgrid') _gridEl: ElementRef;
private isVisible: boolean = false;
private isInitialized: boolean = false;
private isRefreshing: boolean = false;
private _table: Table<any>;
public alerts: sqlops.AgentAlertInfo[];
private _serverName: string;
private _isCloud: boolean;
private _showProgressWheel: boolean;
private NewAlertText: string = nls.localize('jobAlertToolbar-NewJob', "New Alert");
private RefreshText: string = nls.localize('jobAlertToolbar-Refresh', "Refresh");
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _dashboardService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
@Inject(forwardRef(() => AgentViewComponent)) private _agentViewComponent: AgentViewComponent,
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService,
@Inject(IThemeService) private _themeService: IThemeService,
@Inject(ICommandService) private _commandService: ICommandService
) {
this._isCloud = this._dashboardService.connectionManagementService.connectionInfo.serverInfo.isCloud;
}
public layout() {
this._table.layout(new dom.Dimension(dom.getContentWidth(this._gridEl.nativeElement), dom.getContentHeight(this._gridEl.nativeElement)));
}
ngAfterContentChecked() {
if (this.isVisible === false && this._gridEl.nativeElement.offsetParent !== null) {
this.isVisible = true;
if (!this.isInitialized) {
this._showProgressWheel = true;
this.onFirstVisible(false);
this.isInitialized = true;
}
} else if (this.isVisible === true && this._agentViewComponent.refresh === true) {
this._showProgressWheel = true;
this.onFirstVisible(false);
this.isRefreshing = true;
this._agentViewComponent.refresh = false;
} else if (this.isVisible === true && this._gridEl.nativeElement.offsetParent === null) {
this.isVisible = false;
}
}
onFirstVisible(cached?: boolean) {
let self = this;
let columns = this.columns.map((column) => {
column.rerenderOnResize = true;
return column;
});
let options = <Slick.GridOptions<any>>{
syncColumnCellResize: true,
enableColumnReorder: false,
rowHeight: ROW_HEIGHT,
enableCellNavigation: true,
forceFitColumns: true
};
this.dataView = new Slick.Data.DataView();
$(this._gridEl.nativeElement).empty();
this._table = new Table(this._gridEl.nativeElement, undefined, columns, this.options);
this._table.grid.setData(this.dataView, true);
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._jobManagementService.getAlerts(ownerUri).then((result) => {
if (result && result.alerts) {
self.alerts = result.alerts;
self.onAlertsAvailable(result.alerts);
}
});
}
private onAlertsAvailable(alerts: sqlops.AgentAlertInfo[]) {
let items: any = alerts.map((item) => {
return {
id: item.id,
name: item.name,
lastOccurrenceDate: item.lastOccurrenceDate,
enabled: item.isEnabled,
databaseName: item.databaseName,
categoryName: item.categoryName
};
});
this.dataView.beginUpdate();
this.dataView.setItems(items);
this.dataView.endUpdate();
this._table.autosizeColumns();
this._table.resizeCanvas();
this._showProgressWheel = false;
this._cd.detectChanges();
}
private openCreateJobDialog() {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._commandService.executeCommand('agent.openCreateAlertDialog', ownerUri);
}
private refreshJobs() {
this._agentViewComponent.refresh = true;
}
}

View File

@@ -96,7 +96,7 @@ export class JobsViewComponent implements AfterContentChecked {
private filterValueMap: { [columnName: string]: string[]; } = {};
private sortingStylingMap: { [columnName: string]: any; } = {};
private NewJobText: string = nls.localize("jobsToolbar-NewJob", "New job");
private NewJobText: string = nls.localize("jobsToolbar-NewJob", "New Job");
private RefreshText: string = nls.localize("jobsToolbar-Refresh", "Refresh");
constructor(
@@ -145,13 +145,13 @@ export class JobsViewComponent implements AfterContentChecked {
this.onFirstVisible(false);
this.isRefreshing = true;
this._agentViewComponent.refresh = false;
} else if (this.isVisible === true && this._agentViewComponent.refresh === false) {
} /*else if (this.isVisible === true && this._agentViewComponent.refresh === false) {
if (!this.isRefreshing) {
this._showProgressWheel = true;
this.onFirstVisible(true);
}
this.isRefreshing = false;
} else if (this.isVisible === true && this._gridEl.nativeElement.offsetParent === null) {
}*/ else if (this.isVisible === true && this._gridEl.nativeElement.offsetParent === null) {
this.isVisible = false;
}
}
@@ -346,7 +346,11 @@ export class JobsViewComponent implements AfterContentChecked {
currentTarget.title = currentTarget.innerText;
});
this._showProgressWheel = false;
this._cd.detectChanges();
if (this.isVisible) {
this._cd.detectChanges();
}
const self = this;
$(window).resize(() => {
let jobsViewToolbar = $('jobsview-component .jobs-view-toolbar').get(0);
@@ -827,7 +831,7 @@ export class JobsViewComponent implements AfterContentChecked {
private openCreateJobDialog() {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._commandService.executeCommand("agent.openCreateJobDialog", ownerUri);
this._commandService.executeCommand('agent.openCreateJobDialog', ownerUri);
}
private refreshJobs() {

View File

@@ -0,0 +1,17 @@
<!--
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-->
<div class="job-heading-container">
<h1 class="job-heading" *ngIf="_isCloud === false">Operators</h1>
<h1 class="job-heading" *ngIf="_isCloud === true">No Operators Available</h1>
<div class="icon in-progress" *ngIf="_showProgressWheel === true"></div>
</div>
<div class="jobs-view-toolbar">
<div (click)="refreshJobs()" tabindex="0"><div class="small icon refresh"></div><span>{{RefreshText}}</span></div>
<div (click)="openCreateOperatorDialog()" tabindex="0"><div class="small icon new"></div><span>{{NewOperatorText}}</span></div>
</div>
<div #operatorsgrid class="joboperatorsview-grid"></div>

View File

@@ -0,0 +1,157 @@
/*---------------------------------------------------------------------------------------------
* 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!sql/parts/grid/media/slickColorTheme';
import 'vs/css!sql/parts/grid/media/flexbox';
import 'vs/css!sql/parts/grid/media/styles';
import 'vs/css!sql/parts/grid/media/slick.grid';
import 'vs/css!sql/parts/grid/media/slickGrid';
import 'vs/css!../common/media/jobs';
import 'vs/css!sql/media/icons/common-icons';
import 'vs/css!sql/base/browser/ui/table/media/table';
import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, AfterContentChecked } from '@angular/core';
import * as sqlops from 'sqlops';
import * as nls from 'vs/nls';
import { Table } from 'sql/base/browser/ui/table/table';
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
import * as dom from 'vs/base/browser/dom';
import { IJobManagementService } from '../common/interfaces';
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
import { ICommandService } from 'vs/platform/commands/common/commands';
export const VIEW_SELECTOR: string = 'joboperatorsview-component';
export const ROW_HEIGHT: number = 45;
@Component({
selector: VIEW_SELECTOR,
templateUrl: decodeURI(require.toUrl('./operatorsView.component.html')),
providers: [{ provide: TabChild, useExisting: forwardRef(() => OperatorsViewComponent) }],
})
export class OperatorsViewComponent implements AfterContentChecked {
private columns: Array<Slick.Column<any>> = [
{ name: nls.localize('jobOperatorsView.name', 'Name'), field: 'name', width: 200, id: 'name' },
{ name: nls.localize('jobOperatorsView.emailAddress', 'Email Address'), field: 'emailAddress', width: 200, id: 'emailAddress' },
{ name: nls.localize('jobOperatorsView.enabled', 'Enabled'), field: 'enabled', width: 200, id: 'enabled' },
];
private options: Slick.GridOptions<any> = {
syncColumnCellResize: true,
enableColumnReorder: false,
rowHeight: 45,
enableCellNavigation: true,
editable: false
};
private dataView: any;
@ViewChild('operatorsgrid') _gridEl: ElementRef;
private isVisible: boolean = false;
private isInitialized: boolean = false;
private isRefreshing: boolean = false;
private _table: Table<any>;
public operators: sqlops.AgentOperatorInfo[];
private _serverName: string;
private _isCloud: boolean;
private _showProgressWheel: boolean;
private NewOperatorText: string = nls.localize('jobOperatorToolbar-NewItem', "New Operator");
private RefreshText: string = nls.localize('jobOperatorToolbar-Refresh', "Refresh");
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _dashboardService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
@Inject(forwardRef(() => AgentViewComponent)) private _agentViewComponent: AgentViewComponent,
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService,
@Inject(IThemeService) private _themeService: IThemeService,
@Inject(ICommandService) private _commandService: ICommandService
) {
this._isCloud = this._dashboardService.connectionManagementService.connectionInfo.serverInfo.isCloud;
}
public layout() {
this._table.layout(new dom.Dimension(dom.getContentWidth(this._gridEl.nativeElement), dom.getContentHeight(this._gridEl.nativeElement)));
}
ngAfterContentChecked() {
if (this.isVisible === false && this._gridEl.nativeElement.offsetParent !== null) {
this.isVisible = true;
if (!this.isInitialized) {
this._showProgressWheel = true;
this.onFirstVisible(false);
this.isInitialized = true;
}
} else if (this.isVisible === true && this._agentViewComponent.refresh === true) {
this._showProgressWheel = true;
this.onFirstVisible(false);
this.isRefreshing = true;
this._agentViewComponent.refresh = false;
} else if (this.isVisible === true && this._gridEl.nativeElement.offsetParent === null) {
this.isVisible = false;
}
}
onFirstVisible(cached?: boolean) {
let self = this;
let columns = this.columns.map((column) => {
column.rerenderOnResize = true;
return column;
});
let options = <Slick.GridOptions<any>>{
syncColumnCellResize: true,
enableColumnReorder: false,
rowHeight: ROW_HEIGHT,
enableCellNavigation: true,
forceFitColumns: true
};
this.dataView = new Slick.Data.DataView();
$(this._gridEl.nativeElement).empty();
this._table = new Table(this._gridEl.nativeElement, undefined, columns, this.options);
this._table.grid.setData(this.dataView, true);
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._jobManagementService.getOperators(ownerUri).then((result) => {
if (result && result.operators) {
self.operators = result.operators;
self.onOperatorsAvailable(result.operators);
}
});
}
private onOperatorsAvailable(operators: sqlops.AgentOperatorInfo[]) {
let items: any = operators.map((item) => {
return {
id: item.id,
name: item.name,
emailAddress: item.emailAddress,
enabled: item.enabled
};
});
this.dataView.beginUpdate();
this.dataView.setItems(items);
this.dataView.endUpdate();
this._table.autosizeColumns();
this._table.resizeCanvas();
this._showProgressWheel = false;
this._cd.detectChanges();
}
private openCreateOperatorDialog() {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._commandService.executeCommand('agent.openCreateOperatorDialog', ownerUri);
}
private refreshJobs() {
this._agentViewComponent.refresh = true;
}
}

View File

@@ -0,0 +1,17 @@
<!--
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-->
<div class="job-heading-container">
<h1 class="job-heading" *ngIf="_isCloud === false">Proxies</h1>
<h1 class="job-heading" *ngIf="_isCloud === true">No Proxies Available</h1>
<div class="icon in-progress" *ngIf="_showProgressWheel === true"></div>
</div>
<div class="jobs-view-toolbar">
<div (click)="refreshJobs()" tabindex="0"><div class="small icon refresh"></div><span>{{RefreshText}}</span></div>
<div (click)="openCreateProxyDialog()" tabindex="0"><div class="small icon new"></div><span>{{NewProxyText}}</span></div>
</div>
<div #proxiesgrid class="jobproxiesview-grid"></div>

View File

@@ -0,0 +1,155 @@
/*---------------------------------------------------------------------------------------------
* 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!sql/parts/grid/media/slickColorTheme';
import 'vs/css!sql/parts/grid/media/flexbox';
import 'vs/css!sql/parts/grid/media/styles';
import 'vs/css!sql/parts/grid/media/slick.grid';
import 'vs/css!sql/parts/grid/media/slickGrid';
import 'vs/css!../common/media/jobs';
import 'vs/css!sql/media/icons/common-icons';
import 'vs/css!sql/base/browser/ui/table/media/table';
import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, AfterContentChecked } from '@angular/core';
import * as sqlops from 'sqlops';
import * as nls from 'vs/nls';
import { Table } from 'sql/base/browser/ui/table/table';
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
import * as dom from 'vs/base/browser/dom';
import { IJobManagementService } from '../common/interfaces';
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
import { ICommandService } from 'vs/platform/commands/common/commands';
export const VIEW_SELECTOR: string = 'jobproxiesview-component';
export const ROW_HEIGHT: number = 45;
@Component({
selector: VIEW_SELECTOR,
templateUrl: decodeURI(require.toUrl('./proxiesView.component.html')),
providers: [{ provide: TabChild, useExisting: forwardRef(() => ProxiesViewComponent) }],
})
export class ProxiesViewComponent implements AfterContentChecked {
private columns: Array<Slick.Column<any>> = [
{ name: nls.localize('jobProxiesView.accountName', 'Account Name'), field: 'accountName', width: 200, id: 'accountName' },
{ name: nls.localize('jobProxiesView.credentialName', 'Credential Name'), field: 'credentialName', width: 200, id: 'credentialName' },
];
private options: Slick.GridOptions<any> = {
syncColumnCellResize: true,
enableColumnReorder: false,
rowHeight: 45,
enableCellNavigation: true,
editable: false
};
private dataView: any;
@ViewChild('proxiesgrid') _gridEl: ElementRef;
private isVisible: boolean = false;
private isInitialized: boolean = false;
private isRefreshing: boolean = false;
private _table: Table<any>;
public proxies: sqlops.AgentProxyInfo[];
private _serverName: string;
private _isCloud: boolean;
private _showProgressWheel: boolean;
private NewProxyText: string = nls.localize('jobProxyToolbar-NewItem', "New Proxy");
private RefreshText: string = nls.localize('jobProxyToolbar-Refresh', "Refresh");
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _dashboardService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
@Inject(forwardRef(() => AgentViewComponent)) private _agentViewComponent: AgentViewComponent,
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService,
@Inject(IThemeService) private _themeService: IThemeService,
@Inject(ICommandService) private _commandService: ICommandService
) {
this._isCloud = this._dashboardService.connectionManagementService.connectionInfo.serverInfo.isCloud;
}
public layout() {
this._table.layout(new dom.Dimension(dom.getContentWidth(this._gridEl.nativeElement), dom.getContentHeight(this._gridEl.nativeElement)));
}
ngAfterContentChecked() {
if (this.isVisible === false && this._gridEl.nativeElement.offsetParent !== null) {
this.isVisible = true;
if (!this.isInitialized) {
this._showProgressWheel = true;
this.onFirstVisible(false);
this.isInitialized = true;
}
} else if (this.isVisible === true && this._agentViewComponent.refresh === true) {
this._showProgressWheel = true;
this.onFirstVisible(false);
this.isRefreshing = true;
this._agentViewComponent.refresh = false;
} else if (this.isVisible === true && this._gridEl.nativeElement.offsetParent === null) {
this.isVisible = false;
}
}
onFirstVisible(cached?: boolean) {
let self = this;
let columns = this.columns.map((column) => {
column.rerenderOnResize = true;
return column;
});
let options = <Slick.GridOptions<any>>{
syncColumnCellResize: true,
enableColumnReorder: false,
rowHeight: ROW_HEIGHT,
enableCellNavigation: true,
forceFitColumns: true
};
this.dataView = new Slick.Data.DataView();
$(this._gridEl.nativeElement).empty();
this._table = new Table(this._gridEl.nativeElement, undefined, columns, this.options);
this._table.grid.setData(this.dataView, true);
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._jobManagementService.getProxies(ownerUri).then((result) => {
if (result && result.proxies) {
self.proxies = result.proxies;
self.onProxiesAvailable(result.proxies);
}
});
}
private onProxiesAvailable(proxies: sqlops.AgentProxyInfo[]) {
let items: any = proxies.map((item) => {
return {
id: item.id,
accountName: item.accountName,
credentialName: item.credentialName
};
});
this.dataView.beginUpdate();
this.dataView.setItems(items);
this.dataView.endUpdate();
this._table.autosizeColumns();
this._table.resizeCanvas();
this._showProgressWheel = false;
this._cd.detectChanges();
}
private openCreateProxyDialog() {
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
this._commandService.executeCommand('agent.openCreateProxyDialog', ownerUri);
}
private refreshJobs() {
this._agentViewComponent.refresh = true;
}
}