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,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import { AgentUtils } from '../agentUtils';
export class CreateAlertData {
public ownerUri: string;
private _alert: sqlops.AgentAlertInfo;
constructor(ownerUri:string) {
this.ownerUri = ownerUri;
}
public async initialize() {
let agentService = await AgentUtils.getAgentService();
}
public async save() {
}
}

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import { AgentUtils } from '../agentUtils';
export class CreateScheduleData {
public ownerUri: string;
public schedules: sqlops.AgentJobScheduleInfo[];
public selectedSchedule: sqlops.AgentJobScheduleInfo;
constructor(ownerUri:string) {
this.ownerUri = ownerUri;
}
public async initialize() {
let agentService = await AgentUtils.getAgentService();
let result = await agentService.getJobSchedules(this.ownerUri);
if (result && result.success) {
this.schedules = result.schedules;
}
}
public async save() {
}
}

View File

@@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
import { CreateAlertData } from '../data/createAlertData';
export class CreateAlertDialog {
// Top level
private readonly DialogTitle: string = 'Create Alert';
private readonly OkButtonText: string = 'OK';
private readonly CancelButtonText: string = 'Cancel';
private readonly GeneralTabText: string = 'Response';
private readonly ResponseTabText: string = 'Steps';
private readonly OptionsTabText: string = 'Options';
private readonly HistoryTabText: string = 'History';
// General tab strings
private readonly NameTextBoxLabel: string = 'Name';
// Response tab strings
private readonly ExecuteJobTextBoxLabel: string = 'Execute Job';
// Options tab strings
private readonly AdditionalMessageTextBoxLabel: string = 'Additional notification message to send';
// History tab strings
private readonly ResetCountTextBoxLabel: string = 'Reset Count';
// UI Components
private dialog: sqlops.window.modelviewdialog.Dialog;
private generalTab: sqlops.window.modelviewdialog.DialogTab;
private responseTab: sqlops.window.modelviewdialog.DialogTab;
private optionsTab: sqlops.window.modelviewdialog.DialogTab;
private historyTab: sqlops.window.modelviewdialog.DialogTab;
private schedulesTable: sqlops.TableComponent;
// General tab controls
private nameTextBox: sqlops.InputBoxComponent;
// Response tab controls
private executeJobTextBox: sqlops.InputBoxComponent;
// Options tab controls
private additionalMessageTextBox: sqlops.InputBoxComponent;
// History tab controls
private resetCountTextBox: sqlops.InputBoxComponent;
private model: CreateAlertData;
private _onSuccess: vscode.EventEmitter<CreateAlertData> = new vscode.EventEmitter<CreateAlertData>();
public readonly onSuccess: vscode.Event<CreateAlertData> = this._onSuccess.event;
constructor(ownerUri: string) {
this.model = new CreateAlertData(ownerUri);
}
public async showDialog() {
await this.model.initialize();
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
this.generalTab = sqlops.window.modelviewdialog.createTab(this.GeneralTabText);
this.responseTab = sqlops.window.modelviewdialog.createTab(this.ResponseTabText);
this.optionsTab = sqlops.window.modelviewdialog.createTab(this.OptionsTabText);
this.historyTab = sqlops.window.modelviewdialog.createTab(this.HistoryTabText);
this.initializeGeneralTab();
this.initializeResponseTab();
this.initializeOptionsTab();
this.initializeHistoryTab();
this.dialog.content = [this.generalTab, this.responseTab, this.optionsTab, this.historyTab];
this.dialog.okButton.onClick(async () => await this.execute());
this.dialog.cancelButton.onClick(async () => await this.cancel());
this.dialog.okButton.label = this.OkButtonText;
this.dialog.cancelButton.label = this.CancelButtonText;
sqlops.window.modelviewdialog.openDialog(this.dialog);
}
private initializeGeneralTab() {
this.generalTab.registerContent(async view => {
this.nameTextBox = view.modelBuilder.inputBox().component();
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: this.nameTextBox,
title: this.NameTextBoxLabel
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
});
}
private initializeResponseTab() {
this.responseTab.registerContent(async view => {
this.executeJobTextBox = view.modelBuilder.inputBox().component();
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: this.executeJobTextBox,
title: this.ExecuteJobTextBoxLabel
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
});
}
private initializeOptionsTab() {
this.optionsTab.registerContent(async view => {
this.additionalMessageTextBox = view.modelBuilder.inputBox().component();
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: this.additionalMessageTextBox,
title: this.AdditionalMessageTextBoxLabel
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
});
}
private initializeHistoryTab() {
this.historyTab.registerContent(async view => {
this.resetCountTextBox = view.modelBuilder.inputBox().component();
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: this.resetCountTextBox,
title: this.ResetCountTextBoxLabel
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
});
}
private async execute() {
this.updateModel();
await this.model.save();
this._onSuccess.fire(this.model);
}
private async cancel() {
}
private updateModel() {
}
}

View File

