From 21bad7a01f12e52bdba41ef65225055ffbd2b2a4 Mon Sep 17 00:00:00 2001 From: Karl Burtram Date: Fri, 6 Jul 2018 08:57:30 -0700 Subject: [PATCH] Refresh agent dashboard panel after create\update\delete operations (#1861) * Edit alert WIP * A couple alert edit bugs * Hook up dashboard refresh notification * Hook onchange event to other agent service calls * Switch update handler to scalar value * Add null check on handler callback --- extensions/agent/src/data/alertData.ts | 48 ++++++- extensions/agent/src/data/jobData.ts | 3 +- extensions/agent/src/data/jobStepData.ts | 3 +- extensions/agent/src/data/operatorData.ts | 3 +- extensions/agent/src/data/pickScheduleData.ts | 3 +- extensions/agent/src/data/proxyData.ts | 3 +- extensions/agent/src/data/scheduleData.ts | 3 +- extensions/agent/src/dialogs/agentDialog.ts | 10 +- extensions/agent/src/dialogs/alertDialog.ts | 125 +++++++++--------- .../agent/src/dialogs/operatorDialog.ts | 6 +- extensions/agent/src/interfaces.ts | 7 + extensions/agent/src/mainController.ts | 5 +- extensions/agent/src/test/testAgentService.ts | 3 + extensions/mssql/src/features.ts | 107 ++++++++++++--- .../agent/agentView.component.ts | 10 +- .../parts/jobManagement/common/interfaces.ts | 3 + .../parts/jobManagement/common/jobActions.ts | 8 +- .../common/jobManagementService.ts | 9 +- .../views/alertsView.component.ts | 2 +- .../views/proxiesView.component.ts | 2 +- src/sql/sqlops.d.ts | 3 +- .../workbench/api/node/extHostDataProtocol.ts | 7 + .../api/node/mainThreadDataProtocol.ts | 5 + .../workbench/api/node/sqlExtHost.api.impl.ts | 4 + .../workbench/api/node/sqlExtHost.protocol.ts | 1 + 25 files changed, 280 insertions(+), 103 deletions(-) diff --git a/extensions/agent/src/data/alertData.ts b/extensions/agent/src/data/alertData.ts index f2a4807ca7..ad32aadd44 100644 --- a/extensions/agent/src/data/alertData.ts +++ b/extensions/agent/src/data/alertData.ts @@ -4,14 +4,20 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import * as nls from 'vscode-nls'; +import * as vscode from 'vscode'; import * as sqlops from 'sqlops'; import { AgentUtils } from '../agentUtils'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; + +const localize = nls.loadMessageBundle(); export class AlertData implements IAgentDialogData { ownerUri: string; + dialogMode: AgentDialogMode = AgentDialogMode.CREATE; id: number; name: string; + originalName: string; delayBetweenResponses: number; eventDescriptionKeyword: string; eventSource: string; @@ -34,8 +40,36 @@ export class AlertData implements IAgentDialogData { wmiEventNamespace: string; wmiEventQuery: string; - constructor(ownerUri:string) { + constructor(ownerUri:string, alertInfo: sqlops.AgentAlertInfo) { this.ownerUri = ownerUri; + + if (alertInfo) { + this.dialogMode = AgentDialogMode.EDIT; + this.id = alertInfo.id; + this.name = alertInfo.name; + this.originalName = alertInfo.name; + this.delayBetweenResponses = alertInfo.delayBetweenResponses; + this.eventDescriptionKeyword = alertInfo.eventDescriptionKeyword; + this.eventSource = alertInfo.eventSource; + this.hasNotification = alertInfo.hasNotification; + this.includeEventDescription = alertInfo.includeEventDescription.toString(); + this.isEnabled = alertInfo.isEnabled; + this.jobId = alertInfo.jobId; + this.jobName = alertInfo.jobName; + this.lastOccurrenceDate = alertInfo.lastOccurrenceDate; + this.lastResponseDate = alertInfo.lastResponseDate; + this.messageId = alertInfo.messageId; + this.notificationMessage = alertInfo.notificationMessage; + this.occurrenceCount = alertInfo.occurrenceCount; + this.performanceCondition = alertInfo.performanceCondition; + this.severity = alertInfo.severity; + this.databaseName = alertInfo.databaseName; + this.countResetDate = alertInfo.countResetDate; + this.categoryName = alertInfo.categoryName; + this.alertType = alertInfo.alertType.toString(); + this.wmiEventNamespace = alertInfo.wmiEventNamespace; + this.wmiEventQuery = alertInfo.wmiEventQuery; + } } public async initialize() { @@ -43,9 +77,13 @@ export class AlertData implements IAgentDialogData { public async save() { let agentService = await AgentUtils.getAgentService(); - let result = await agentService.createAlert(this.ownerUri, this.toAgentAlertInfo()); + let result = this.dialogMode === AgentDialogMode.CREATE + ? await agentService.createAlert(this.ownerUri, this.toAgentAlertInfo()) + : await agentService.updateAlert(this.ownerUri, this.originalName, this.toAgentAlertInfo()); + if (!result || !result.success) { - // TODO handle error here + vscode.window.showErrorMessage( + localize('alertData.saveErrorMessage', "Alert update failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown')); } } @@ -76,4 +114,4 @@ export class AlertData implements IAgentDialogData { wmiEventQuery: this.wmiEventQuery }; } -} +} \ No newline at end of file diff --git a/extensions/agent/src/data/jobData.ts b/extensions/agent/src/data/jobData.ts index f8291a153d..3de9daccd3 100644 --- a/extensions/agent/src/data/jobData.ts +++ b/extensions/agent/src/data/jobData.ts @@ -6,7 +6,7 @@ import * as sqlops from 'sqlops'; import { AgentUtils } from '../agentUtils'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; export class JobData implements IAgentDialogData { @@ -23,6 +23,7 @@ export class JobData implements IAgentDialogData { private _defaultOwner: string; private _jobCompletionActionConditions: sqlops.CategoryValue[]; + public dialogMode: AgentDialogMode = AgentDialogMode.CREATE; public name: string; public enabled: boolean = true; public description: string; diff --git a/extensions/agent/src/data/jobStepData.ts b/extensions/agent/src/data/jobStepData.ts index 6631a6bca1..e11ec015c8 100644 --- a/extensions/agent/src/data/jobStepData.ts +++ b/extensions/agent/src/data/jobStepData.ts @@ -5,9 +5,10 @@ 'use strict'; import { AgentUtils } from '../agentUtils'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; export class JobStepData implements IAgentDialogData { + public dialogMode: AgentDialogMode = AgentDialogMode.CREATE; public ownerUri: string; public jobId: string; // public jobName: string; diff --git a/extensions/agent/src/data/operatorData.ts b/extensions/agent/src/data/operatorData.ts index e39044618a..da3392e1cc 100644 --- a/extensions/agent/src/data/operatorData.ts +++ b/extensions/agent/src/data/operatorData.ts @@ -6,9 +6,10 @@ import * as sqlops from 'sqlops'; import { AgentUtils } from '../agentUtils'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; export class OperatorData implements IAgentDialogData { + public dialogMode: AgentDialogMode = AgentDialogMode.CREATE; ownerUri: string; name: string; id: number; diff --git a/extensions/agent/src/data/pickScheduleData.ts b/extensions/agent/src/data/pickScheduleData.ts index cf867fa7ac..0192aa3176 100644 --- a/extensions/agent/src/data/pickScheduleData.ts +++ b/extensions/agent/src/data/pickScheduleData.ts @@ -6,9 +6,10 @@ import * as sqlops from 'sqlops'; import { AgentUtils } from '../agentUtils'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; export class PickScheduleData implements IAgentDialogData { + public dialogMode: AgentDialogMode = AgentDialogMode.VIEW; public ownerUri: string; public schedules: sqlops.AgentJobScheduleInfo[]; public selectedSchedule: sqlops.AgentJobScheduleInfo; diff --git a/extensions/agent/src/data/proxyData.ts b/extensions/agent/src/data/proxyData.ts index f29b96c689..52f22fab95 100644 --- a/extensions/agent/src/data/proxyData.ts +++ b/extensions/agent/src/data/proxyData.ts @@ -6,9 +6,10 @@ import * as sqlops from 'sqlops'; import { AgentUtils } from '../agentUtils'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; export class ProxyData implements IAgentDialogData { + public dialogMode: AgentDialogMode = AgentDialogMode.CREATE; ownerUri: string; id: number; accountName: string; diff --git a/extensions/agent/src/data/scheduleData.ts b/extensions/agent/src/data/scheduleData.ts index a1237b3d11..bd9a4c6e85 100644 --- a/extensions/agent/src/data/scheduleData.ts +++ b/extensions/agent/src/data/scheduleData.ts @@ -6,9 +6,10 @@ import * as sqlops from 'sqlops'; import { AgentUtils } from '../agentUtils'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; export class ScheduleData implements IAgentDialogData { + public dialogMode: AgentDialogMode = AgentDialogMode.CREATE; public ownerUri: string; public schedules: sqlops.AgentJobScheduleInfo[]; public selectedSchedule: sqlops.AgentJobScheduleInfo; diff --git a/extensions/agent/src/dialogs/agentDialog.ts b/extensions/agent/src/dialogs/agentDialog.ts index 67a2133786..fa2c1cea85 100644 --- a/extensions/agent/src/dialogs/agentDialog.ts +++ b/extensions/agent/src/dialogs/agentDialog.ts @@ -7,14 +7,14 @@ import * as nls from 'vscode-nls'; import * as sqlops from 'sqlops'; import * as vscode from 'vscode'; -import { IAgentDialogData } from '../interfaces'; +import { IAgentDialogData, AgentDialogMode } from '../interfaces'; const localize = nls.loadMessageBundle(); export abstract class AgentDialog { - private static readonly OkButtonText: string = localize('createAlert.OK', 'OK'); - private static readonly CancelButtonText: string = localize('createAlert.Cancel', 'Cancel'); + private static readonly OkButtonText: string = localize('agentDialog.OK', 'OK'); + private static readonly CancelButtonText: string = localize('agentDialog.Cancel', 'Cancel'); protected _onSuccess: vscode.EventEmitter = new vscode.EventEmitter(); public readonly onSuccess: vscode.Event = this._onSuccess.event; @@ -23,6 +23,10 @@ export abstract class AgentDialog { constructor(public ownerUri: string, public model: T, public title: string) { } + public get dialogMode(): AgentDialogMode { + return this.model.dialogMode; + } + protected abstract async updateModel(); protected abstract async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog); diff --git a/extensions/agent/src/dialogs/alertDialog.ts b/extensions/agent/src/dialogs/alertDialog.ts index b5f860fc91..accce97d19 100644 --- a/extensions/agent/src/dialogs/alertDialog.ts +++ b/extensions/agent/src/dialogs/alertDialog.ts @@ -16,48 +16,49 @@ const localize = nls.loadMessageBundle(); export class AlertDialog extends AgentDialog { // Top level - private static readonly DialogTitle: string = localize('createAlert.createAlert', 'Create Alert'); - private static readonly GeneralTabText: string = localize('createAlert.General', 'General'); - private static readonly ResponseTabText: string = localize('createAlert.Response', 'Response'); - private static readonly OptionsTabText: string = localize('createAlert.Options', 'Options'); + private static readonly CreateDialogTitle: string = localize('alertDialog.createAlert', 'Create Alert'); + private static readonly EditDialogTitle: string = localize('alertDialog.editAlert', 'Edit Alert'); + private static readonly GeneralTabText: string = localize('alertDialog.General', 'General'); + private static readonly ResponseTabText: string = localize('alertDialog.Response', 'Response'); + private static readonly OptionsTabText: string = localize('alertDialog.Options', 'Options'); // General tab strings - private static readonly NameLabel: string = localize('createAlert.Name', 'Name'); - private static readonly TypeLabel: string = localize('createAlert.Type', 'Type'); - private static readonly EnabledCheckboxLabel: string = localize('createAlert.Enabled', 'Enabled'); - private static readonly DatabaseLabel: string = localize('createAlert.DatabaseName', 'Database name'); - private static readonly ErrorNumberLabel: string = localize('createAlert.ErrorNumber', 'Error number'); - private static readonly SeverityLabel: string = localize('createAlert.Severity', 'Severity'); - private static readonly RaiseIfMessageContainsLabel: string = localize('createAlert.RaiseAlertContains', 'Raise alert when message contains'); - private static readonly MessageTextLabel: string = localize('createAlert.MessageText', 'Message text'); - private static readonly AlertTypeSqlServerEventString: string = localize('createAlert.SqlServerEventAlert', 'SQL Server event alert'); - private static readonly AlertTypePerformanceConditionString: string = localize('createAlert.PerformanceCondition', 'SQL Server performance condition alert'); - private static readonly AlertTypeWmiEventString: string = localize('createAlert.WmiEvent', 'WMI event alert'); - private static readonly AlertSeverity001Label: string = localize('createAlert.Severity001', '001 - Miscellaneous System Information'); - private static readonly AlertSeverity002Label: string = localize('createAlert.Severity002', '002 - Reserved'); - private static readonly AlertSeverity003Label: string = localize('createAlert.Severity003', '003 - Reserved'); - private static readonly AlertSeverity004Label: string = localize('createAlert.Severity004', '004 - Reserved'); - private static readonly AlertSeverity005Label: string = localize('createAlert.Severity005', '005 - Reserved'); - private static readonly AlertSeverity006Label: string = localize('createAlert.Severity006', '006 - Reserved'); - private static readonly AlertSeverity007Label: string = localize('createAlert.Severity007', '007 - Notification: Status Information'); - private static readonly AlertSeverity008Label: string = localize('createAlert.Severity008', '008 - Notification: User Intervention Required'); - private static readonly AlertSeverity009Label: string = localize('createAlert.Severity009', '009 - User Defined'); - private static readonly AlertSeverity010Label: string = localize('createAlert.Severity010', '010 - Information'); - private static readonly AlertSeverity011Label: string = localize('createAlert.Severity011', '011 - Specified Database Object Not Found'); - private static readonly AlertSeverity012Label: string = localize('createAlert.Severity012', '012 - Unused'); - private static readonly AlertSeverity013Label: string = localize('createAlert.Severity013', '013 - User Transaction Syntax Error'); - private static readonly AlertSeverity014Label: string = localize('createAlert.Severity014', '014 - Insufficient Permission'); - private static readonly AlertSeverity015Label: string = localize('createAlert.Severity015', '015 - Syntax Error in SQL Statements'); - private static readonly AlertSeverity016Label: string = localize('createAlert.Severity016', '016 - Miscellaneous User Error'); - private static readonly AlertSeverity017Label: string = localize('createAlert.Severity017', '017 - Insufficient Resources'); - private static readonly AlertSeverity018Label: string = localize('createAlert.Severity018', '018 - Nonfatal Internal Error'); - private static readonly AlertSeverity019Label: string = localize('createAlert.Severity019', '019 - Fatal Error in Resource'); - private static readonly AlertSeverity020Label: string = localize('createAlert.Severity020', '020 - Fatal Error in Current Process'); - private static readonly AlertSeverity021Label: string = localize('createAlert.Severity021', '021 - Fatal Error in Database Processes'); - private static readonly AlertSeverity022Label: string = localize('createAlert.Severity022', '022 - Fatal Error: Table Integrity Suspect'); - private static readonly AlertSeverity023Label: string = localize('createAlert.Severity023', '023 - Fatal Error: Database Integrity Suspect'); - private static readonly AlertSeverity024Label: string = localize('createAlert.Severity024', '024 - Fatal Error: Hardware Error'); - private static readonly AlertSeverity025Label: string = localize('createAlert.Severity025', '025 - Fatal Error'); + private static readonly NameLabel: string = localize('alertDialog.Name', 'Name'); + private static readonly TypeLabel: string = localize('alertDialog.Type', 'Type'); + private static readonly EnabledCheckboxLabel: string = localize('alertDialog.Enabled', 'Enabled'); + private static readonly DatabaseLabel: string = localize('alertDialog.DatabaseName', 'Database name'); + private static readonly ErrorNumberLabel: string = localize('alertDialog.ErrorNumber', 'Error number'); + private static readonly SeverityLabel: string = localize('alertDialog.Severity', 'Severity'); + private static readonly RaiseIfMessageContainsLabel: string = localize('alertDialog.RaiseAlertContains', 'Raise alert when message contains'); + private static readonly MessageTextLabel: string = localize('alertDialog.MessageText', 'Message text'); + private static readonly AlertTypeSqlServerEventString: string = localize('alertDialog.SqlServerEventAlert', 'SQL Server event alert'); + private static readonly AlertTypePerformanceConditionString: string = localize('alertDialog.PerformanceCondition', 'SQL Server performance condition alert'); + private static readonly AlertTypeWmiEventString: string = localize('alertDialog.WmiEvent', 'WMI event alert'); + private static readonly AlertSeverity001Label: string = localize('alertDialog.Severity001', '001 - Miscellaneous System Information'); + private static readonly AlertSeverity002Label: string = localize('alertDialog.Severity002', '002 - Reserved'); + private static readonly AlertSeverity003Label: string = localize('alertDialog.Severity003', '003 - Reserved'); + private static readonly AlertSeverity004Label: string = localize('alertDialog.Severity004', '004 - Reserved'); + private static readonly AlertSeverity005Label: string = localize('alertDialog.Severity005', '005 - Reserved'); + private static readonly AlertSeverity006Label: string = localize('alertDialog.Severity006', '006 - Reserved'); + private static readonly AlertSeverity007Label: string = localize('alertDialog.Severity007', '007 - Notification: Status Information'); + private static readonly AlertSeverity008Label: string = localize('alertDialog.Severity008', '008 - Notification: User Intervention Required'); + private static readonly AlertSeverity009Label: string = localize('alertDialog.Severity009', '009 - User Defined'); + private static readonly AlertSeverity010Label: string = localize('alertDialog.Severity010', '010 - Information'); + private static readonly AlertSeverity011Label: string = localize('alertDialog.Severity011', '011 - Specified Database Object Not Found'); + private static readonly AlertSeverity012Label: string = localize('alertDialog.Severity012', '012 - Unused'); + private static readonly AlertSeverity013Label: string = localize('alertDialog.Severity013', '013 - User Transaction Syntax Error'); + private static readonly AlertSeverity014Label: string = localize('alertDialog.Severity014', '014 - Insufficient Permission'); + private static readonly AlertSeverity015Label: string = localize('alertDialog.Severity015', '015 - Syntax Error in SQL Statements'); + private static readonly AlertSeverity016Label: string = localize('alertDialog.Severity016', '016 - Miscellaneous User Error'); + private static readonly AlertSeverity017Label: string = localize('alertDialog.Severity017', '017 - Insufficient Resources'); + private static readonly AlertSeverity018Label: string = localize('alertDialog.Severity018', '018 - Nonfatal Internal Error'); + private static readonly AlertSeverity019Label: string = localize('alertDialog.Severity019', '019 - Fatal Error in Resource'); + private static readonly AlertSeverity020Label: string = localize('alertDialog.Severity020', '020 - Fatal Error in Current Process'); + private static readonly AlertSeverity021Label: string = localize('alertDialog.Severity021', '021 - Fatal Error in Database Processes'); + private static readonly AlertSeverity022Label: string = localize('alertDialog.Severity022', '022 - Fatal Error: Table Integrity Suspect'); + private static readonly AlertSeverity023Label: string = localize('alertDialog.Severity023', '023 - Fatal Error: Database Integrity Suspect'); + private static readonly AlertSeverity024Label: string = localize('alertDialog.Severity024', '024 - Fatal Error: Hardware Error'); + private static readonly AlertSeverity025Label: string = localize('alertDialog.Severity025', '025 - Fatal Error'); private static readonly AlertTypes: string[] = [ AlertDialog.AlertTypeSqlServerEventString, @@ -94,23 +95,23 @@ export class AlertDialog extends AgentDialog { ]; // Response tab strings - private static readonly ExecuteJobCheckBoxLabel: string = localize('createAlert.ExecuteJob', 'Execute Job'); - private static readonly ExecuteJobTextBoxLabel: string = localize('createAlert.ExecuteJobName', 'Job Name'); - private static readonly NotifyOperatorsTextBoxLabel: string = localize('createAlert.NotifyOperators', 'Notify Operators'); - private static readonly NewJobButtonLabel: string = localize('createAlert.NewJob', 'New Job'); - private static readonly OperatorListLabel: string = localize('createAlert.OperatorList', 'Operator List'); - private static readonly OperatorNameColumnLabel: string = localize('createAlert.OperatorName', 'Operator'); - private static readonly OperatorEmailColumnLabel: string = localize('createAlert.OperatorEmail', 'E-mail'); - private static readonly OperatorPagerColumnLabel: string = localize('createAlert.OperatorPager', 'Pager'); - private static readonly NewOperatorButtonLabel: string = localize('createAlert.NewOperator', 'New Operator'); + private static readonly ExecuteJobCheckBoxLabel: string = localize('alertDialog.ExecuteJob', 'Execute Job'); + private static readonly ExecuteJobTextBoxLabel: string = localize('alertDialog.ExecuteJobName', 'Job Name'); + private static readonly NotifyOperatorsTextBoxLabel: string = localize('alertDialog.NotifyOperators', 'Notify Operators'); + private static readonly NewJobButtonLabel: string = localize('alertDialog.NewJob', 'New Job'); + private static readonly OperatorListLabel: string = localize('alertDialog.OperatorList', 'Operator List'); + private static readonly OperatorNameColumnLabel: string = localize('alertDialog.OperatorName', 'Operator'); + private static readonly OperatorEmailColumnLabel: string = localize('alertDialog.OperatorEmail', 'E-mail'); + private static readonly OperatorPagerColumnLabel: string = localize('alertDialog.OperatorPager', 'Pager'); + private static readonly NewOperatorButtonLabel: string = localize('alertDialog.NewOperator', 'New Operator'); // Options tab strings - private static readonly IncludeErrorInEmailCheckBoxLabel: string = localize('createAlert.IncludeErrorInEmail', 'Include alert error text in e-mail'); - private static readonly IncludeErrorInPagerCheckBoxLabel: string = localize('createAlert.IncludeErrorInPager', 'Include alert error text in pager'); - private static readonly AdditionalMessageTextBoxLabel: string = localize('createAlert.AdditionalNotification', 'Additional notification message to send'); - private static readonly DelayBetweenResponsesTextBoxLabel: string = localize('createAlert.DelayBetweenResponse', 'Delay between responses'); - private static readonly DelayMinutesTextBoxLabel: string = localize('createAlert.DelayMinutes', 'Delay Minutes'); - private static readonly DelaySecondsTextBoxLabel: string = localize('createAlert.DelaySeconds', 'Delay Seconds'); + private static readonly IncludeErrorInEmailCheckBoxLabel: string = localize('alertDialog.IncludeErrorInEmail', 'Include alert error text in e-mail'); + private static readonly IncludeErrorInPagerCheckBoxLabel: string = localize('alertDialog.IncludeErrorInPager', 'Include alert error text in pager'); + private static readonly AdditionalMessageTextBoxLabel: string = localize('alertDialog.AdditionalNotification', 'Additional notification message to send'); + private static readonly DelayBetweenResponsesTextBoxLabel: string = localize('alertDialog.DelayBetweenResponse', 'Delay between responses'); + private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes'); + private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds'); // UI Components private generalTab: sqlops.window.modelviewdialog.DialogTab; @@ -141,8 +142,10 @@ export class AlertDialog extends AgentDialog { private delayMinutesTextBox: sqlops.InputBoxComponent; private delaySecondsTextBox: sqlops.InputBoxComponent; - constructor(ownerUri: string) { - super(ownerUri, new AlertData(ownerUri), AlertDialog.DialogTitle); + constructor(ownerUri: string, alertInfo: sqlops.AgentAlertInfo = null) { + super(ownerUri, + new AlertData(ownerUri, alertInfo), + alertInfo ? AlertDialog.EditDialogTitle : AlertDialog.CreateDialogTitle); } protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) { @@ -210,7 +213,7 @@ export class AlertDialog extends AgentDialog { title: AlertDialog.SeverityLabel }, { component: this.raiseAlertMessageCheckBox, - title: AlertDialog.RaiseIfMessageContainsLabel + title: '' }, { component: this.raiseAlertMessageTextBox, title: AlertDialog.MessageTextLabel @@ -218,6 +221,9 @@ export class AlertDialog extends AgentDialog { ]).withLayout({ width: '100%' }).component(); await view.initializeModel(formModel); + + this.nameTextBox.value = this.model.name; + this.enabledCheckBox.checked = this.model.isEnabled; }); } @@ -326,7 +332,7 @@ export class AlertDialog extends AgentDialog { if (selected) { let index = AlertDialog.AlertSeverities.indexOf(selected); if (index >= 0) { - severityNumber = index; + severityNumber = index + 1; } } return severityNumber; @@ -339,6 +345,7 @@ export class AlertDialog extends AgentDialog { this.model.alertType = this.getDropdownValue(this.typeDropDown); this.model.databaseName = this.getDropdownValue(this.databaseDropDown); this.model.severity = this.getSeverityNumber(); + this.model.messageId = undefined; let raiseIfError = this.raiseAlertMessageCheckBox.checked; if (raiseIfError) { diff --git a/extensions/agent/src/dialogs/operatorDialog.ts b/extensions/agent/src/dialogs/operatorDialog.ts index 586cb40459..4ddab02ee8 100644 --- a/extensions/agent/src/dialogs/operatorDialog.ts +++ b/extensions/agent/src/dialogs/operatorDialog.ts @@ -81,9 +81,9 @@ export class OperatorDialog extends AgentDialog { private initializeGeneralTab() { this.generalTab.registerContent(async view => { - this.nameTextBox = view.modelBuilder.inputBox() - .withProperties({ width: '100%' }) - .component(); + + this.nameTextBox = view.modelBuilder.inputBox().component(); + this.enabledCheckBox = view.modelBuilder.checkBox() .withProperties({ label: OperatorDialog.EnabledCheckboxLabel diff --git a/extensions/agent/src/interfaces.ts b/extensions/agent/src/interfaces.ts index ca38d722a7..1ea6f4dc05 100644 --- a/extensions/agent/src/interfaces.ts +++ b/extensions/agent/src/interfaces.ts @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +export enum AgentDialogMode { + CREATE = 1, + EDIT = 2, + VIEW = 3 +} + export interface IAgentDialogData { + dialogMode: AgentDialogMode; initialize(): void; save(): void; } diff --git a/extensions/agent/src/mainController.ts b/extensions/agent/src/mainController.ts index 1926b29632..c8914afa76 100644 --- a/extensions/agent/src/mainController.ts +++ b/extensions/agent/src/mainController.ts @@ -3,6 +3,7 @@ * 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 { AlertDialog } from './dialogs/alertDialog'; import { JobDialog } from './dialogs/jobDialog'; @@ -38,8 +39,8 @@ export class MainController { let dialog = new PickScheduleDialog(ownerUri); dialog.showDialog(); }); - vscode.commands.registerCommand('agent.openCreateAlertDialog', (ownerUri: string) => { - let dialog = new AlertDialog(ownerUri); + vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, alertInfo: sqlops.AgentAlertInfo) => { + let dialog = new AlertDialog(ownerUri, alertInfo); dialog.openDialog(); }); vscode.commands.registerCommand('agent.openCreateOperatorDialog', (ownerUri: string) => { diff --git a/extensions/agent/src/test/testAgentService.ts b/extensions/agent/src/test/testAgentService.ts index d14c4b1a53..31d6b9e1a0 100644 --- a/extensions/agent/src/test/testAgentService.ts +++ b/extensions/agent/src/test/testAgentService.ts @@ -99,4 +99,7 @@ export class TestAgentService implements sqlops.AgentServicesProvider { deleteJobSchedule(ownerUri: string, scheduleInfo: sqlops.AgentJobScheduleInfo): Thenable { return undefined; } + + registerOnUpdated(handler: () => any): void { + } } diff --git a/extensions/mssql/src/features.ts b/extensions/mssql/src/features.ts index d90b078cb2..71ac7a9630 100644 --- a/extensions/mssql/src/features.ts +++ b/extensions/mssql/src/features.ts @@ -35,6 +35,8 @@ export class AgentServicesFeature extends SqlOpsFeature { contracts.AgentJobActionRequest.type ]; + private onUpdatedHandler: () => any; + constructor(client: SqlOpsDataClient) { super(client, AgentServicesFeature.messagesTypes); } @@ -53,6 +55,18 @@ export class AgentServicesFeature extends SqlOpsFeature { protected registerProvider(options: undefined): Disposable { const client = this._client; + let self = this; + + // On updated registration + let registerOnUpdated = (handler: () => any): void => { + self.onUpdatedHandler = handler; + }; + + let fireOnUpdated = (): void => { + if (self.onUpdatedHandler) { + self.onUpdatedHandler(); + } + }; // Job management methods let getJobs = (ownerUri: string): Thenable => { @@ -96,7 +110,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.CreateAgentJobRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -112,7 +129,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.UpdateAgentJobRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -127,7 +147,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.DeleteAgentJobRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -157,7 +180,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.CreateAgentJobStepRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -173,7 +199,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.UpdateAgentJobStepRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -188,7 +217,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.DeleteAgentJobStepRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -218,7 +250,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.CreateAgentAlertRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -234,7 +269,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.UpdateAgentAlertRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -249,7 +287,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.DeleteAgentAlertRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -279,7 +320,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.CreateAgentOperatorRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -295,7 +339,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.UpdateAgentOperatorRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -310,7 +357,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.DeleteAgentOperatorRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -340,7 +390,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.CreateAgentProxyRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -356,7 +409,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.UpdateAgentProxyRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -371,7 +427,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.DeleteAgentProxyRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -401,7 +460,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.CreateAgentJobScheduleRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -417,7 +479,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.UpdateAgentJobScheduleRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -432,7 +497,10 @@ export class AgentServicesFeature extends SqlOpsFeature { }; let requestType = contracts.DeleteAgentJobScheduleRequest.type; return client.sendRequest(requestType, params).then( - r => r, + r => { + fireOnUpdated(); + return r; + }, e => { client.logFailedRequest(requestType, e); return Promise.resolve(undefined); @@ -467,7 +535,8 @@ export class AgentServicesFeature extends SqlOpsFeature { getJobSchedules, createJobSchedule, updateJobSchedule, - deleteJobSchedule + deleteJobSchedule, + registerOnUpdated }); } } diff --git a/src/sql/parts/jobManagement/agent/agentView.component.ts b/src/sql/parts/jobManagement/agent/agentView.component.ts index 74e5f654d0..8634879fb1 100644 --- a/src/sql/parts/jobManagement/agent/agentView.component.ts +++ b/src/sql/parts/jobManagement/agent/agentView.component.ts @@ -18,6 +18,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; import { AgentJobInfo, AgentJobHistoryInfo } from 'sqlops'; import { PanelComponent, IPanelOptions, NavigationBarLayout } from 'sql/base/browser/ui/panel/panel.component'; +import { IJobManagementService } from 'sql/parts/jobManagement/common/interfaces'; export const DASHBOARD_SELECTOR: string = 'agentview-component'; @@ -56,8 +57,15 @@ export class AgentViewComponent { }; constructor( - @Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef) { + @Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef, + @Inject(IJobManagementService) jobManagementService: IJobManagementService) { this._expanded = new Map(); + + let self = this; + jobManagementService.onDidChange((args) => { + self.refresh = true; + self._cd.detectChanges(); + }); } /** diff --git a/src/sql/parts/jobManagement/common/interfaces.ts b/src/sql/parts/jobManagement/common/interfaces.ts index 62f209692e..e157ee90e8 100644 --- a/src/sql/parts/jobManagement/common/interfaces.ts +++ b/src/sql/parts/jobManagement/common/interfaces.ts @@ -8,6 +8,7 @@ import * as sqlops from 'sqlops'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { JobCacheObject } from './jobManagementService'; +import { Event } from 'vs/base/common/event'; export const SERVICE_ID = 'jobManagementService'; @@ -15,8 +16,10 @@ export const IJobManagementService = createDecorator(SERV export interface IJobManagementService { _serviceBrand: any; + onDidChange: Event; registerProvider(providerId: string, provider: sqlops.AgentServicesProvider): void; + fireOnDidChange(): void; getJobs(connectionUri: string): Thenable; getJobHistory(connectionUri: string, jobID: string): Thenable; diff --git a/src/sql/parts/jobManagement/common/jobActions.ts b/src/sql/parts/jobManagement/common/jobActions.ts index 80cc0cc671..fd5c9050d7 100644 --- a/src/sql/parts/jobManagement/common/jobActions.ts +++ b/src/sql/parts/jobManagement/common/jobActions.ts @@ -244,11 +244,17 @@ export class EditAlertAction extends Action { public static ID = 'jobaction.editAlert'; public static LABEL = nls.localize('jobaction.editAlert', "Edit Alert"); - constructor() { + constructor( + @ICommandService private _commandService: ICommandService + ) { super(EditAlertAction.ID, EditAlertAction.LABEL); } public run(actionInfo: IJobActionInfo): TPromise { + this._commandService.executeCommand( + 'agent.openAlertDialog', + actionInfo.ownerUri, + actionInfo.targetObject); return TPromise.as(true); } } diff --git a/src/sql/parts/jobManagement/common/jobManagementService.ts b/src/sql/parts/jobManagement/common/jobManagementService.ts index 2100af662c..fb3c4b8940 100644 --- a/src/sql/parts/jobManagement/common/jobManagementService.ts +++ b/src/sql/parts/jobManagement/common/jobManagementService.ts @@ -10,11 +10,14 @@ import * as sqlops from 'sqlops'; import { TPromise } from 'vs/base/common/winjs.base'; import { IJobManagementService } from 'sql/parts/jobManagement/common/interfaces'; import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; - +import { Event, Emitter } from 'vs/base/common/event'; export class JobManagementService implements IJobManagementService { _serviceBrand: any; + private _onDidChange = new Emitter(); + public readonly onDidChange: Event = this._onDidChange.event; + private _providers: { [handle: string]: sqlops.AgentServicesProvider; } = Object.create(null); private _jobCacheObject : {[server: string]: JobCacheObject; } = {}; @@ -23,6 +26,10 @@ export class JobManagementService implements IJobManagementService { ) { } + public fireOnDidChange(): void { + this._onDidChange.fire(void 0); + } + public getJobs(connectionUri: string): Thenable { return this._runAction(connectionUri, (runner) => { return runner.getJobs(connectionUri); diff --git a/src/sql/parts/jobManagement/views/alertsView.component.ts b/src/sql/parts/jobManagement/views/alertsView.component.ts index a196c0a2af..8988c8d4f5 100644 --- a/src/sql/parts/jobManagement/views/alertsView.component.ts +++ b/src/sql/parts/jobManagement/views/alertsView.component.ts @@ -164,7 +164,7 @@ export class AlertsViewComponent extends JobManagementView implements OnInit { public openCreateAlertDialog() { let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri; - this._commandService.executeCommand('agent.openCreateAlertDialog', ownerUri); + this._commandService.executeCommand('agent.openAlertDialog', ownerUri); } private refreshJobs() { diff --git a/src/sql/parts/jobManagement/views/proxiesView.component.ts b/src/sql/parts/jobManagement/views/proxiesView.component.ts index 166c7451b7..d12618407f 100644 --- a/src/sql/parts/jobManagement/views/proxiesView.component.ts +++ b/src/sql/parts/jobManagement/views/proxiesView.component.ts @@ -136,7 +136,7 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit { private onProxiesAvailable(proxies: sqlops.AgentProxyInfo[]) { let items: any = proxies.map((item) => { return { - id: item.id, + id: item.accountName, accountName: item.accountName, credentialName: item.credentialName }; diff --git a/src/sql/sqlops.d.ts b/src/sql/sqlops.d.ts index a84bc849b2..076da0fe56 100644 --- a/src/sql/sqlops.d.ts +++ b/src/sql/sqlops.d.ts @@ -1384,12 +1384,13 @@ declare module 'sqlops' { updateProxy(ownerUri: string, originalProxyName: string, proxyInfo: AgentProxyInfo): Thenable; deleteProxy(ownerUri: string, proxyInfo: AgentProxyInfo): Thenable; - // Job Schedule management methods getJobSchedules(ownerUri: string): Thenable; createJobSchedule(ownerUri: string, scheduleInfo: AgentJobScheduleInfo): Thenable; updateJobSchedule(ownerUri: string, originalScheduleName: string, scheduleInfo: AgentJobScheduleInfo): Thenable; deleteJobSchedule(ownerUri: string, scheduleInfo: AgentJobScheduleInfo): Thenable; + + registerOnUpdated(handler: () => any): void; } // Task service interfaces ---------------------------------------------------------------------------- diff --git a/src/sql/workbench/api/node/extHostDataProtocol.ts b/src/sql/workbench/api/node/extHostDataProtocol.ts index b6a47110f1..7735a38ffa 100644 --- a/src/sql/workbench/api/node/extHostDataProtocol.ts +++ b/src/sql/workbench/api/node/extHostDataProtocol.ts @@ -603,4 +603,11 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { $deleteProxy(handle: number, ownerUri: string, proxy: sqlops.AgentProxyInfo): Thenable { return this._resolveProvider(handle).deleteProxy(ownerUri, proxy); } + + /** + * SQL Agent job data update notification + */ + public $onJobDataUpdated(handle: Number): void { + this._proxy.$onJobDataUpdated(handle); + } } diff --git a/src/sql/workbench/api/node/mainThreadDataProtocol.ts b/src/sql/workbench/api/node/mainThreadDataProtocol.ts index 96d87fa631..92776e0c95 100644 --- a/src/sql/workbench/api/node/mainThreadDataProtocol.ts +++ b/src/sql/workbench/api/node/mainThreadDataProtocol.ts @@ -460,6 +460,11 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape { this._profilerService.onSessionStopped(response); } + // SQL Server Agent handlers + public $onJobDataUpdated(handle: Number): void { + this._jobManagementService.fireOnDidChange(); + } + public $unregisterProvider(handle: number): TPromise { let capabilitiesRegistration = this._capabilitiesRegistrations[handle]; if (capabilitiesRegistration) { diff --git a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts index 742907a9a8..bf39d98f96 100644 --- a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts @@ -265,6 +265,10 @@ export function createApiFactory( }; let registerAgentServicesProvider = (provider: sqlops.AgentServicesProvider): vscode.Disposable => { + provider.registerOnUpdated(() => { + extHostDataProvider.$onJobDataUpdated(provider.handle); + }); + return extHostDataProvider.$registerAgentServiceProvider(provider); }; diff --git a/src/sql/workbench/api/node/sqlExtHost.protocol.ts b/src/sql/workbench/api/node/sqlExtHost.protocol.ts index 568c68d646..a37d267a00 100644 --- a/src/sql/workbench/api/node/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/node/sqlExtHost.protocol.ts @@ -456,6 +456,7 @@ export interface MainThreadDataProtocolShape extends IDisposable { $onScriptingComplete(handle: number, message: sqlops.ScriptingCompleteResult): void; $onSessionEventsAvailable(handle: number, response: sqlops.ProfilerSessionEvents): void; $onSessionStopped(handle: number, response: sqlops.ProfilerSessionStoppedParams): void; + $onJobDataUpdated(handle: Number): void; /** * Callback when a session has completed initialization