diff --git a/extensions/agent/src/dialogs/alertDialog.ts b/extensions/agent/src/dialogs/alertDialog.ts index 3c4b3651e4..5bc352f542 100644 --- a/extensions/agent/src/dialogs/alertDialog.ts +++ b/extensions/agent/src/dialogs/alertDialog.ts @@ -10,6 +10,8 @@ import * as sqlops from 'sqlops'; import { AgentDialog } from './agentDialog'; import { AgentUtils } from '../agentUtils'; import { AlertData } from '../data/alertData'; +import { OperatorDialog } from './operatorDialog'; +import { JobDialog } from './jobDialog'; const localize = nls.loadMessageBundle(); @@ -21,6 +23,7 @@ export class AlertDialog extends AgentDialog { 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'); + private static readonly EventAlertText: string = localize('alertDialog.eventAlert', 'Event alert definition'); // General tab strings private static readonly NameLabel: string = localize('alertDialog.Name', 'Name'); @@ -111,89 +114,26 @@ export class AlertDialog extends AgentDialog { private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes'); private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds'); - // Object dropdown strings - private static readonly AccessMethodsLabel: string = localize('alertDialog.AccessMethods', 'Access Methods'); - private static readonly AdvancedAnalyticsLabel: string = localize('alertDialog.AdvancedAnalyticsLabel', 'Advanced Analytics'); - private static readonly AvailabilityReplicaLabel: string = localize('alertDialog.AvailabilityReplica', 'Availability Replica'); - private static readonly BatchRespStatisticsLabel: string = localize('alertDialog.BatchRespStatistics', 'Batch Resp Statistics'); - private static readonly BrokerActivationLabel: string = localize('alertDialog.BrokerActivation', 'Broker Activation'); - private static readonly BrokerStatisticsLabel: string = localize('alertDialog.BrokerStatistics', 'Broker Statistics'); - private static readonly BrokerTOStatisticsLabel: string = localize('alertDialog.BrokerTOStatistics', 'Broker TO Statistics'); - private static readonly BrokerDBMTransportLabel: string = localize('alertDialog.BrokerDBMTransport', 'Broker/DBM Transport'); - private static readonly BufferManagerLabel: string = localize('alertDialog.BufferManager', 'Buffer Manager'); - private static readonly BufferNodeLabel: string = localize('alertDialog.BufferNode', 'Buffer Node'); - private static readonly CatalogMetadataLabel: string = localize('alertDialog.CatalogMetadata', 'Catalog Metadata'); - private static readonly CLRLabel: string = localize('alertDialog.CLR', 'CLR'); - private static readonly ColumnstoreLabel: string = localize('alertDialog.Columnstore', 'Columnstore'); - private static readonly CursorManagerLabel: string = localize('alertDialog.CursorManagerLabel', 'Cursor Manager by Type'); - private static readonly CursorManagerTotalLabel: string = localize('alertDialog.CursorManagerTotalLabel', 'Cursor Manager Total'); - private static readonly DatabaseReplicaLabel: string = localize('alertDialog.DatabaseReplica', 'Database Replica'); - private static readonly DatabasesLabel: string = localize('alertDialog.DatabasesLabel', 'Databases'); - private static readonly DeprecatedFeaturesLabel: string = localize('alertDialog.DeprecatedFeatures', 'Deprecated Features'); - private static readonly ExecStatisticsLabel: string = localize('alertDialog.ExecStatistics', 'Exec Statistics'); - private static readonly ExternalScriptsLabel: string = localize('alertDialog.ExternalScripts', 'External Scripts'); - private static readonly FileTableLabel: string = localize('alertDialog.FileTable', 'File Table'); - private static readonly GeneralStatisticsLabel: string = localize('alertDialog.GeneralStatistics', 'General Statistics'); - private static readonly HTTPStorageLabel: string = localize('alertDialog.HTTPStorage', 'HTTP Storage'); - private static readonly LatchesLabel: string = localize('alertDialog.Latches', 'Latches'); - private static readonly LocksLabel: string = localize('alertDialog.Locks', 'Locks'); - private static readonly LogPoolFreePoolLabel: string = localize('alertDialog.LogPoolFreePool', 'LogPool FreePool'); - private static readonly MemoryBrokerClerksLabel: string = localize('alertDialog.MemoryBrokerClerks', 'Memory Broker Clerks'); - private static readonly MemoryManagerLabel: string = localize('alertDialog.MemoryManager', 'Memory Manager'); - private static readonly MemoryNodeLabel: string = localize('alertDialog.MemoryNode', 'Memory Node'); - private static readonly PlanCacheLabel: string = localize('alertDialog.PlanCache', 'Plan Cache'); - private static readonly QueryStoreLabel: string = localize('alertDialog.QueryStore', 'Query Store'); - private static readonly ResourcePoolStatsLabel: string = localize('alertDialog.ResourcePoolStats', 'Resource Pool Stats'); - private static readonly SQLErrorsLabel: string = localize('alertDialog.SQLErrors', 'SQL Errors'); - private static readonly SQLServer2017XTPCursorsLabel: string = localize('alertDialog.SQLServer2017XTPCursors', 'SQL Server 2017 XTP Cursors'); - private static readonly SQLServer2017XTPGarbageCollectionLabel: string = localize('alertDialog.SQLServer2017XTPGarbageCollection', 'SQL Server 2017 XTP Garbage Collection'); - private static readonly SQLServer2017XTPIOGovernerLabel: string = localize('alertDialog.SQLServer2017XTPIOGoverner', 'SQL Server 2017 XTP IO Governer'); - private static readonly SQLServer2017XTPPhantomProcessorLabel: string = localize('alertDialog.SQLServer2017XTPPhantomProcessor', 'SQL Server 2017 XTP Phantom Processor'); - private static readonly SQLServer2017XTPStorageLabel: string = localize('alertDialog.SQLServer2017XTPStorage', 'SQL Server 2017 XTP Storage'); - private static readonly SQLServer2017XTPTransactionLogLabel: string = localize('alertDialog.SQLServer2017XTPTransactionLog', 'SQL Server 2017 XTP Transaction Log'); - private static readonly SQLServer2017XTPTransactionsLabel: string = localize('alertDialog.SQLServer2017XTPTransactions', 'SQL Server 2017 XTP Transactions'); - private static readonly TransactionsLabel: string = localize('alertDialog.Transactions', 'Transactions'); - private static readonly UserSettableLabel: string = localize('alertDialog.UserSettable', 'User Settable'); - private static readonly WaitStatisticsLabel: string = localize('alertDialog.WaitStatistics', 'Wait Statistics'); - private static readonly WorkloadGroupStats: string = localize('alertDialog.WorkloadGroupStats', 'Workload Group Stats'); - private static readonly ObjectDropdownOptions: string[] = [AlertDialog.AccessMethodsLabel, AlertDialog.AdvancedAnalyticsLabel, AlertDialog.AvailabilityReplicaLabel, - AlertDialog.BatchRespStatisticsLabel, AlertDialog.BrokerActivationLabel, AlertDialog.BrokerStatisticsLabel, AlertDialog.BrokerTOStatisticsLabel, AlertDialog.BrokerDBMTransportLabel, - AlertDialog.BufferManagerLabel, AlertDialog.BufferNodeLabel, AlertDialog.CatalogMetadataLabel, AlertDialog.CLRLabel, AlertDialog.ColumnstoreLabel, - AlertDialog.CursorManagerLabel, AlertDialog.CursorManagerTotalLabel, AlertDialog.DatabaseReplicaLabel, AlertDialog.DatabasesLabel, AlertDialog.DeprecatedFeaturesLabel, - AlertDialog.ExecStatisticsLabel, AlertDialog.ExternalScriptsLabel, AlertDialog.FileTableLabel, AlertDialog.GeneralStatisticsLabel, AlertDialog.HTTPStorageLabel, - AlertDialog.LatchesLabel, AlertDialog.LocksLabel, AlertDialog.LogPoolFreePoolLabel, AlertDialog.MemoryBrokerClerksLabel, AlertDialog.MemoryManagerLabel, - AlertDialog.MemoryNodeLabel, AlertDialog.PlanCacheLabel, AlertDialog.QueryStoreLabel, AlertDialog.ResourcePoolStatsLabel, AlertDialog.SQLErrorsLabel, - AlertDialog.SQLServer2017XTPCursorsLabel, AlertDialog.SQLServer2017XTPGarbageCollectionLabel, AlertDialog.SQLServer2017XTPIOGovernerLabel, - AlertDialog.SQLServer2017XTPPhantomProcessorLabel, AlertDialog.SQLServer2017XTPStorageLabel, AlertDialog.SQLServer2017XTPTransactionLogLabel, - AlertDialog.SQLServer2017XTPTransactionsLabel, AlertDialog.TransactionsLabel, AlertDialog.UserSettableLabel, AlertDialog.WaitStatisticsLabel, - AlertDialog.WorkloadGroupStats]; - // UI Components private generalTab: sqlops.window.modelviewdialog.DialogTab; private responseTab: sqlops.window.modelviewdialog.DialogTab; private optionsTab: sqlops.window.modelviewdialog.DialogTab; - // Form Models - private eventAlertFormModel: sqlops.FormContainer; - private performanceConditionAlertFormModel: sqlops.FormContainer; - private wmiEventFormModel: sqlops.FormContainer; - // General tab controls private nameTextBox: sqlops.InputBoxComponent; private typeDropDown: sqlops.DropDownComponent; private severityDropDown: sqlops.DropDownComponent; - private errorNumberTextBox: sqlops.InputBoxComponent; private databaseDropDown: sqlops.DropDownComponent; private enabledCheckBox: sqlops.CheckBoxComponent; + private errorNumberRadioButton: sqlops.RadioButtonComponent; + private severityRadioButton: sqlops.RadioButtonComponent; + private errorNumberTextBox: sqlops.InputBoxComponent; private raiseAlertMessageCheckBox: sqlops.CheckBoxComponent; private raiseAlertMessageTextBox: sqlops.InputBoxComponent; - private severityRadioButton: sqlops.RadioButtonComponent; - private errorNumberRadioButton: sqlops.RadioButtonComponent; - private objectDropDown: sqlops.DropDownComponent; // Response tab controls - private executeJobDropdown: sqlops.DropDownComponent; + private executeJobTextBox: sqlops.InputBoxComponent; private executeJobCheckBox: sqlops.CheckBoxComponent; private newJobButton: sqlops.ButtonComponent; private notifyOperatorsCheckBox: sqlops.CheckBoxComponent; @@ -244,7 +184,6 @@ export class AlertDialog extends AgentDialog { dialog.okButton.enabled = false; } }); - this.enabledCheckBox = view.modelBuilder.checkBox() .withProperties({ label: AlertDialog.EnabledCheckboxLabel @@ -252,123 +191,116 @@ export class AlertDialog extends AgentDialog { this.enabledCheckBox.checked = true; + this.databaseDropDown = view.modelBuilder.dropDown() + .withProperties({ + value: databases[0], + values: databases, + width: '100%' + }).component(); + this.typeDropDown = view.modelBuilder.dropDown() - .withProperties({ - value: '', - values: AlertDialog.AlertTypes - }).component(); + .withProperties({ + value: '', + values: AlertDialog.AlertTypes, + width: '100%' + }).component(); - this.initializeSqlServerEventAlert(view, databases); - }); - } + this.severityRadioButton = view.modelBuilder.radioButton() + .withProperties({ + value: 'serverity', + name: 'alertTypeOptions', + label: AlertDialog.SeverityLabel, + checked: true + }).component(); + this.severityRadioButton.checked = true; - private async initializeSqlServerPerformanceConditionAlert(view: sqlops.ModelView) { - this.objectDropDown = view.modelBuilder.dropDown() - .withProperties({ - value: '', - values: AlertDialog.ObjectDropdownOptions - }).component(); - this.performanceConditionAlertFormModel = view.modelBuilder.formContainer() - .withFormItems([{ - component: this.nameTextBox, - title: AlertDialog.NameLabel - }, { - component: this.typeDropDown, - title: AlertDialog.TypeLabel - }, { - component: this.objectDropDown, - title: 'Object' - }]).component(); - } + this.severityDropDown = view.modelBuilder.dropDown() + .withProperties({ + value: AlertDialog.AlertSeverities[0], + values: AlertDialog.AlertSeverities, + width: '100%' + }).component(); - private async initializeSqlServerEventAlert(view: sqlops.ModelView, databases: string[]) { - this.databaseDropDown = view.modelBuilder.dropDown() - .withProperties({ - value: databases[0], - values: databases - }).component(); + this.errorNumberRadioButton = view.modelBuilder.radioButton() + .withProperties({ + value: 'errorNumber', + name: 'alertTypeOptions', + label: AlertDialog.ErrorNumberLabel + }).component(); - this.severityDropDown = view.modelBuilder.dropDown() - .withProperties({ - value: AlertDialog.AlertSeverities[0], - values: AlertDialog.AlertSeverities, - width: 320 - }).component(); - - let severityFormContainer = view.modelBuilder.formContainer() - .withFormItems([{ - component: this.severityDropDown, - title: '' - }]).component(); - - this.severityRadioButton = view.modelBuilder.radioButton() - .withProperties({ - value: 'Severity', - name: 'radioButtonOptions', - label: AlertDialog.SeverityLabel - }).component(); - - this.severityRadioButton.checked = true; - this.severityDropDown.enabled = true; - - this.severityRadioButton.onDidClick(() => { + this.errorNumberTextBox = view.modelBuilder.inputBox() + .withProperties({ + width: '100%' + }) + .component(); this.errorNumberTextBox.enabled = false; - this.errorNumberRadioButton.checked = false; - this.severityDropDown.enabled = true; - }); - this.errorNumberTextBox = view.modelBuilder.inputBox() - .withProperties({ - inputType: 'text', - placeHolder: '1', - width: 320 - }).component(); + this.errorNumberRadioButton.onDidClick(() => { + this.errorNumberTextBox.enabled = true; + this.severityDropDown.enabled = false; + }); - let errorNumberFormContainer = view.modelBuilder.formContainer() - .withFormItems([{ - component: this.errorNumberTextBox, - title: '' - }]).component(); + this.severityRadioButton.onDidClick(() => { + this.errorNumberTextBox.enabled = false; + this.severityDropDown.enabled = true; + }); - this.errorNumberRadioButton = view.modelBuilder.radioButton() - .withProperties({ - value: 'Error Number', - name: 'radioButtonOptions', - label: AlertDialog.ErrorNumberLabel - }).component(); + this.raiseAlertMessageCheckBox = view.modelBuilder.checkBox() + .withProperties({ + label: AlertDialog.RaiseIfMessageContainsLabel + }).component(); - this.errorNumberRadioButton.checked = false; + this.raiseAlertMessageTextBox = view.modelBuilder.inputBox().component(); + this.raiseAlertMessageTextBox.enabled = false; - this.errorNumberRadioButton.onDidClick(() => { - this.severityRadioButton.checked = false; - this.errorNumberTextBox.enabled = true; - this.severityDropDown.enabled = false; - }); + this.raiseAlertMessageCheckBox.onChanged(() => { + this.raiseAlertMessageTextBox.enabled = this.raiseAlertMessageCheckBox.checked; + }); - this.raiseAlertMessageCheckBox = view.modelBuilder.checkBox() - .withProperties({ - label: AlertDialog.RaiseIfMessageContainsLabel - }).component(); + let formModel = view.modelBuilder.formContainer() + .withFormItems([{ + component: this.nameTextBox, + title: AlertDialog.NameLabel + }, { + component: this.enabledCheckBox, + title: '' + }, { + component: this.typeDropDown, + title: AlertDialog.TypeLabel + }, { + components: [{ + component: this.databaseDropDown, + title: AlertDialog.DatabaseLabel + }, + { + component: this.severityRadioButton, + title: '' + }, + { + component: this.severityDropDown, + title: '' + }, + { + component: this.errorNumberRadioButton, + title: '' + }, + { + component: this.errorNumberTextBox, + title: '' + }, + { + component: this.raiseAlertMessageCheckBox, + title: '' + }, { + component: this.raiseAlertMessageTextBox, + title: AlertDialog.MessageTextLabel + }], + title: AlertDialog.EventAlertText + } + ]).withLayout({ width: '100%' }).component(); - this.raiseAlertMessageTextBox = view.modelBuilder.inputBox() - .withProperties({ - width: 320 - }) - .component(); - this.raiseAlertMessageTextBox.enabled = false; - let raiseAlertMessageContainer = view.modelBuilder.formContainer() - .withFormItems([{ - component: this.raiseAlertMessageTextBox, - title: AlertDialog.MessageTextLabel - }]) - .component(); + await view.initializeModel(formModel); - this.raiseAlertMessageCheckBox.onChanged(() => { - if (this.raiseAlertMessageCheckBox.checked) { - this.raiseAlertMessageTextBox.enabled = true; - } else { - this.raiseAlertMessageTextBox.enabled = false; - } // initialize control values this.nameTextBox.value = this.model.name; this.raiseAlertMessageTextBox.value = this.model.eventDescriptionKeyword; @@ -392,40 +324,6 @@ export class AlertDialog extends AgentDialog { } } }); - let flexRadioButtonContainer = view.modelBuilder.flexContainer() - .withLayout({ - flexFlow: 'column' - }).withItems([this.errorNumberRadioButton, errorNumberFormContainer, - this.severityRadioButton, severityFormContainer, this.raiseAlertMessageCheckBox, - raiseAlertMessageContainer]) - .component(); - - this.eventAlertFormModel = view.modelBuilder.formContainer() - .withFormItems([{ - component: this.nameTextBox, - title: AlertDialog.NameLabel - }, { - component: this.enabledCheckBox, - title: '' - }, { - component: this.typeDropDown, - title: AlertDialog.TypeLabel - }, { - component: this.databaseDropDown, - title: AlertDialog.DatabaseLabel - }, { - component: flexRadioButtonContainer, - title: '' - } - ]).withLayout({ width: '100%' }).component(); - - let flexModel = view.modelBuilder.flexContainer() - .withItems([this.eventAlertFormModel]).component(); - - await view.initializeModel(flexModel); - - this.nameTextBox.value = this.model.name; - this.enabledCheckBox.checked = this.model.isEnabled; } private initializeResponseTab() { @@ -435,40 +333,39 @@ export class AlertDialog extends AgentDialog { label: AlertDialog.ExecuteJobCheckBoxLabel }).component(); - this.executeJobDropdown = view.modelBuilder.dropDown() - .withProperties({ - value: this.jobs[0], - values: this.jobs, - width: 380 - }).component(); - - this.executeJobDropdown.editable = true; - this.executeJobDropdown.enabled = false; + this.executeJobTextBox = view.modelBuilder.inputBox() + .withProperties({ width: 375 }) + .component(); + this.executeJobTextBox.enabled = false; this.newJobButton = view.modelBuilder.button().withProperties({ label: AlertDialog.NewJobButtonLabel, width: 80 }).component(); this.newJobButton.enabled = false; - - let executeJobContainer = view.modelBuilder.formContainer() - .withFormItems([{ - component: this.executeJobDropdown, - title: AlertDialog.ExecuteJobTextBoxLabel - },{ component: this.newJobButton, - title: '' - }]) - .component(); + this.newJobButton.onDidClick(() => { + let jobDialog = new JobDialog(this.ownerUri); + jobDialog.openDialog(); + }); this.executeJobCheckBox.onChanged(() => { if (this.executeJobCheckBox.checked) { - this.executeJobDropdown.enabled = true; + this.executeJobTextBox.enabled = true; this.newJobButton.enabled = true; } else { - this.executeJobDropdown.enabled = false; + this.executeJobTextBox.enabled = false; this.newJobButton.enabled = false; } }); + let executeJobContainer = view.modelBuilder.formContainer() + .withFormItems([{ + component: this.executeJobTextBox, + title: AlertDialog.ExecuteJobTextBoxLabel + }, { + component: this.newJobButton, + title: AlertDialog.NewJobButtonLabel + }], { componentWidth: '100%'}).component(); + this.notifyOperatorsCheckBox = view.modelBuilder.checkBox() .withProperties({ label: AlertDialog.NotifyOperatorsTextBoxLabel @@ -483,7 +380,7 @@ export class AlertDialog extends AgentDialog { ], data: [], height: 500, - width: 380 + width: 375 }).component(); this.newOperatorButton = view.modelBuilder.button().withProperties({ @@ -494,15 +391,10 @@ export class AlertDialog extends AgentDialog { this.operatorsTable.enabled = false; this.newOperatorButton.enabled = false; - let operatorContainer = view.modelBuilder.formContainer() - .withFormItems([{ - component: this.operatorsTable, - title: AlertDialog.OperatorListLabel - }, { - component: this.newOperatorButton, - title: '' - }]) - .component(); + this.newOperatorButton.onDidClick(() => { + let operatorDialog = new OperatorDialog(this.ownerUri); + operatorDialog.openDialog(); + }); this.notifyOperatorsCheckBox.onChanged(() => { if (this.notifyOperatorsCheckBox.checked) { @@ -514,18 +406,30 @@ export class AlertDialog extends AgentDialog { } }); - let flexModel = view.modelBuilder.flexContainer() - .withLayout({ - flexFlow: 'column' - }) - .withItems([this.executeJobCheckBox, executeJobContainer, this.notifyOperatorsCheckBox, operatorContainer]) - .component(); + let notifyOperatorContainer = view.modelBuilder.formContainer() + .withFormItems([{ + component: this.operatorsTable, + title: AlertDialog.OperatorListLabel + }, { + component: this.newOperatorButton, + title: '' + }], { componentWidth: '100%'}).component(); let formModel = view.modelBuilder.formContainer() .withFormItems([{ - component: flexModel, + component: this.executeJobCheckBox, title: '' - }]).withLayout({ width: '100%' }).component(); + }, { + component: executeJobContainer, + title: '' + }, { + component: this.notifyOperatorsCheckBox, + title: '' + }, { + component: notifyOperatorContainer, + title: '' + }]) + .withLayout({ width: '100%' }).component(); await view.initializeModel(formModel); }); @@ -544,29 +448,21 @@ export class AlertDialog extends AgentDialog { label: AlertDialog.IncludeErrorInPagerCheckBoxLabel }).component(); - this.additionalMessageTextBox = view.modelBuilder.inputBox() - .withProperties({ - multiline: true, - height: 150, - inputType: 'text' - }) - .component(); + this.additionalMessageTextBox = view.modelBuilder.inputBox().component(); this.delayMinutesTextBox = view.modelBuilder.inputBox() - .withValidation(component => +component.value >= 0) .withProperties({ - inputType: 'number' + inputType: 'number', + placeHolder: 0 }) .component(); - this.delayMinutesTextBox.required = true; this.delaySecondsTextBox = view.modelBuilder.inputBox() - .withValidation(component => +component.value >= 0) .withProperties({ - inputType: 'number' + inputType: 'number', + placeHolder: 0 }) .component(); - this.delaySecondsTextBox.required = true; let formModel = view.modelBuilder.formContainer() .withFormItems([{ @@ -598,11 +494,6 @@ export class AlertDialog extends AgentDialog { if (index >= 0) { severityNumber = index + 1; } - } else { - let errorNumber = +this.errorNumberTextBox.value; - if (errorNumber) { - severityNumber = errorNumber; - } } return severityNumber; } @@ -610,6 +501,7 @@ export class AlertDialog extends AgentDialog { protected updateModel() { this.model.name = this.nameTextBox.value; this.model.isEnabled = this.enabledCheckBox.checked; + this.model.alertType = this.getDropdownValue(this.typeDropDown); let databaseName = this.getDropdownValue(this.databaseDropDown); this.model.databaseName = (databaseName !== AlertDialog.AllDatabases) ? databaseName : undefined; @@ -627,7 +519,9 @@ export class AlertDialog extends AgentDialog { } else { this.model.eventDescriptionKeyword = ''; } - this.model.notificationMessage = this.additionalMessageTextBox.value; - this.model.delayBetweenResponses = +this.delayMinutesTextBox.value * 60 + +this.delaySecondsTextBox.value; + let minutes = this.delayMinutesTextBox.value ? +this.delayMinutesTextBox.value : 0; + let seconds = this.delaySecondsTextBox.value ? +this.delaySecondsTextBox : 0; + this.model.delayBetweenResponses = minutes + seconds; + } } diff --git a/extensions/agent/src/dialogs/jobDialog.ts b/extensions/agent/src/dialogs/jobDialog.ts index 1bbc126171..321b2a0aeb 100644 --- a/extensions/agent/src/dialogs/jobDialog.ts +++ b/extensions/agent/src/dialogs/jobDialog.ts @@ -3,6 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; +import * as nls from 'vscode-nls'; import * as sqlops from 'sqlops'; import { JobData } from '../data/jobData'; import { JobStepDialog } from './jobStepDialog'; @@ -10,51 +11,57 @@ import { PickScheduleDialog } from './pickScheduleDialog'; import { AlertDialog } from './alertDialog'; import { AgentDialog } from './agentDialog'; +const localize = nls.loadMessageBundle(); + export class JobDialog extends AgentDialog { // TODO: localize // Top level - private static readonly CreateDialogTitle: string = 'New Job'; - private static readonly EditDialogTitle: string = 'Edit Job'; - private readonly GeneralTabText: string = 'General'; - private readonly StepsTabText: string = 'Steps'; - private readonly SchedulesTabText: string = 'Schedules'; - private readonly AlertsTabText: string = 'Alerts'; - private readonly NotificationsTabText: string = 'Notifications'; + private static readonly CreateDialogTitle: string = localize('jobDialog.newJob', 'New Job'); + private static readonly EditDialogTitle: string = localize('jobDialog.editJob', 'Edit Job'); + private readonly GeneralTabText: string = localize('jobDialog.general', 'General'); + private readonly StepsTabText: string = localize('jobDialog.steps', 'Steps'); + private readonly SchedulesTabText: string = localize('jobDialog.schedules', 'Schedules'); + private readonly AlertsTabText: string = localize('jobDialog.alerts', 'Alerts'); + private readonly NotificationsTabText: string = localize('jobDialog.notifications', 'Notifications'); + private readonly BlankJobNameErrorText: string = localize('jobDialog.blankJobNameError', 'The name of the job cannot be blank.'); // General tab strings - private readonly NameTextBoxLabel: string = 'Name'; - private readonly OwnerTextBoxLabel: string = 'Owner'; - private readonly CategoryDropdownLabel: string = 'Category'; - private readonly DescriptionTextBoxLabel: string = 'Description'; - private readonly EnabledCheckboxLabel: string = 'Enabled'; + private readonly NameTextBoxLabel: string = localize('jobDialog.name', 'Name'); + private readonly OwnerTextBoxLabel: string = localize('jobDialog.owner', 'Owner'); + private readonly CategoryDropdownLabel: string = localize('jobDialog.category', 'Category'); + private readonly DescriptionTextBoxLabel: string = localize('jobDialog.description', 'Description'); + private readonly EnabledCheckboxLabel: string = localize('jobDialog.enabled', 'Enabled'); // Steps tab strings - private readonly JobStepsTopLabelString: string = 'Job step list'; - private readonly StepsTable_StepColumnString: string = 'Step'; - private readonly StepsTable_NameColumnString: string = 'Name'; - private readonly StepsTable_TypeColumnString: string = 'Type'; - private readonly StepsTable_SuccessColumnString: string = 'On Success'; - private readonly StepsTable_FailureColumnString: string = 'On Failure'; - private readonly NewStepButtonString: string = 'New...'; - private readonly InsertStepButtonString: string = 'Insert...'; - private readonly EditStepButtonString: string = 'Edit'; - private readonly DeleteStepButtonString: string = 'Delete'; + private readonly JobStepsTopLabelString: string = localize('jobDialog.jobStepList', 'Job step list'); + private readonly StepsTable_StepColumnString: string = localize('jobDialog.step', 'Step'); + private readonly StepsTable_NameColumnString: string = localize('jobDialog.name', 'Name'); + private readonly StepsTable_TypeColumnString: string = localize('jobDialog.type', 'Type'); + private readonly StepsTable_SuccessColumnString: string = localize('jobDialog.onSuccess', 'On Success'); + private readonly StepsTable_FailureColumnString: string = localize('jobDialog.onFailure', 'On Failure'); + private readonly NewStepButtonString: string = localize('jobDialog.new', 'New...'); + private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit'); + private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete'); + private readonly MoveStepUpButtonString: string = localize('jobDialog.moveUp', 'Move Step Up'); + private readonly MoveStepDownButtonString: string = localize('jobDialog.moveDown', 'Move Step Up'); // Notifications tab strings - private readonly NotificationsTabTopLabelString: string = 'Actions to perform when the job completes'; - private readonly EmailCheckBoxString: string = 'Email'; - private readonly PagerCheckBoxString: string = 'Page'; - private readonly EventLogCheckBoxString: string = 'Write to the Windows Application event log'; - private readonly DeleteJobCheckBoxString: string = 'Automatically delete job'; + private readonly NotificationsTabTopLabelString: string = localize('jobDialog.notificationsTabTop', 'Actions to perform when the job completes'); + private readonly EmailCheckBoxString: string = localize('jobDialog.email', 'Email'); + private readonly PagerCheckBoxString: string = localize('jobDialog.page', 'Page'); + private readonly EventLogCheckBoxString: string = localize('jobDialog.eventLogCheckBoxLabel', 'Write to the Windows Application event log'); + private readonly DeleteJobCheckBoxString: string = localize('jobDialog.deleteJobLabel', 'Automatically delete job'); // Schedules tab strings - private readonly SchedulesTopLabelString: string = 'Schedules list'; - private readonly PickScheduleButtonString: string = 'Pick Schedule'; + private readonly SchedulesTopLabelString: string = localize('jobDialog.schedulesaLabel', 'Schedules list'); + private readonly PickScheduleButtonString: string = localize('jobDialog.pickSchedule', 'Pick Schedule'); + private readonly ScheduleNameLabelString: string = localize('jobDialog.scheduleNameLabel', 'Schedule Name'); // Alerts tab strings - private readonly AlertsTopLabelString: string = 'Alerts list'; - private readonly NewAlertButtonString: string = 'New Alert'; + private readonly AlertsTopLabelString: string = localize('jobDialog.alertsList', 'Alerts list'); + private readonly NewAlertButtonString: string = localize('jobDialog.newAlert', 'New Alert'); + private readonly AlertNameLabelString: string = localize('jobDialog.alertNameLabel', 'Alert Name'); // UI Components private generalTab: sqlops.window.modelviewdialog.DialogTab; @@ -73,7 +80,8 @@ export class JobDialog extends AgentDialog { // Steps tab controls private stepsTable: sqlops.TableComponent; private newStepButton: sqlops.ButtonComponent; - private insertStepButton: sqlops.ButtonComponent; + private moveStepUpButton: sqlops.ButtonComponent; + private moveStepDownButton: sqlops.ButtonComponent; private editStepButton: sqlops.ButtonComponent; private deleteStepButton: sqlops.ButtonComponent; @@ -133,6 +141,12 @@ export class JobDialog extends AgentDialog { private initializeGeneralTab() { this.generalTab.registerContent(async view => { this.nameTextBox = view.modelBuilder.inputBox().component(); + this.nameTextBox.required = true; + this.nameTextBox.onTextChanged(() => { + if (this.nameTextBox.value && this.nameTextBox.value.length > 0) { + this.dialog.message = null; + } + }); this.ownerTextBox = view.modelBuilder.inputBox().component(); this.categoryDropdown = view.modelBuilder.dropDown().component(); this.descriptionTextBox = view.modelBuilder.inputBox().withProperties({ @@ -187,21 +201,32 @@ export class JobDialog extends AgentDialog { height: 800 }).component(); + this.moveStepUpButton = view.modelBuilder.button() + .withProperties({ + label: this.MoveStepUpButtonString, + width: 80 + }).component(); + + this.moveStepDownButton = view.modelBuilder.button() + .withProperties({ + label: this.MoveStepDownButtonString, + width: 80 + }).component(); + this.newStepButton = view.modelBuilder.button().withProperties({ label: this.NewStepButtonString, width: 80 }).component(); this.newStepButton.onDidClick((e)=>{ - let stepDialog = new JobStepDialog(this.model.ownerUri, '', '', 1, this.model); - stepDialog.openNewStepDialog(); + if (this.nameTextBox.value && this.nameTextBox.value.length > 0) { + let stepDialog = new JobStepDialog(this.model.ownerUri, this.nameTextBox.value, '' , 1, this.model); + stepDialog.openNewStepDialog(); + } else { + this.dialog.message = { text: this.BlankJobNameErrorText }; + } }); - this.insertStepButton = view.modelBuilder.button().withProperties({ - label: this.InsertStepButtonString, - width: 80 - }).component(); - this.editStepButton = view.modelBuilder.button().withProperties({ label: this.EditStepButtonString, width: 80 @@ -216,7 +241,7 @@ export class JobDialog extends AgentDialog { .withFormItems([{ component: this.stepsTable, title: this.JobStepsTopLabelString, - actions: [this.newStepButton, this.insertStepButton, this.editStepButton, this.deleteStepButton] + actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton] }]).withLayout({ width: '100%' }).component(); await view.initializeModel(formModel); }); @@ -227,7 +252,7 @@ export class JobDialog extends AgentDialog { this.alertsTable = view.modelBuilder.table() .withProperties({ columns: [ - 'Alert Name' + this.AlertNameLabelString ], data: [], height: 600, @@ -262,11 +287,11 @@ export class JobDialog extends AgentDialog { this.schedulesTable = view.modelBuilder.table() .withProperties({ columns: [ - 'Schedule Name' + this.ScheduleNameLabelString ], data: [], height: 600, - width: 400 + width: 420 }).component(); this.pickScheduleButton = view.modelBuilder.button().withProperties({ diff --git a/extensions/agent/src/dialogs/jobStepDialog.ts b/extensions/agent/src/dialogs/jobStepDialog.ts index 7c07b3c2cd..78b4605960 100644 --- a/extensions/agent/src/dialogs/jobStepDialog.ts +++ b/extensions/agent/src/dialogs/jobStepDialog.ts @@ -3,6 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; +import * as nls from 'vscode-nls'; import * as sqlops from 'sqlops'; import * as vscode from 'vscode'; import { JobStepData } from '../data/jobStepData'; @@ -10,31 +11,57 @@ import { AgentUtils } from '../agentUtils'; import { JobData } from '../data/jobData'; const path = require('path'); +const localize = nls.loadMessageBundle(); + export class JobStepDialog { // TODO: localize // Top level // - private static readonly DialogTitle: string = 'New Job Step'; - private static readonly FileBrowserDialogTitle: string = 'Locate Database Files - '; - private static readonly OkButtonText: string = 'OK'; - private static readonly CancelButtonText: string = 'Cancel'; - private static readonly GeneralTabText: string = 'General'; - private static readonly AdvancedTabText: string = 'Advanced'; - private static readonly OpenCommandText: string = 'Open...'; - private static readonly ParseCommandText: string = 'Parse'; - private static readonly NextButtonText: string = 'Next'; - private static readonly PreviousButtonText: string = 'Previous'; - private static readonly SuccessAction: string = 'On success action'; - private static readonly FailureAction: string = 'On failure action'; + private readonly DialogTitle: string = localize('jobStepDialog.newJobStep', 'New Job Step'); + private readonly FileBrowserDialogTitle: string = localize('jobStepDialog.fileBrowserTitle', 'Locate Database Files - '); + private readonly OkButtonText: string = localize('jobStepDialog.ok', 'OK'); + private readonly CancelButtonText: string = localize('jobStepDialog.cancel', 'Cancel'); + private readonly GeneralTabText: string = localize('jobStepDialog.general', 'General'); + private readonly AdvancedTabText: string = localize('jobStepDialog.advanced', 'Advanced'); + private readonly OpenCommandText: string = localize('jobStepDialog.open', 'Open...'); + private readonly ParseCommandText: string = localize('jobStepDialog.parse','Parse'); + private readonly NextButtonText: string = localize('jobStepDialog.next', 'Next'); + private readonly PreviousButtonText: string = localize('jobStepDialog.previous','Previous'); + private readonly SuccessfulParseText: string = localize('jobStepDialog.successParse', 'The command was successfully parsed.'); + private readonly FailureParseText: string = localize('jobStepDialog.failParse', 'The command failed.'); + // General Control Titles + private readonly StepNameLabelString: string = localize('jobStepDialog.stepNameLabel', 'Step Name'); + private readonly TypeLabelString: string = localize('jobStepDialog.typeLabel', 'Type'); + private readonly RunAsLabelString: string = localize('jobStepDialog.runAsLabel', 'Run as'); + private readonly DatabaseLabelString: string = localize('jobStepDialog.databaseLabel', 'Database'); + private readonly CommandLabelString: string = localize('jobStepDialog.commandLabel', 'Command'); + + // Advanced Control Titles + private readonly SuccessActionLabel: string = localize('jobStepDialog.successAction', 'On success action'); + private readonly FailureActionLabel: string = localize('jobStepDialog.failureAction', 'On failure action'); + private readonly RunAsUserLabel: string = localize('jobStepDialog.runAsUser', 'Run as user'); + private readonly RetryAttemptsLabel: string = localize('jobStepDialog.retryAttempts', 'Retry Attempts'); + private readonly RetryIntervalLabel: string = localize('jobStepDialog.retryInterval', 'Retry Interval (minutes)'); + private readonly LogToTableLabel: string = localize('jobStepDialog.logToTable', 'Log to table'); + private readonly AppendExistingTableEntryLabel: string = localize('jobStepDialog.appendExistingTableEntry', 'Append output to exisiting entry in table'); + private readonly IncludeStepOutputHistoryLabel: string = localize('jobStepDialog.includeStepOutputHistory', 'Include step output in history'); + private readonly OutputFileNameLabel: string = localize('jobStepDialog.outputFile', 'Output File'); + private readonly AppendOutputToFileLabel: string = localize('jobStepDialog.appendOutputToFile', 'Append output to existing file'); + + // File Browser Control Titles + private readonly SelectedPathLabelString: string = localize('jobStepDialog.selectedPath', 'Selected path'); + private readonly FilesOfTypeLabelString: string = localize('jobStepDialog.filesOfType', 'Files of type'); + private readonly FileNameLabelString: string = localize('jobStepDialog.fileName', 'File name'); + private readonly AllFilesLabelString: string = localize('jobStepDialog.allFiles', 'All Files (*)'); // Dropdown options - private static readonly TSQLScript: string = 'Transact-SQL script (T-SQL)'; - private static readonly AgentServiceAccount: string = 'SQL Server Agent Service Account'; - private static readonly NextStep: string = 'Go to the next step'; - private static readonly QuitJobReportingSuccess: string = 'Quit the job reporting success'; - private static readonly QuitJobReportingFailure: string = 'Quit the job reporting failure'; + private readonly TSQLScript: string = localize('jobStepDialog.TSQL', 'Transact-SQL script (T-SQL)'); + private readonly AgentServiceAccount: string = localize('jobStepDialog.agentServiceAccount', 'SQL Server Agent Service Account'); + private readonly NextStep: string = localize('jobStepDialog.nextStep', 'Go to the next step'); + private readonly QuitJobReportingSuccess: string = localize('jobStepDialog.quitJobSuccess', 'Quit the job reporting success'); + private readonly QuitJobReportingFailure: string = localize('jobStepDialog.quitJobFailure', 'Quit the job reporting failure'); // UI Components @@ -54,6 +81,7 @@ export class JobStepDialog { private retryIntervalBox: sqlops.InputBoxComponent; private outputFileNameBox: sqlops.InputBoxComponent; private fileBrowserNameBox: sqlops.InputBoxComponent; + private userInputBox: sqlops.InputBoxComponent; // Dropdowns private typeDropdown: sqlops.DropDownComponent; @@ -98,33 +126,33 @@ export class JobStepDialog { } private initializeUIComponents() { - this.dialog = sqlops.window.modelviewdialog.createDialog(JobStepDialog.DialogTitle); - this.generalTab = sqlops.window.modelviewdialog.createTab(JobStepDialog.GeneralTabText); - this.advancedTab = sqlops.window.modelviewdialog.createTab(JobStepDialog.AdvancedTabText); + this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle); + this.generalTab = sqlops.window.modelviewdialog.createTab(this.GeneralTabText); + this.advancedTab = sqlops.window.modelviewdialog.createTab(this.AdvancedTabText); this.dialog.content = [this.generalTab, this.advancedTab]; this.dialog.okButton.onClick(async () => await this.execute()); - this.dialog.okButton.label = JobStepDialog.OkButtonText; - this.dialog.cancelButton.label = JobStepDialog.CancelButtonText; + this.dialog.okButton.label = this.OkButtonText; + this.dialog.cancelButton.label = this.CancelButtonText; } private createCommands(view, queryProvider: sqlops.QueryProvider) { this.openButton = view.modelBuilder.button() .withProperties({ - label: JobStepDialog.OpenCommandText, + label: this.OpenCommandText, width: '80px' }).component(); this.parseButton = view.modelBuilder.button() .withProperties({ - label: JobStepDialog.ParseCommandText, + label: this.ParseCommandText, width: '80px' }).component(); this.parseButton.onDidClick(e => { if (this.commandTextBox.value) { queryProvider.parseSyntax(this.ownerUri, this.commandTextBox.value).then(result => { if (result && result.parseable) { - this.dialog.message = { text: 'The command was successfully parsed.', level: 2}; + this.dialog.message = { text: this.SuccessfulParseText, level: 2}; } else if (result && !result.parseable) { - this.dialog.message = { text: 'The command failed' }; + this.dialog.message = { text: this.FailureParseText }; } }); } @@ -139,13 +167,13 @@ export class JobStepDialog { .component(); this.nextButton = view.modelBuilder.button() .withProperties({ - label: JobStepDialog.NextButtonText, + label: this.NextButtonText, enabled: false, width: '80px' }).component(); this.previousButton = view.modelBuilder.button() .withProperties({ - label: JobStepDialog.PreviousButtonText, + label: this.PreviousButtonText, enabled: false, width: '80px' }).component(); @@ -159,8 +187,8 @@ export class JobStepDialog { this.nameTextBox.required = true; this.typeDropdown = view.modelBuilder.dropDown() .withProperties({ - value: JobStepDialog.TSQLScript, - values: [JobStepDialog.TSQLScript] + value: this.TSQLScript, + values: [this.TSQLScript] }) .component(); this.runAsDropdown = view.modelBuilder.dropDown() @@ -171,8 +199,8 @@ export class JobStepDialog { .component(); this.runAsDropdown.enabled = false; this.typeDropdown.onValueChanged((type) => { - if (type.selected !== JobStepDialog.TSQLScript) { - this.runAsDropdown.value = JobStepDialog.AgentServiceAccount; + if (type.selected !== this.TSQLScript) { + this.runAsDropdown.value = this.AgentServiceAccount; this.runAsDropdown.values = [this.runAsDropdown.value]; } else { this.runAsDropdown.value = ''; @@ -200,19 +228,19 @@ export class JobStepDialog { let formModel = view.modelBuilder.formContainer() .withFormItems([{ component: this.nameTextBox, - title: 'Step name' + title: this.StepNameLabelString }, { component: this.typeDropdown, - title: 'Type' + title: this.TypeLabelString }, { component: this.runAsDropdown, - title: 'Run as' + title: this.RunAsLabelString }, { component: this.databaseDropdown, - title: 'Database' + title: this.DatabaseLabelString }, { component: this.commandTextBox, - title: 'Command', + title: this.CommandLabelString, actions: [buttonContainer] }], { horizontal: false, @@ -224,81 +252,57 @@ export class JobStepDialog { }); } - private createRunAsUserOptions(view) { - let userInputBox = view.modelBuilder.inputBox() - .withProperties({ inputType: 'text', width: '100px' }).component(); - let viewButton = view.modelBuilder.button() - .withProperties({ label: '...', width: '20px' }).component(); - let viewButtonContainer = view.modelBuilder.flexContainer() - .withLayout({ width: 100, textAlign: 'right' }) - .withItems([viewButton], { flex: '1 1 50%' }).component(); - let userInputBoxContainer = view.modelBuilder.flexContainer() - .withLayout({ width: 200, textAlign: 'left' }) - .withItems([userInputBox], { flex: '1 1 50%' }).component(); - let runAsUserContainer = view.modelBuilder.flexContainer() - .withLayout({ width: 200 }) - .withItems([userInputBoxContainer, viewButtonContainer], { flex: '1 1 50%' }) - .component(); - let runAsUserForm = view.modelBuilder.formContainer() - .withFormItems([{ - component: runAsUserContainer, - title: 'Run as user' - }], { horizontal: true, componentWidth: 200 }).component(); - return runAsUserForm; - } - private createAdvancedTab() { this.advancedTab.registerContent(async (view) => { this.successActionDropdown = view.modelBuilder.dropDown() .withProperties({ - value: JobStepDialog.NextStep, - values: [JobStepDialog.NextStep, JobStepDialog.QuitJobReportingSuccess, JobStepDialog.QuitJobReportingFailure] + width: '100%', + value: this.NextStep, + values: [this.NextStep, this.QuitJobReportingSuccess, this.QuitJobReportingFailure] }) .component(); let retryFlexContainer = this.createRetryCounters(view); + this.failureActionDropdown = view.modelBuilder.dropDown() .withProperties({ - value: JobStepDialog.QuitJobReportingFailure, - values: [JobStepDialog.QuitJobReportingFailure, JobStepDialog.NextStep, JobStepDialog.QuitJobReportingSuccess] + value: this.QuitJobReportingFailure, + values: [this.QuitJobReportingFailure, this.NextStep, this.QuitJobReportingSuccess] }) .component(); let optionsGroup = this.createTSQLOptions(view); - let viewButton = view.modelBuilder.button() - .withProperties({ label: 'View', width: '50px' }).component(); - viewButton.enabled = false; this.logToTableCheckbox = view.modelBuilder.checkBox() .withProperties({ - label: 'Log to table' + label: this.LogToTableLabel }).component(); let appendToExistingEntryInTableCheckbox = view.modelBuilder.checkBox() - .withProperties({ label: 'Append output to existing entry in table' }).component(); + .withProperties({ label: this.AppendExistingTableEntryLabel }).component(); appendToExistingEntryInTableCheckbox.enabled = false; this.logToTableCheckbox.onChanged(e => { - viewButton.enabled = e; appendToExistingEntryInTableCheckbox.enabled = e; }); let appendCheckboxContainer = view.modelBuilder.groupContainer() .withItems([appendToExistingEntryInTableCheckbox]).component(); let logToTableContainer = view.modelBuilder.flexContainer() .withLayout({ flexFlow: 'row', justifyContent: 'space-between', width: 300 }) - .withItems([this.logToTableCheckbox, viewButton]).component(); + .withItems([this.logToTableCheckbox]).component(); let logStepOutputHistoryCheckbox = view.modelBuilder.checkBox() - .withProperties({ label: 'Include step output in history' }).component(); - let runAsUserOptions = this.createRunAsUserOptions(view); + .withProperties({ label: this.IncludeStepOutputHistoryLabel }).component(); + this.userInputBox = view.modelBuilder.inputBox() + .withProperties({ inputType: 'text', width: '100%' }).component(); let formModel = view.modelBuilder.formContainer() .withFormItems( [{ component: this.successActionDropdown, - title: JobStepDialog.SuccessAction + title: this.SuccessActionLabel }, { component: retryFlexContainer, title: '' }, { component: this.failureActionDropdown, - title: JobStepDialog.FailureAction + title: this.FailureActionLabel }, { component: optionsGroup, - title: 'Transact-SQL script (T-SQL)' + title: this.TSQLScript }, { component: logToTableContainer, title: '' @@ -309,8 +313,8 @@ export class JobStepDialog { component: logStepOutputHistoryCheckbox, title: '' }, { - component: runAsUserOptions, - title: '' + component: this.userInputBox, + title: this.RunAsUserLabel }], { componentWidth: 400 }).component(); @@ -323,32 +327,37 @@ export class JobStepDialog { private createRetryCounters(view) { this.retryAttemptsBox = view.modelBuilder.inputBox() - .withValidation(component => component.value >= 0) - .withProperties({ - inputType: 'number' - }) - .component(); + .withValidation(component => component.value >= 0) + .withProperties({ + inputType: 'number', + width: '100%', + placeHolder: '0' + }) + .component(); this.retryIntervalBox = view.modelBuilder.inputBox() .withValidation(component => component.value >= 0) .withProperties({ - inputType: 'number' + inputType: 'number', + width: '100%', + placeHolder: '0' }).component(); let retryAttemptsContainer = view.modelBuilder.formContainer() .withFormItems( - [{ - component: this.retryAttemptsBox, - title: 'Retry Attempts' - }], { - horizontal: false - }) + [{ + component: this.retryAttemptsBox, + title: this.RetryAttemptsLabel + }], { + horizontal: false, + componentWidth: '100%' + }) .component(); let retryIntervalContainer = view.modelBuilder.formContainer() .withFormItems( [{ component: this.retryIntervalBox, - title: 'Retry Interval (minutes)' + title: this.RetryIntervalLabel }], { horizontal: false }) @@ -362,7 +371,7 @@ export class JobStepDialog { } private openFileBrowserDialog() { - let fileBrowserTitle = JobStepDialog.FileBrowserDialogTitle + `${this.server}`; + let fileBrowserTitle = this.FileBrowserDialogTitle + `${this.server}`; this.fileBrowserDialog = sqlops.window.modelviewdialog.createDialog(fileBrowserTitle); let fileBrowserTab = sqlops.window.modelviewdialog.createTab('File Browser'); this.fileBrowserDialog.content = [fileBrowserTab]; @@ -379,8 +388,8 @@ export class JobStepDialog { }); this.fileTypeDropdown = view.modelBuilder.dropDown() .withProperties({ - value: 'All Files (*)', - values: ['All Files (*)'] + value: this.AllFilesLabelString, + values: [this.AllFilesLabelString] }) .component(); this.fileBrowserNameBox = view.modelBuilder.inputBox() @@ -392,13 +401,13 @@ export class JobStepDialog { title: '' }, { component: this.selectedPathTextBox, - title: 'Selected path:' + title: this.SelectedPathLabelString }, { component: this.fileTypeDropdown, - title: 'Files of type:' + title: this.FilesOfTypeLabelString }, { component: this.fileBrowserNameBox, - title: 'File name:' + title: this.FileNameLabelString } ]).component(); view.initializeModel(fileBrowserContainer); @@ -406,8 +415,8 @@ export class JobStepDialog { this.fileBrowserDialog.okButton.onClick(() => { this.outputFileNameBox.value = path.join(path.dirname(this.selectedPathTextBox.value), this.fileBrowserNameBox.value); }); - this.fileBrowserDialog.okButton.label = JobStepDialog.OkButtonText; - this.fileBrowserDialog.cancelButton.label = JobStepDialog.CancelButtonText; + this.fileBrowserDialog.okButton.label = this.OkButtonText; + this.fileBrowserDialog.cancelButton.label = this.CancelButtonText; sqlops.window.modelviewdialog.openDialog(this.fileBrowserDialog); } @@ -417,21 +426,15 @@ export class JobStepDialog { this.outputFileBrowserButton.onDidClick(() => this.openFileBrowserDialog()); this.outputFileNameBox = view.modelBuilder.inputBox() .withProperties({ - width: '150px', + width: 250, inputType: 'text' }).component(); - let outputViewButton = view.modelBuilder.button() - .withProperties({ - width: '50px', - label: 'View' - }).component(); - outputViewButton.enabled = false; let outputButtonContainer = view.modelBuilder.flexContainer() .withLayout({ flexFlow: 'row', textAlign: 'right', - width: 120 - }).withItems([this.outputFileBrowserButton, outputViewButton], { flex: '1 1 50%' }).component(); + width: '100%' + }).withItems([this.outputFileBrowserButton], { flex: '1 1 50%' }).component(); let outputFlexBox = view.modelBuilder.flexContainer() .withLayout({ flexFlow: 'row', @@ -441,7 +444,7 @@ export class JobStepDialog { }).component(); this.appendToExistingFileCheckbox = view.modelBuilder.checkBox() .withProperties({ - label: 'Append output to existing file' + label: this.AppendOutputToFileLabel }).component(); this.appendToExistingFileCheckbox.enabled = false; this.outputFileNameBox.onTextChanged((input) => { @@ -454,11 +457,11 @@ export class JobStepDialog { let outputFileForm = view.modelBuilder.formContainer() .withFormItems([{ component: outputFlexBox, - title: 'Output file' + title: this.OutputFileNameLabel }, { component: this.appendToExistingFileCheckbox, title: '' - }], { horizontal: true, componentWidth: 200 }).component(); + }], { horizontal: false, componentWidth: 200 }).component(); return outputFileForm; } @@ -471,8 +474,8 @@ export class JobStepDialog { this.model.databaseName = this.databaseDropdown.value as string; this.model.script = this.commandTextBox.value; this.model.successAction = this.successActionDropdown.value as string; - this.model.retryAttempts = +this.retryAttemptsBox.value; - this.model.retryInterval = +this.retryIntervalBox.value; + this.model.retryAttempts = this.retryAttemptsBox.value ? +this.retryAttemptsBox.value : 0; + this.model.retryInterval = +this.retryIntervalBox.value ? +this.retryIntervalBox.value : 0; this.model.failureAction = this.failureActionDropdown.value as string; this.model.outputFileName = this.outputFileNameBox.value; this.model.appendToLogFile = this.appendToExistingFileCheckbox.checked; diff --git a/extensions/agent/src/dialogs/operatorDialog.ts b/extensions/agent/src/dialogs/operatorDialog.ts index 839c6786d1..2e53b4b22d 100644 --- a/extensions/agent/src/dialogs/operatorDialog.ts +++ b/extensions/agent/src/dialogs/operatorDialog.ts @@ -33,6 +33,8 @@ export class OperatorDialog extends AgentDialog { private static readonly PagerFridayCheckBoxLabel: string = localize('createOperator.PagerFridayCheckBox', 'Friday '); private static readonly PagerSaturdayCheckBoxLabel: string = localize('createOperator.PagerSaturdayCheckBox', 'Saturday'); private static readonly PagerSundayCheckBoxLabel: string = localize('createOperator.PagerSundayCheckBox', 'Sunday'); + private static readonly WorkdayBeginLabel: string = localize('createOperator.workdayBegin', 'Workday begin'); + private static readonly WorkdayEndLabel: string = localize('createOperator.workdayEnd', 'Workday end'); // Notifications tab strings private static readonly AlertsTableLabel: string = localize('createOperator.AlertListHeading', 'Alert list'); @@ -184,7 +186,7 @@ export class OperatorDialog extends AgentDialog { let weekdayStartInputContainer = view.modelBuilder.formContainer() .withFormItems([{ component: this.weekdayPagerStartTimeInput, - title: 'Workday begin' + title: OperatorDialog.WorkdayBeginLabel }]).component(); this.weekdayPagerEndTimeInput = view.modelBuilder.inputBox() @@ -196,7 +198,7 @@ export class OperatorDialog extends AgentDialog { let weekdayEndInputContainer = view.modelBuilder.formContainer() .withFormItems([{ component: this.weekdayPagerEndTimeInput, - title: 'Workday end' + title: OperatorDialog.WorkdayEndLabel }]).component(); this.pagerFridayCheckBox = view.modelBuilder.checkBox() @@ -249,7 +251,7 @@ export class OperatorDialog extends AgentDialog { let saturdayStartInputContainer = view.modelBuilder.formContainer() .withFormItems([{ component: this.saturdayPagerStartTimeInput, - title: 'Workday begin' + title: OperatorDialog.WorkdayBeginLabel }]).component(); this.saturdayPagerEndTimeInput = view.modelBuilder.inputBox() @@ -261,7 +263,7 @@ export class OperatorDialog extends AgentDialog { let saturdayEndInputContainer = view.modelBuilder.formContainer() .withFormItems([{ component: this.saturdayPagerEndTimeInput, - title: 'Workday end' + title: OperatorDialog.WorkdayEndLabel }]).component(); let pagerSaturdayCheckboxContainer = view.modelBuilder.flexContainer() @@ -296,7 +298,7 @@ export class OperatorDialog extends AgentDialog { let sundayStartInputContainer = view.modelBuilder.formContainer() .withFormItems([{ component: this.sundayPagerStartTimeInput, - title: 'Workday begin' + title: OperatorDialog.WorkdayBeginLabel }]).component(); this.sundayPagerEndTimeInput = view.modelBuilder.inputBox() @@ -308,7 +310,7 @@ export class OperatorDialog extends AgentDialog { let sundayEndInputContainer = view.modelBuilder.formContainer() .withFormItems([{ component: this.sundayPagerEndTimeInput, - title: 'Workday end' + title: OperatorDialog.WorkdayEndLabel }]).component(); let pagerSundayCheckboxContainer = view.modelBuilder.flexContainer() diff --git a/extensions/agent/src/dialogs/pickScheduleDialog.ts b/extensions/agent/src/dialogs/pickScheduleDialog.ts index 98d2cf4e9c..d2d0a6188c 100644 --- a/extensions/agent/src/dialogs/pickScheduleDialog.ts +++ b/extensions/agent/src/dialogs/pickScheduleDialog.ts @@ -4,18 +4,22 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import * as nls from 'vscode-nls'; import * as sqlops from 'sqlops'; import * as vscode from 'vscode'; import { PickScheduleData } from '../data/pickScheduleData'; +const localize = nls.loadMessageBundle(); + export class PickScheduleDialog { // TODO: localize // Top level - private readonly DialogTitle: string = 'Job Schedules'; - private readonly OkButtonText: string = 'OK'; - private readonly CancelButtonText: string = 'Cancel'; - private readonly SchedulesTabText: string = 'Schedules'; + private readonly DialogTitle: string = localize('pickSchedule.jobSchedules', 'Job Schedules'); + private readonly OkButtonText: string = localize('pickSchedule.ok', 'OK'); + private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel'); + private readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Schedule Name'); + private readonly SchedulesLabelText: string = localize('pickSchedule.schedules', 'Schedules'); // UI Components private dialog: sqlops.window.modelviewdialog.Dialog; @@ -38,7 +42,6 @@ export class PickScheduleDialog { 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); } @@ -47,17 +50,17 @@ export class PickScheduleDialog { this.schedulesTable = view.modelBuilder.table() .withProperties({ columns: [ - 'Schedule Name' + this.ScheduleNameLabelText ], data: [], - height: 600, - width: 400 + height: '80em', + width: '40em' }).component(); let formModel = view.modelBuilder.formContainer() .withFormItems([{ component: this.schedulesTable, - title: 'Schedules' + title: this.SchedulesLabelText }]).withLayout({ width: '100%' }).component(); await view.initializeModel(formModel); diff --git a/extensions/agent/src/dialogs/scheduleDialog.ts b/extensions/agent/src/dialogs/scheduleDialog.ts index 792002396c..8e94838559 100644 --- a/extensions/agent/src/dialogs/scheduleDialog.ts +++ b/extensions/agent/src/dialogs/scheduleDialog.ts @@ -4,17 +4,21 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; - +import * as nls from 'vscode-nls'; import * as sqlops from 'sqlops'; import * as vscode from 'vscode'; import { ScheduleData } from '../data/scheduleData'; +const localize = nls.loadMessageBundle(); + export class ScheduleDialog { // Top level - private readonly DialogTitle: string = 'New Schedule'; - private readonly OkButtonText: string = 'OK'; - private readonly CancelButtonText: string = 'Cancel'; + private readonly DialogTitle: string = localize('scheduleDialog.newSchedule', 'New Schedule'); + private readonly OkButtonText: string = localize('scheduleDialog.ok', 'OK'); + private readonly CancelButtonText: string = localize('scheduleDialog.cancel', 'Cancel'); + private readonly ScheduleNameText: string = localize('scheduleDialog.scheduleName', 'Schedule Name'); + private readonly SchedulesLabelText: string = localize('scheduleDialog.schedules', 'Schedules'); // UI Components private dialog: sqlops.window.modelviewdialog.Dialog; @@ -46,7 +50,7 @@ export class ScheduleDialog { this.schedulesTable = view.modelBuilder.table() .withProperties({ columns: [ - 'Schedule Name' + this.ScheduleNameText ], data: [], height: 600, @@ -56,7 +60,7 @@ export class ScheduleDialog { let formModel = view.modelBuilder.formContainer() .withFormItems([{ component: this.schedulesTable, - title: 'Schedules' + title: this.SchedulesLabelText }]).withLayout({ width: '100%' }).component(); await view.initializeModel(formModel); diff --git a/samples/sqlservices/src/controllers/mainController.ts b/samples/sqlservices/src/controllers/mainController.ts index 1facf2fae1..65e212fd1d 100644 --- a/samples/sqlservices/src/controllers/mainController.ts +++ b/samples/sqlservices/src/controllers/mainController.ts @@ -285,7 +285,6 @@ export default class MainController implements vscode.Disposable { tab1.registerContent(async (view) => { await this.getTabContent(view, customButton1, customButton2, 400); }); - sqlops.window.modelviewdialog.openDialog(dialog); } diff --git a/src/sql/parts/modelComponents/componentBase.ts b/src/sql/parts/modelComponents/componentBase.ts index ff44630a8e..c99fa4ecfc 100644 --- a/src/sql/parts/modelComponents/componentBase.ts +++ b/src/sql/parts/modelComponents/componentBase.ts @@ -134,8 +134,9 @@ export abstract class ComponentBase extends Disposable implements IComponent, On if (size && typeof (size) === 'string') { if (size.toLowerCase().endsWith('px')) { return +size.replace('px', ''); + } else if (size.toLowerCase().endsWith('em')) { + return +size.replace('em', '') * 11; } - } else if (!size) { return 0; }