@@ -7,12 +7,12 @@ import * as sqlops from 'sqlops';
import { CreateJobData } from '../data/createJobData'; import { CreateJobData } from '../data/createJobData';
import { CreateStepDialog } from './createStepDialog'; import { CreateStepDialog } from './createStepDialog';
import { PickScheduleDialog } from './pickScheduleDialog'; import { PickScheduleDialog } from './pickScheduleDialog';
import { CreateAlertDialog } from './createAlertDialog';
export class CreateJobDialog { export class CreateJobDialog {
// TODO: localize // TODO: localize
// Top level // Top level
//
private readonly DialogTitle: string = 'New Job'; private readonly DialogTitle: string = 'New Job';
private readonly OkButtonText: string = 'OK'; private readonly OkButtonText: string = 'OK';
private readonly CancelButtonText: string = 'Cancel'; private readonly CancelButtonText: string = 'Cancel';
@@ -23,7 +23,6 @@ export class CreateJobDialog {
private readonly NotificationsTabText: string = 'Notifications'; private readonly NotificationsTabText: string = 'Notifications';
// General tab strings // General tab strings
//
private readonly NameTextBoxLabel: string = 'Name'; private readonly NameTextBoxLabel: string = 'Name';
private readonly OwnerTextBoxLabel: string = 'Owner'; private readonly OwnerTextBoxLabel: string = 'Owner';
private readonly CategoryDropdownLabel: string = 'Category'; private readonly CategoryDropdownLabel: string = 'Category';
@@ -43,7 +42,6 @@ export class CreateJobDialog {
private readonly DeleteStepButtonString: string = 'Delete'; private readonly DeleteStepButtonString: string = 'Delete';
// Notifications tab strings // Notifications tab strings
//
private readonly NotificationsTabTopLabelString: string = 'Actions to perform when the job completes'; private readonly NotificationsTabTopLabelString: string = 'Actions to perform when the job completes';
private readonly EmailCheckBoxString: string = 'Email'; private readonly EmailCheckBoxString: string = 'Email';
private readonly PagerCheckBoxString: string = 'Page'; private readonly PagerCheckBoxString: string = 'Page';
@@ -51,10 +49,14 @@ export class CreateJobDialog {
private readonly DeleteJobCheckBoxString: string = 'Automatically delete job'; private readonly DeleteJobCheckBoxString: string = 'Automatically delete job';
// Schedules tab strings // Schedules tab strings
private readonly SchedulesTopLabelString: string = 'Schedules list';
private readonly PickScheduleButtonString: string = 'Pick Schedule'; private readonly PickScheduleButtonString: string = 'Pick Schedule';
// Alerts tab strings
private readonly AlertsTopLabelString: string = 'Alerts list';
private readonly NewAlertButtonString: string = 'New Alert';
// UI Components // UI Components
//
private dialog: sqlops.window.modelviewdialog.Dialog; private dialog: sqlops.window.modelviewdialog.Dialog;
private generalTab: sqlops.window.modelviewdialog.DialogTab; private generalTab: sqlops.window.modelviewdialog.DialogTab;
private stepsTab: sqlops.window.modelviewdialog.DialogTab; private stepsTab: sqlops.window.modelviewdialog.DialogTab;
@@ -63,7 +65,6 @@ export class CreateJobDialog {
private notificationsTab: sqlops.window.modelviewdialog.DialogTab; private notificationsTab: sqlops.window.modelviewdialog.DialogTab;
// General tab controls // General tab controls
//
private nameTextBox: sqlops.InputBoxComponent; private nameTextBox: sqlops.InputBoxComponent;
private ownerTextBox: sqlops.InputBoxComponent; private ownerTextBox: sqlops.InputBoxComponent;
private categoryDropdown: sqlops.DropDownComponent; private categoryDropdown: sqlops.DropDownComponent;
@@ -94,6 +95,10 @@ export class CreateJobDialog {
private schedulesTable: sqlops.TableComponent; private schedulesTable: sqlops.TableComponent;
private pickScheduleButton: sqlops.ButtonComponent; private pickScheduleButton: sqlops.ButtonComponent;
// Alert tab controls
private alertsTable: sqlops.TableComponent;
private newAlertButton: sqlops.ButtonComponent;
private model: CreateJobData; private model: CreateJobData;
constructor(ownerUri: string) { constructor(ownerUri: string) {
@@ -225,6 +230,38 @@ export class CreateJobDialog {
} }
private initializeAlertsTab() { private initializeAlertsTab() {
this.alertsTab.registerContent(async view => {
this.alertsTable = view.modelBuilder.table()
.withProperties({
columns: [
'Alert Name'
],
data: [],
height: 600,
width: 400
}).component();
this.newAlertButton = view.modelBuilder.button().withProperties({
label: this.NewAlertButtonString,
width: 80
}).component();
this.newAlertButton.onDidClick((e)=>{
let alertDialog = new CreateAlertDialog(this.model.ownerUri);
alertDialog.onSuccess((dialogModel) => {
});
alertDialog.showDialog();
});
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: this.alertsTable,
title: this.AlertsTopLabelString,
actions: [this.newAlertButton]
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
});
} }
private initializeSchedulesTab() { private initializeSchedulesTab() {
@@ -259,7 +296,7 @@ export class CreateJobDialog {
let formModel = view.modelBuilder.formContainer() let formModel = view.modelBuilder.formContainer()
.withFormItems([{ .withFormItems([{
component: this.schedulesTable, component: this.schedulesTable,
title: this.JobStepsTopLabelString, title: this.SchedulesTopLabelString,
actions: [this.pickScheduleButton] actions: [this.pickScheduleButton]
}]).withLayout({ width: '100%' }).component(); }]).withLayout({ width: '100%' }).component();

View File

@@ -0,0 +1,91 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
import { CreateScheduleData } from '../data/createScheduleData';
export class CreateScheduleDialog {
// Top level
private readonly DialogTitle: string = 'New Schedule';
private readonly OkButtonText: string = 'OK';
private readonly CancelButtonText: string = 'Cancel';
// UI Components
private dialog: sqlops.window.modelviewdialog.Dialog;
private schedulesTable: sqlops.TableComponent;
private model: CreateScheduleData;
private _onSuccess: vscode.EventEmitter<CreateScheduleData> = new vscode.EventEmitter<CreateScheduleData>();
public readonly onSuccess: vscode.Event<CreateScheduleData> = this._onSuccess.event;
constructor(ownerUri: string) {
this.model = new CreateScheduleData(ownerUri);
}
public async showDialog() {
await this.model.initialize();
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
this.initializeContent();
this.dialog.okButton.onClick(async () => await this.execute());
this.dialog.cancelButton.onClick(async () => await this.cancel());
this.dialog.okButton.label = this.OkButtonText;
this.dialog.cancelButton.label = this.CancelButtonText;
sqlops.window.modelviewdialog.openDialog(this.dialog);
}
private initializeContent() {
this.dialog.registerContent(async view => {
this.schedulesTable = view.modelBuilder.table()
.withProperties({
columns: [
'Schedule Name'
],
data: [],
height: 600,
width: 400
}).component();
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: this.schedulesTable,
title: 'Schedules'
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
if (this.model.schedules) {
let data: any[][] = [];
for (let i = 0; i < this.model.schedules.length; ++i) {
let schedule = this.model.schedules[i];
data[i] = [ schedule.name ];
}
this.schedulesTable.data = data;
}
});
}
private async execute() {
this.updateModel();
await this.model.save();
this._onSuccess.fire(this.model);
}
private async cancel() {
}
private updateModel() {
let selectedRows = this.schedulesTable.selectedRows;
if (selectedRows && selectedRows.length > 0) {
let selectedRow = selectedRows[0];
this.model.selectedSchedule = this.model.schedules[selectedRow];
}
}
}

View File

@@ -19,7 +19,6 @@ export class PickScheduleDialog {
// UI Components // UI Components
private dialog: sqlops.window.modelviewdialog.Dialog; private dialog: sqlops.window.modelviewdialog.Dialog;
private scheduleTab: sqlops.window.modelviewdialog.DialogTab;
private schedulesTable: sqlops.TableComponent; private schedulesTable: sqlops.TableComponent;
private model: PickScheduleData; private model: PickScheduleData;
@@ -34,7 +33,6 @@ export class PickScheduleDialog {
public async showDialog() { public async showDialog() {
await this.model.initialize(); await this.model.initialize();
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle); this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
this.scheduleTab = sqlops.window.modelviewdialog.createTab(this.SchedulesTabText);
this.initializeContent(); this.initializeContent();
this.dialog.okButton.onClick(async () => await this.execute()); this.dialog.okButton.onClick(async () => await this.execute());
this.dialog.cancelButton.onClick(async () => await this.cancel()); this.dialog.cancelButton.onClick(async () => await this.cancel());

View File

@@ -6,12 +6,10 @@
import vscode = require('vscode'); import vscode = require('vscode');
import { MainController } from './mainController'; import { MainController } from './mainController';
import { ApiWrapper } from './apiWrapper';
export let controller: MainController; export let controller: MainController;
export function activate(context: vscode.ExtensionContext) { export function activate(context: vscode.ExtensionContext) {
let apiWrapper = new ApiWrapper(); controller = new MainController(context);
controller = new MainController(context, apiWrapper);
controller.activate(); controller.activate();
} }

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ApiWrapper } from './apiWrapper'; import { CreateAlertDialog } from './dialogs/createAlertDialog';
import { CreateJobDialog } from './dialogs/createJobDialog'; import { CreateJobDialog } from './dialogs/createJobDialog';
import { CreateStepDialog } from './dialogs/createStepDialog'; import { CreateStepDialog } from './dialogs/createStepDialog';
import { PickScheduleDialog } from './dialogs/pickScheduleDialog'; import { PickScheduleDialog } from './dialogs/pickScheduleDialog';
@@ -13,21 +13,16 @@ import { PickScheduleDialog } from './dialogs/pickScheduleDialog';
* The main controller class that initializes the extension * The main controller class that initializes the extension
*/ */
export class MainController { export class MainController {
protected _apiWrapper: ApiWrapper;
protected _context: vscode.ExtensionContext; protected _context: vscode.ExtensionContext;
// PUBLIC METHODS ////////////////////////////////////////////////////// // PUBLIC METHODS //////////////////////////////////////////////////////
public constructor(context: vscode.ExtensionContext, apiWrapper?: ApiWrapper) { public constructor(context: vscode.ExtensionContext) {
this._apiWrapper = apiWrapper || new ApiWrapper();
this._context = context; this._context = context;
} }
/** /**
* Deactivates the extension * Activates the extension
*/ */
public deactivate(): void {
}
public activate(): void { public activate(): void {
vscode.commands.registerCommand('agent.openCreateJobDialog', (ownerUri: string) => { vscode.commands.registerCommand('agent.openCreateJobDialog', (ownerUri: string) => {
let dialog = new CreateJobDialog(ownerUri); let dialog = new CreateJobDialog(ownerUri);
@@ -41,9 +36,19 @@ export class MainController {
let dialog = new PickScheduleDialog(ownerUri); let dialog = new PickScheduleDialog(ownerUri);
dialog.showDialog(); dialog.showDialog();
}); });
} vscode.commands.registerCommand('agent.openCreateAlertDialog', (ownerUri: string) => {
let dialog = new CreateAlertDialog(ownerUri);
dialog.showDialog();
});
vscode.commands.registerCommand('agent.openCreateOperatorDialog', (ownerUri: string) => {
});
vscode.commands.registerCommand('agent.openCreateProxyDialog', (ownerUri: string) => {
});
}
private updateJobStepDialog() { /**
* Deactivates the extension
} */
public deactivate(): void {
}
} }

View File

@@ -1,6 +1,6 @@
{ {
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "1.5.0-alpha.1", "version": "1.5.0-alpha.2",
"downloadFileNames": { "downloadFileNames": {
"Windows_86": "win-x86-netcoreapp2.1.zip", "Windows_86": "win-x86-netcoreapp2.1.zip",
"Windows_64": "win-x64-netcoreapp2.1.zip", "Windows_64": "win-x64-netcoreapp2.1.zip",

View File

@@ -409,7 +409,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
); );
}; };
let updateJobSchedule= (ownerUri: string, originalScheduleName: string, scheduleInfo: sqlops.AgentJobScheduleInfo): Thenable<sqlops.UpdateAgentJobScheduleResult> => { let updateJobSchedule = (ownerUri: string, originalScheduleName: string, scheduleInfo: sqlops.AgentJobScheduleInfo): Thenable<sqlops.UpdateAgentJobScheduleResult> => {
let params: contracts.UpdateAgentJobScheduleParams = { let params: contracts.UpdateAgentJobScheduleParams = {
ownerUri: ownerUri, ownerUri: ownerUri,
originalScheduleName: originalScheduleName, originalScheduleName: originalScheduleName,

View File

@@ -51,7 +51,10 @@ import { ControlHostContent } from 'sql/parts/dashboard/contents/controlHostCont
import { DashboardControlHostContainer } from 'sql/parts/dashboard/containers/dashboardControlHostContainer.component'; import { DashboardControlHostContainer } from 'sql/parts/dashboard/containers/dashboardControlHostContainer.component';
import { JobsViewComponent } from 'sql/parts/jobManagement/views/jobsView.component'; import { JobsViewComponent } from 'sql/parts/jobManagement/views/jobsView.component';
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component'; import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
import { AlertsViewComponent } from 'sql/parts/jobManagement/views/alertsView.component';
import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component'; import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component';
import { OperatorsViewComponent } from 'sql/parts/jobManagement/views/operatorsView.component';
import { ProxiesViewComponent } from 'sql/parts/jobManagement/views/proxiesView.component';
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
@@ -59,9 +62,8 @@ import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer, let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer,
DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, ModelViewContent, WebviewContent, WidgetContent, DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, ModelViewContent, WebviewContent, WidgetContent,
ComponentHostDirective, BreadcrumbComponent, ControlHostContent, DashboardControlHostContainer, ComponentHostDirective, BreadcrumbComponent, ControlHostContent, DashboardControlHostContainer,
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent, DashboardModelViewContainer, ModelComponentWrapper, Checkbox, JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent, AlertsViewComponent, ProxiesViewComponent, OperatorsViewComponent,
SelectBox, DashboardModelViewContainer, ModelComponentWrapper, Checkbox, SelectBox, InputBox,];
InputBox,];
/* Panel */ /* Panel */
import { PanelModule } from 'sql/base/browser/ui/panel/panel.module'; import { PanelModule } from 'sql/base/browser/ui/panel/panel.module';

View File

@@ -4,17 +4,42 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
--> -->
<div id="agentViewDiv" class="fullsize">
<panel class="dashboard-panel" [options]="panelOpt"> <panel class="dashboard-panel" [options]="panelOpt">
<tab [title]="jobsComponentTitle" class="fullsize" [identifier]="jobsTabIdentifier" <tab [title]="jobsComponentTitle" class="fullsize" [identifier]="jobsTabIdentifier"
[iconClass]="jobsIconClass"> [iconClass]="jobsIconClass">
<ng-template> <ng-template>
<div id="jobsDiv" class="fullsize" *ngIf="showHistory === false"> <div id="jobsDiv" class="fullsize" *ngIf="showHistory === false">
<jobsview-component></jobsview-component> <jobsview-component></jobsview-component>
</div> </div>
<div id="historyDiv" class="fullsize" *ngIf="showHistory === true"> <div id="historyDiv" class="fullsize" *ngIf="showHistory === true">
<jobhistory-component></jobhistory-component> <jobhistory-component></jobhistory-component>
</div> </div>
</ng-template> </ng-template>
</tab> </tab>
</panel> <tab [title]="alertsComponentTitle" class="fullsize" [identifier]="alertsTabIdentifier"
[iconClass]="alertsIconClass">
<ng-template>
<div id="alertsDiv" class="fullsize">
<jobalertsview-component></jobalertsview-component>
</div>
</ng-template>
</tab>
<tab [title]="operatorsComponentTitle" class="fullsize" [identifier]="operatorsTabIdentifier"
[iconClass]="operatorsIconClass">
<ng-template>
<div id="operatorsDiv" class="fullsize">
<joboperatorsview-component></joboperatorsview-component>
</div>
</ng-template>
</tab>
<tab [title]="proxiesComponentTitle" class="fullsize" [identifier]="proxiesTabIdentifier"
[iconClass]="proxiesIconClass">
<ng-template>
<div id="proxiesDiv" class="fullsize">
<jobproxiesview-component></jobproxiesview-component>
</div>
</ng-template>
</tab>
</panel>
</div>

View File

@@ -33,6 +33,10 @@ export class AgentViewComponent {
// tslint:disable:no-unused-variable // tslint:disable:no-unused-variable
private readonly jobsComponentTitle: string = nls.localize('jobview.Jobs', "Jobs"); private readonly jobsComponentTitle: string = nls.localize('jobview.Jobs', "Jobs");
private readonly alertsComponentTitle: string = nls.localize('jobview.Alerts', "Alerts");
private readonly proxiesComponentTitle: string = nls.localize('jobview.Proxies', "Proxies");
private readonly operatorsComponentTitle: string = nls.localize('jobview.Operators', "Operators");
private _showHistory: boolean = false; private _showHistory: boolean = false;
private _jobId: string = null; private _jobId: string = null;
private _agentJobInfo: AgentJobInfo = null; private _agentJobInfo: AgentJobInfo = null;
@@ -40,6 +44,9 @@ export class AgentViewComponent {
private _expanded: Map<string, string>; private _expanded: Map<string, string>;
public jobsIconClass: string = 'jobsview-icon'; public jobsIconClass: string = 'jobsview-icon';
public alertsIconClass: string = 'alertsview-icon';
public proxiesIconClass: string = 'proxiesview-icon';
public operatorsIconClass: string = 'operatorsview-icon';
// tslint:disable-next-line:no-unused-variable // tslint:disable-next-line:no-unused-variable
private readonly panelOpt: IPanelOptions = { private readonly panelOpt: IPanelOptions = {

View File

@@ -7,7 +7,6 @@
import * as sqlops from 'sqlops'; import * as sqlops from 'sqlops';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Table } from 'sql/base/browser/ui/table/table';
import { JobCacheObject } from './jobManagementService'; import { JobCacheObject } from './jobManagementService';
export const SERVICE_ID = 'jobManagementService'; export const SERVICE_ID = 'jobManagementService';
@@ -21,6 +20,12 @@ export interface IJobManagementService {
getJobs(connectionUri: string): Thenable<sqlops.AgentJobsResult>; getJobs(connectionUri: string): Thenable<sqlops.AgentJobsResult>;
getAlerts(connectionUri: string): Thenable<sqlops.AgentAlertsResult>;
getOperators(connectionUri: string): Thenable<sqlops.AgentOperatorsResult>;
getProxies(connectionUri: string): Thenable<sqlops.AgentProxiesResult>;
getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult>; getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult>;
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus>; jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus>;

View File

@@ -29,6 +29,25 @@ export class JobManagementService implements IJobManagementService {
}); });
} }
public getAlerts(connectionUri: string): Thenable<sqlops.AgentAlertsResult> {
return this._runAction(connectionUri, (runner) => {
return runner.getAlerts(connectionUri);
});
}
public getOperators(connectionUri: string): Thenable<sqlops.AgentOperatorsResult> {
return this._runAction(connectionUri, (runner) => {
return runner.getOperators(connectionUri);
});
}
public getProxies(connectionUri: string): Thenable<sqlops.AgentProxiesResult> {
return this._runAction(connectionUri, (runner) => {
return runner.getProxies(connectionUri);
});
}
public getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> { public getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> {
return this._runAction(connectionUri, (runner) => { return this._runAction(connectionUri, (runner) => {
return runner.getJobHistory(connectionUri, jobID); return runner.getJobHistory(connectionUri, jobID);

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#212121;}</style></defs><title>blocker</title><polygon class="cls-1" points="0.99 3.99 -0.01 3.99 -0.01 0.03 3.98 0.03 3.98 1.03 0.99 1.03 0.99 3.99"/><polygon class="cls-1" points="16.01 3.99 15.01 3.99 15.01 1.03 12.02 1.03 12.02 0.03 16.01 0.03 16.01 3.99"/><polygon class="cls-1" points="16.01 15.97 12.02 15.97 12.02 14.97 15.01 14.97 15.01 12.01 16.01 12.01 16.01 15.97"/><polygon class="cls-1" points="4 15.97 0.01 15.97 0.01 12.01 1.01 12.01 1.01 14.97 4 14.97 4 15.97"/><path class="cls-1" d="M8.41,3.18A4.82,4.82,0,1,0,13.23,8,4.83,4.83,0,0,0,8.41,3.18Zm0,.74A4.08,4.08,0,0,1,12.49,8a4,4,0,0,1-.85,2.47L5.69,5A4,4,0,0,1,8.41,3.93Zm0,8.15A4.08,4.08,0,0,1,4.34,8a4,4,0,0,1,.85-2.47L11.14,11A4,4,0,0,1,8.41,12.07Z"/></svg>

After

Width:  |  Height:  |  Size: 847 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>blocker_inverse</title><polygon class="cls-1" points="0.99 3.99 -0.01 3.99 -0.01 0.03 3.98 0.03 3.98 1.03 0.99 1.03 0.99 3.99"/><polygon class="cls-1" points="16.01 3.99 15.01 3.99 15.01 1.03 12.02 1.03 12.02 0.03 16.01 0.03 16.01 3.99"/><polygon class="cls-1" points="16.01 15.97 12.02 15.97 12.02 14.97 15.01 14.97 15.01 12.01 16.01 12.01 16.01 15.97"/><polygon class="cls-1" points="4 15.97 0.01 15.97 0.01 12.01 1.01 12.01 1.01 14.97 4 14.97 4 15.97"/><path class="cls-1" d="M8.41,3.18A4.82,4.82,0,1,0,13.23,8,4.83,4.83,0,0,0,8.41,3.18Zm0,.74A4.08,4.08,0,0,1,12.49,8a4,4,0,0,1-.85,2.47L5.69,5A4,4,0,0,1,8.41,3.93Zm0,8.15A4.08,4.08,0,0,1,4.34,8a4,4,0,0,1,.85-2.47L11.14,11A4,4,0,0,1,8.41,12.07Z"/></svg>

After

Width:  |  Height:  |  Size: 852 B

View File

@@ -31,7 +31,7 @@ jobhistory-component {
border-bottom: 3px solid #444444; border-bottom: 3px solid #444444;
} }
#jobsDiv .jobview-grid { .jobview-grid {
height: 94.7%; height: 94.7%;
width : 100%; width : 100%;
display: block; display: block;
@@ -49,6 +49,18 @@ jobhistory-component {
font-size: larger; font-size: larger;
} }
.vs-dark #agentViewDiv .slick-header-column {
background: #333333 !important;
}
#agentViewDiv .slick-header-column {
background-color: transparent !important;
background: white !important;
border: 0px !important;
font-weight: bold;
font-size: larger;
}
.vs-dark #jobsDiv jobsview-component .jobview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell { .vs-dark #jobsDiv jobsview-component .jobview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
background:#333333; background:#333333;
} }
@@ -107,14 +119,14 @@ jobhistory-component {
border-bottom: none; border-bottom: none;
} }
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell.l1.r1.error-row { .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell.l1.r1.error-row {
width: 100%; width: 100%;
opacity: 1; opacity: 1;
font-weight: 700; font-weight: 700;
color: orangered; color: orangered;
} }
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell._detail_selector.error-row { .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell._detail_selector.error-row {
opacity: 1; opacity: 1;
} }
@@ -178,6 +190,30 @@ jobhistory-component {
background-image: url('./job_inverse.svg'); background-image: url('./job_inverse.svg');
} }
.alertsview-icon {
background-image: url('./alert.svg');
}
.vs-dark .alertsview-icon {
background-image: url('./alert_inverse.svg');
}
.proxiesview-icon {
background-image: url('./proxy.svg');
}
.vs-dark .proxiesview-icon {
background-image: url('./proxy_inverse.svg');
}
.operatorsview-icon {
background-image: url('./operator.svg');
}
.vs-dark .operatorsview-icon {
background-image: url('./operator_inverse.svg');
}
agentview-component .jobview-grid .grid-canvas > .ui-widget-content.slick-row.even > .slick-cell, agentview-component .jobview-grid .grid-canvas > .ui-widget-content.slick-row.even > .slick-cell,
agentview-component .jobview-grid .grid-canvas > .ui-widget-content.slick-row.odd > .slick-cell { agentview-component .jobview-grid .grid-canvas > .ui-widget-content.slick-row.odd > .slick-cell {
cursor: pointer; cursor: pointer;
@@ -259,4 +295,23 @@ table.jobprevruns > tbody {
.jobs-view-toolbar span{ .jobs-view-toolbar span{
padding-left: 5px; padding-left: 5px;
} }
#alertsDiv .jobalertsview-grid {
height: 94.7%;
width : 100%;
display: block;
}
#operatorsDiv .joboperatorsview-grid {
height: 94.7%;
width : 100%;
display: block;
}
#proxiesDiv .jobproxiesview-grid {
height: 94.7%;
width : 100%;
display: block;
}

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>security</title><path d="M6,8a4.88,4.88,0,0,0-1.33.18,5.11,5.11,0,0,0-1.2.5,5,5,0,0,0-1.79,1.79,5.11,5.11,0,0,0-.5,1.2A4.88,4.88,0,0,0,1,13H0a5.9,5.9,0,0,1,.28-1.79,6.12,6.12,0,0,1,2-2.94,5.33,5.33,0,0,1,1.58-.88,4.18,4.18,0,0,1-.79-.65,4,4,0,0,1-.59-.8A4.05,4.05,0,0,1,2.13,5a4,4,0,0,1,.18-2.57A4,4,0,0,1,4.44.31a4,4,0,0,1,3.12,0A4,4,0,0,1,9.69,2.44,4,4,0,0,1,9.87,5a4.05,4.05,0,0,1-.37.93,4,4,0,0,1-.59.8,4.18,4.18,0,0,1-.79.65,6.14,6.14,0,0,1,1,.5,5.73,5.73,0,0,1,.91.69l-.68.74a5,5,0,0,0-1.57-1A4.93,4.93,0,0,0,6,8ZM3,4a2.92,2.92,0,0,0,.23,1.17,3,3,0,0,0,1.6,1.6,3,3,0,0,0,2.33,0,3,3,0,0,0,1.6-1.6,3,3,0,0,0,0-2.33,3,3,0,0,0-1.6-1.6,3,3,0,0,0-2.33,0,3,3,0,0,0-1.6,1.6A2.92,2.92,0,0,0,3,4Zm12,8a2.45,2.45,0,0,1,0,1l1,.4-.38.93-1-.41a2.59,2.59,0,0,1-.67.67l.41,1-.93.38L13,15a2.45,2.45,0,0,1-1,0l-.4,1-.93-.38.41-1a2.59,2.59,0,0,1-.67-.67l-1,.41-.38-.93,1-.4a2.45,2.45,0,0,1,0-1l-1-.4.38-.93,1,.41a2.59,2.59,0,0,1,.67-.67l-.41-1,.93-.38.4,1a2.45,2.45,0,0,1,1,0l.4-1,.93.38-.41,1a2.59,2.59,0,0,1,.67.67l1-.41.38.93ZM12.5,14a1.47,1.47,0,0,0,.59-.12,1.49,1.49,0,0,0,.8-.8,1.52,1.52,0,0,0,0-1.17,1.49,1.49,0,0,0-.8-.8,1.52,1.52,0,0,0-1.17,0,1.49,1.49,0,0,0-.8.8,1.52,1.52,0,0,0,0,1.17,1.49,1.49,0,0,0,.8.8A1.47,1.47,0,0,0,12.5,14Z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>security_inverse</title><path class="cls-1" d="M6,8a4.88,4.88,0,0,0-1.33.18,5.11,5.11,0,0,0-1.2.5,5,5,0,0,0-1.79,1.79,5.11,5.11,0,0,0-.5,1.2A4.88,4.88,0,0,0,1,13H0a5.9,5.9,0,0,1,.28-1.79,6.12,6.12,0,0,1,2-2.94,5.33,5.33,0,0,1,1.58-.88,4.18,4.18,0,0,1-.79-.65,4,4,0,0,1-.59-.8A4.05,4.05,0,0,1,2.13,5a4,4,0,0,1,.18-2.57A4,4,0,0,1,4.44.31a4,4,0,0,1,3.12,0A4,4,0,0,1,9.69,2.44,4,4,0,0,1,9.87,5a4.05,4.05,0,0,1-.37.93,4,4,0,0,1-.59.8,4.18,4.18,0,0,1-.79.65,6.14,6.14,0,0,1,1,.5,5.73,5.73,0,0,1,.91.69l-.68.74a5,5,0,0,0-1.57-1A4.93,4.93,0,0,0,6,8ZM3,4a2.92,2.92,0,0,0,.23,1.17,3,3,0,0,0,1.6,1.6,3,3,0,0,0,2.33,0,3,3,0,0,0,1.6-1.6,3,3,0,0,0,0-2.33,3,3,0,0,0-1.6-1.6,3,3,0,0,0-2.33,0,3,3,0,0,0-1.6,1.6A2.92,2.92,0,0,0,3,4Zm12,8a2.45,2.45,0,0,1,0,1l1,.4-.38.93-1-.41a2.59,2.59,0,0,1-.67.67l.41,1-.93.38L13,15a2.45,2.45,0,0,1-1,0l-.4,1-.93-.38.41-1a2.59,2.59,0,0,1-.67-.67l-1,.41-.38-.93,1-.4a2.45,2.45,0,0,1,0-1l-1-.4.38-.93,1,.41a2.59,2.59,0,0,1,.67-.67l-.41-1,.93-.38.4,1a2.45,2.45,0,0,1,1,0l.4-1,.93.38-.41,1a2.59,2.59,0,0,1,.67.67l1-.41.38.93ZM12.5,14a1.47,1.47,0,0,0,.59-.12,1.49,1.49,0,0,0,.8-.8,1.52,1.52,0,0,0,0-1.17,1.49,1.49,0,0,0-.8-.8,1.52,1.52,0,0,0-1.17,0,1.49,1.49,0,0,0-.8.8,1.52,1.52,0,0,0,0,1.17,1.49,1.49,0,0,0,.8.8A1.47,1.47,0,0,0,12.5,14Z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#101e23;}.cls-2{fill:#4bb8d1;}.cls-3{fill:#0c1011;}</style></defs><title>health</title><path class="cls-1" d="M12.58,1.51A6.36,6.36,0,0,0,8,3.9,6.32,6.32,0,0,0,3.41,1.51,3.81,3.81,0,0,0,0,5.35,5.7,5.7,0,0,0,.64,7.88h.72l0-.08A5.18,5.18,0,0,1,.64,5.39c.07-1.25.87-3.14,2.8-3.23h.12A5.81,5.81,0,0,1,7.73,4.63L8,5.06l.27-.43a5.72,5.72,0,0,1,4.28-2.47c1.93.09,2.73,2,2.8,3.23a5.15,5.15,0,0,1-.64,2.34l0,0a2.38,2.38,0,0,1-.34.68,19.45,19.45,0,0,1-6.57,6.06,11.11,11.11,0,0,1-1.25-.81c-.34-.25-.66-.52-1-.8h0a22.83,22.83,0,0,1-2.76-3H2a18.68,18.68,0,0,0,5.76,5.29h0l0,0h0c3.49-1.63,7-5.73,7.49-7.18V8A5.85,5.85,0,0,0,16,5.35,3.81,3.81,0,0,0,12.58,1.51Z"/><path class="cls-1" d="M1.41,8l-.1-.15h0Z"/><path class="cls-1" d="M7.79,15.22v0h0Z"/><path class="cls-1" d="M7.76,15.23h0v0Z"/><path class="cls-1" d="M14.72,7.73l0,0a.13.13,0,0,0,0,0Z"/><path class="cls-2" d="M12.62,8.7v.12a.48.48,0,0,1-.48.48H8.66l0,.07L7.38,12.65h0A.72.72,0,0,1,6,12.53V9.44H6V6.6L5,9.05H5a.56.56,0,0,1-.52.37H.92V8.36H4.13l0-.07L5.41,5h0a.72.72,0,0,1,1.42.12V8.22h0v2.84L7.77,8.6h0a.56.56,0,0,1,.52-.37h3.84A.48.48,0,0,1,12.62,8.7Z"/><path class="cls-3" d="M12.62,8.7v.12a.48.48,0,0,1-.48.48H8.66l0,.07L7.38,12.65h0A.72.72,0,0,1,6,12.53V9.44H6V6.6L5,9.05H5a.56.56,0,0,1-.52.37H.92V8.36H4.13l0-.07L5.41,5h0a.72.72,0,0,1,1.42.12V8.22h0v2.84L7.77,8.6h0a.56.56,0,0,1,.52-.37h3.84A.48.48,0,0,1,12.62,8.7Z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#101e23;}.cls-3{fill:#4bb8d1;}</style></defs><title>health_inverse</title><path class="cls-1" d="M12.58,1.51A6.36,6.36,0,0,0,8,3.9,6.32,6.32,0,0,0,3.41,1.51,3.81,3.81,0,0,0,0,5.35,5.7,5.7,0,0,0,.64,7.88h.72l0-.08A5.18,5.18,0,0,1,.64,5.39c.07-1.25.87-3.14,2.8-3.23h.12A5.81,5.81,0,0,1,7.73,4.63L8,5.06l.27-.43a5.72,5.72,0,0,1,4.28-2.47c1.93.09,2.73,2,2.8,3.23a5.15,5.15,0,0,1-.64,2.34l0,0a2.38,2.38,0,0,1-.34.68,19.45,19.45,0,0,1-6.57,6.06,11.11,11.11,0,0,1-1.25-.81c-.34-.25-.66-.52-1-.8h0a22.83,22.83,0,0,1-2.76-3H2a18.68,18.68,0,0,0,5.76,5.29h0l0,0h0c3.49-1.63,7-5.73,7.49-7.18V8A5.85,5.85,0,0,0,16,5.35,3.81,3.81,0,0,0,12.58,1.51Z"/><path class="cls-2" d="M1.41,8l-.1-.15h0Z"/><path class="cls-2" d="M7.79,15.22v0h0Z"/><path class="cls-2" d="M7.76,15.23h0v0Z"/><path class="cls-2" d="M14.72,7.73l0,0a.13.13,0,0,0,0,0Z"/><path class="cls-3" d="M12.62,8.7v.12a.48.48,0,0,1-.48.48H8.66l0,.07L7.38,12.65h0A.72.72,0,0,1,6,12.53V9.44H6V6.6L5,9.05H5a.56.56,0,0,1-.52.37H.92V8.36H4.13l0-.07L5.41,5h0a.72.72,0,0,1,1.42.12V8.22h0v2.84L7.77,8.6h0a.56.56,0,0,1,.52-.37h3.84A.48.48,0,0,1,12.62,8.7Z"/><path class="cls-1" d="M12.62,8.7v.12a.48.48,0,0,1-.48.48H8.66l0,.07L7.38,12.65h0A.72.72,0,0,1,6,12.53V9.44H6V6.6L5,9.05H5a.56.56,0,0,1-.52.37H.92V8.36H4.13l0-.07L5.41,5h0a.72.72,0,0,1,1.42.12V8.22h0v2.84L7.77,8.6h0a.56.56,0,0,1,.52-.37h3.84A.48.48,0,0,1,12.62,8.7Z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

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

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

@@ -1211,6 +1211,7 @@ declare module 'sqlops' {
export interface AgentAlertInfo { export interface AgentAlertInfo {
id: number; id: number;
name: string;
delayBetweenResponses: number; delayBetweenResponses: number;
eventDescriptionKeyword: string; eventDescriptionKeyword: string;
eventSource: string; eventSource: string;
@@ -1327,15 +1328,15 @@ declare module 'sqlops' {
} }
export interface AgentProxiesResult extends ResultStatus { export interface AgentProxiesResult extends ResultStatus {
operators: AgentOperatorInfo[]; proxies: AgentProxyInfo[];
} }
export interface CreateAgentProxyResult extends ResultStatus { export interface CreateAgentProxyResult extends ResultStatus {
operator: AgentOperatorInfo; proxy: AgentProxyInfo;
} }
export interface UpdateAgentProxyResult extends ResultStatus { export interface UpdateAgentProxyResult extends ResultStatus {
operator: AgentOperatorInfo; proxy: AgentProxyInfo;
} }
export interface AgentJobSchedulesResult extends ResultStatus { export interface AgentJobSchedulesResult extends ResultStatus {

View File

@@ -554,4 +554,25 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
public $jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> { public $jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> {
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).jobAction(ownerUri, jobName, action); return this._resolveProvider<sqlops.AgentServicesProvider>(handle).jobAction(ownerUri, jobName, action);
} }
/**
* Get Agent Alerts list
*/
$getAlerts(handle: number, ownerUri: string): Thenable<sqlops.AgentAlertsResult> {
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).getAlerts(ownerUri);
}
/**
* Get Agent Oeprators list
*/
$getOperators(handle: number, ownerUri: string): Thenable<sqlops.AgentOperatorsResult> {
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).getOperators(ownerUri);
}
/**
* Get Agent Proxies list
*/
$getProxies(handle: number, ownerUri: string): Thenable<sqlops.AgentProxiesResult> {
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).getProxies(ownerUri);
}
} }

View File

@@ -344,6 +344,15 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
}, },
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> { jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> {
return self._proxy.$jobAction(handle, connectionUri, jobName, action); return self._proxy.$jobAction(handle, connectionUri, jobName, action);
},
getAlerts(connectionUri: string): Thenable<sqlops.AgentAlertsResult> {
return self._proxy.$getAlerts(handle, connectionUri);
},
getOperators(connectionUri: string): Thenable<sqlops.AgentOperatorsResult> {
return self._proxy.$getOperators(handle, connectionUri);
},
getProxies(connectionUri: string): Thenable<sqlops.AgentProxiesResult> {
return self._proxy.$getProxies(handle, connectionUri);
} }
}); });

View File

@@ -337,6 +337,21 @@ export abstract class ExtHostDataProtocolShape {
* Run an action on a Job * Run an action on a Job
*/ */
$jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> { throw ni(); } $jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> { throw ni(); }
/**
* Get Agent Alerts list
*/
$getAlerts(handle: number, connectionUri: string): Thenable<sqlops.AgentAlertsResult> { throw ni(); }
/**
* Get Agent Oeprators list
*/
$getOperators(handle: number, connectionUri: string): Thenable<sqlops.AgentOperatorsResult> { throw ni(); }
/**
* Get Agent Proxies list
*/
$getProxies(handle: number, connectionUri: string): Thenable<sqlops.AgentProxiesResult> { throw ni(); }
} }
/** /**