/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; import * as vscode from 'vscode'; import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { DefaultColumnCheckboxWidth } from '../../ui/dialogBase'; import { IObjectManagementService } from 'mssql'; import * as localizedConstants from '../localizedConstants'; import * as constants from '../constants'; import { Server, ServerViewInfo, NumaNode, AffinityType, ServerLoginMode, AuditLevel } from '../interfaces'; const Dialog_Width = '750px'; export class ServerPropertiesDialog extends ObjectManagementDialogBase { private generalTab: azdata.Tab; private readonly generalTabId: string = 'generalId'; private platformSection: azdata.GroupContainer; private sqlServerSection: azdata.GroupContainer; private nameInput: azdata.InputBoxComponent; private hardwareGenerationInput: azdata.InputBoxComponent; private languageDropdown: azdata.DropDownComponent; private memoryInput: azdata.InputBoxComponent; private operatingSystemInput: azdata.InputBoxComponent; private platformInput: azdata.InputBoxComponent; private processorsInput: azdata.InputBoxComponent; private isClusteredInput: azdata.InputBoxComponent; private isHadrEnabledInput: azdata.InputBoxComponent; private isPolyBaseInstalledInput: azdata.InputBoxComponent; private isXTPSupportedInput: azdata.InputBoxComponent; private productInput: azdata.InputBoxComponent; private reservedStorageSizeInMBInput: azdata.InputBoxComponent; private rootDirectoryInput: azdata.InputBoxComponent; private serverCollationInput: azdata.InputBoxComponent; private serviceTierInput: azdata.InputBoxComponent; private storageSpaceUsageInMBInput: azdata.InputBoxComponent; private versionInput: azdata.InputBoxComponent; private memoryTab: azdata.Tab; private readonly memoryTabId: string = 'memoryId'; private memorySection: azdata.GroupContainer; private minServerMemoryInput: azdata.InputBoxComponent; private maxServerMemoryInput: azdata.InputBoxComponent; private engineEdition: azdata.DatabaseEngineEdition; private processorsTab: azdata.Tab; private readonly processorsTabId: string = 'processorsId'; private processorsSection: azdata.GroupContainer; private autoSetProcessorAffinityMaskForAllCheckbox: azdata.CheckBoxComponent; private autoSetProcessorIOAffinityMaskForAllCheckbox: azdata.CheckBoxComponent; private securityTab: azdata.Tab; private readonly securityTabId: string = 'securityId'; private securitySection: azdata.GroupContainer; // Server authentication radio buttons private onlyWindowsAuthRadioButton: azdata.RadioButtonComponent; private sqlServerAndWindowsAuthRadioButton: azdata.RadioButtonComponent; // Login auditing radio buttons private noneRadioButton: azdata.RadioButtonComponent; private failedLoginsOnlyRadioButton: azdata.RadioButtonComponent; private successfulLoginsOnlyRadioButton: azdata.RadioButtonComponent; private bothFailedAndSuccessfulLoginsRadioButton: azdata.RadioButtonComponent; private databaseSettingsTab: azdata.Tab; private readonly databaseSettingsTabId: string = 'databaseSettingsId'; private databaseSettingsSection: azdata.GroupContainer; private compressBackupCheckbox: azdata.CheckBoxComponent; private backupChecksumCheckbox: azdata.CheckBoxComponent; private dataLocationInput: azdata.InputBoxComponent; private logLocationInput: azdata.InputBoxComponent; private backupLocationInput: azdata.InputBoxComponent; private advancedTab: azdata.Tab; private readonly advancedTabId: string = 'advancedId'; private allowTriggerToFireOthersDropdown: azdata.DropDownComponent; private blockedProcThresholdInput: azdata.InputBoxComponent; private cursorThresholdInput: azdata.InputBoxComponent; private defaultFullTextLanguageInput: azdata.InputBoxComponent; private defaultLanguageDropdown: azdata.DropDownComponent; private fullTextUpgradeOptionDropdown: azdata.DropDownComponent; private maxTextReplicationSizeInput: azdata.InputBoxComponent; private optimizeAdHocWorkloadsDropdown: azdata.DropDownComponent; private scanStartupProcsDropdown: azdata.DropDownComponent; private twoDigitYearCutoffInput: azdata.InputBoxComponent; private costThresholdParallelismInput: azdata.InputBoxComponent; private locksInput: azdata.InputBoxComponent; private maxDegreeParallelismInput: azdata.InputBoxComponent; private queryWaitInput: azdata.InputBoxComponent; private activeTabId: string; private shouldRestartServer: boolean = false; constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) { options.width = Dialog_Width; super(objectManagementService, options); this.disposables.push(this.dialogObject.onClosed(async (reason: azdata.window.CloseReason) => { if (reason === 'ok') { // only show message if user apply changes await this.notifyServerRestart(); } })); } protected override get helpUrl(): string { let helpUrl = ''; switch (this.activeTabId) { case this.generalTabId: helpUrl = constants.ViewGeneralServerPropertiesDocUrl; break; case this.memoryTabId: helpUrl = constants.ViewMemoryServerPropertiesDocUrl; break; case this.processorsTabId: helpUrl = constants.ViewProcessorsServerPropertiesDocUrl; break; case this.securityTabId: helpUrl = constants.ViewSecurityServerPropertiesDocUrl; break; case this.databaseSettingsTabId: helpUrl = constants.ViewDatabaseSettingsPropertiesDocUrl; break; case this.advancedTabId: helpUrl = constants.ViewAdvancedServerPropertiesDocUrl; break; default: break; } return helpUrl; } protected async initializeUI(): Promise { const serverInfo = await azdata.connection.getServerInfo(this.options.objectExplorerContext.connectionProfile.id); this.engineEdition = serverInfo.engineEditionId; this.initializeGeneralSection(); this.initializeMemorySection(); this.initializeProcessorsSection(); this.initializeSecuritySection(); this.initializeDatabaseSettingsSection(); this.initializeAdvancedSection(); const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab, this.processorsTab, this.securityTab, this.databaseSettingsTab, this.advancedTab] }; const serverPropertiesTabbedPannel = this.modelView.modelBuilder.tabbedPanel() .withTabs([serverPropertiesTabGroup]) .withLayout({ orientation: azdata.TabOrientation.Vertical }) .withProps({ CSSStyles: { 'margin': '-10px 0px 0px -10px' } }).component(); this.disposables.push( serverPropertiesTabbedPannel.onTabChanged(async tabId => { this.activeTabId = tabId; })); this.formContainer.addItem(serverPropertiesTabbedPannel); } private initializeGeneralSection(): void { this.nameInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.NameText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.name }); const nameContainer = this.createLabelInputContainer(localizedConstants.NameText, this.nameInput); this.hardwareGenerationInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.HardwareGenerationText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.hardwareGeneration.toString() }); const hardwareGenerationContainer = this.createLabelInputContainer(localizedConstants.HardwareGenerationText, this.hardwareGenerationInput); this.languageDropdown = this.createDropdown(localizedConstants.LanguageText, async () => { }, [this.objectInfo.language], this.objectInfo.language, this.options.isNewObject); const languageContainer = this.createLabelInputContainer(localizedConstants.LanguageText, this.languageDropdown); this.memoryInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.MemoryText, inputType: 'text', enabled: this.options.isNewObject, value: localizedConstants.StringValueInMB(this.objectInfo.memoryInMB.toString()) }); const memoryContainer = this.createLabelInputContainer(localizedConstants.MemoryText, this.memoryInput); this.operatingSystemInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.OperatingSystemText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.operatingSystem }); const operatingSystemContainer = this.createLabelInputContainer(localizedConstants.OperatingSystemText, this.operatingSystemInput); this.platformInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.PlatformText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.platform }); const platformContainer = this.createLabelInputContainer(localizedConstants.PlatformText, this.platformInput); this.processorsInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.ProcessorsText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.processors }); const processorsContainer = this.createLabelInputContainer(localizedConstants.ProcessorsText, this.processorsInput); this.isClusteredInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.IsClusteredText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.isClustered.toString() }); const isClusteredContainer = this.createLabelInputContainer(localizedConstants.IsClusteredText, this.isClusteredInput); this.isHadrEnabledInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.IsHadrEnabledText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.isHadrEnabled.toString() }); const isHadrEnabledContainer = this.createLabelInputContainer(localizedConstants.IsHadrEnabledText, this.isHadrEnabledInput); this.isPolyBaseInstalledInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.IsPolyBaseInstalledText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.isPolyBaseInstalled.toString() }); const isPolyBaseInstalledContainer = this.createLabelInputContainer(localizedConstants.IsPolyBaseInstalledText, this.isPolyBaseInstalledInput); this.isXTPSupportedInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.IsXTPSupportedText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.isXTPSupported.toString() }); const isXTPSupportedContainer = this.createLabelInputContainer(localizedConstants.IsXTPSupportedText, this.isXTPSupportedInput); this.productInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.ProductText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.product }); const productContainer = this.createLabelInputContainer(localizedConstants.ProductText, this.productInput); this.reservedStorageSizeInMBInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.ReservedStorageSizeInMBText, inputType: 'text', enabled: this.options.isNewObject, value: localizedConstants.StringValueInMB(this.objectInfo.reservedStorageSizeMB.toString()) }); const reservedStorageSizeInMBContainer = this.createLabelInputContainer(localizedConstants.ReservedStorageSizeInMBText, this.reservedStorageSizeInMBInput); this.rootDirectoryInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.RootDirectoryText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.rootDirectory }); const rootDirectoryContainer = this.createLabelInputContainer(localizedConstants.RootDirectoryText, this.rootDirectoryInput); this.serverCollationInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.ServerCollationText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.serverCollation }); const serverCollationContainer = this.createLabelInputContainer(localizedConstants.ServerCollationText, this.serverCollationInput); this.serviceTierInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.ServiceTierText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.serviceTier }); const serviceTierContainer = this.createLabelInputContainer(localizedConstants.ServiceTierText, this.serviceTierInput); this.storageSpaceUsageInMBInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.StorageSpaceUsageInMBText, inputType: 'text', enabled: this.options.isNewObject, value: localizedConstants.StringValueInMB(this.objectInfo.storageSpaceUsageInMB.toString()) }); const storageSpaceUsageInMbContainer = this.createLabelInputContainer(localizedConstants.StorageSpaceUsageInMBText, this.storageSpaceUsageInMBInput); this.versionInput = this.createInputBox(async () => { }, { ariaLabel: localizedConstants.VersionText, inputType: 'text', enabled: this.options.isNewObject, value: this.objectInfo.version }); const versionContainer = this.createLabelInputContainer(localizedConstants.VersionText, this.versionInput); let platformItems = [ nameContainer, languageContainer, memoryContainer, operatingSystemContainer, platformContainer, processorsContainer ]; let sqlServerItems = [ isClusteredContainer, isHadrEnabledContainer, isPolyBaseInstalledContainer, isXTPSupportedContainer, productContainer, rootDirectoryContainer, serverCollationContainer, versionContainer ]; if (this.engineEdition === azdata.DatabaseEngineEdition.SqlManagedInstance) { platformItems.unshift(hardwareGenerationContainer); sqlServerItems.push(reservedStorageSizeInMBContainer, serviceTierContainer, storageSpaceUsageInMbContainer); // remove isXTPSupported sqlServerItems.splice(3, 1); } this.platformSection = this.createGroup('Platform', platformItems, true); this.sqlServerSection = this.createGroup('SQL Server', sqlServerItems, true); const generalContainer = this.createGroup('', [this.platformSection, this.sqlServerSection]) this.generalTab = this.createTab(this.generalTabId, localizedConstants.GeneralSectionHeader, generalContainer); } private initializeMemorySection(): void { const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance; const minServerProps: azdata.InputBoxProperties = { ariaLabel: localizedConstants.minServerMemoryText, inputType: 'number', enabled: isEnabled, max: this.objectInfo.minServerMemory.maximumValue, min: this.objectInfo.minServerMemory.minimumValue, value: this.objectInfo.minServerMemory.value.toString(), required: true }; this.minServerMemoryInput = this.createInputBox(async (newValue) => { this.objectInfo.minServerMemory.value = +newValue; }, minServerProps); const minMemoryContainer = this.createLabelInputContainer(localizedConstants.minServerMemoryText, this.minServerMemoryInput); const maxServerProps: azdata.InputBoxProperties = { ariaLabel: localizedConstants.maxServerMemoryText, inputType: 'number', enabled: isEnabled, max: this.objectInfo.maxServerMemory.maximumValue, min: this.objectInfo.maxServerMemory.minimumValue, value: this.objectInfo.maxServerMemory.value.toString(), required: true }; this.maxServerMemoryInput = this.createInputBox(async (newValue) => { this.objectInfo.maxServerMemory.value = +newValue; }, maxServerProps); const maxMemoryContainer = this.createLabelInputContainer(localizedConstants.maxServerMemoryText, this.maxServerMemoryInput); this.memorySection = this.createGroup('', [ minMemoryContainer, maxMemoryContainer ], false); this.memoryTab = this.createTab(this.memoryTabId, localizedConstants.MemoryText, this.memorySection); } protected override async validateInput(): Promise { const errors = await super.validateInput(); if (this.objectInfo.maxServerMemory.value < this.objectInfo.minServerMemory.value) { errors.push(localizedConstants.serverMemoryMaxLowerThanMinInputError); } return errors; } private async notifyServerRestart(): Promise { if (this.shouldRestartServer) { await vscode.window.showInformationMessage(localizedConstants.needToRestartServer, { modal: true }); this.shouldRestartServer = false; } } private initializeProcessorsSection(): void { const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance; let nodes: NumaNode[] = this.objectInfo.numaNodes; let nodeTableList: azdata.TableComponent[] = []; let tableGroups: azdata.GroupContainer[] = []; if (isEnabled) { for (let node of nodes) { let table = this.createProcessorTable(node); nodeTableList.push(table); tableGroups.push(this.createGroup(localizedConstants.serverNumaNodeLabel(node.numaNodeId), [table], true)); } } this.autoSetProcessorAffinityMaskForAllCheckbox = this.createCheckbox(localizedConstants.autoSetProcessorAffinityMaskForAllText, async (newValue) => { this.objectInfo.autoProcessorAffinityMaskForAll = newValue; if (isEnabled) { for (let table of nodeTableList) { let newData = table.data; for (let i = 0; i < newData.length; i++) { if (newValue) { // if affinity mask for all is checked, then uncheck the individual processors newData[i][AffinityType.ProcessorAffinity] = false; } } await this.setTableData(table, newData); } } }, this.objectInfo.autoProcessorAffinityMaskForAll, isEnabled); this.autoSetProcessorIOAffinityMaskForAllCheckbox = this.createCheckbox(localizedConstants.autoSetProcessorAffinityIOMaskForAllText, async (newValue) => { this.objectInfo.autoProcessorAffinityIOMaskForAll = newValue; if (isEnabled) { for (let table of nodeTableList) { let newData = table.data; for (let i = 0; i < newData.length; i++) { if (newValue) { // if IO affinity mask for all is checked, then uncheck the individual processors newData[i][AffinityType.IOAffinity] = false; } } await this.setTableData(table, newData); this.resetNumaNodes(); } } }, this.objectInfo.autoProcessorAffinityIOMaskForAll, isEnabled); this.processorsSection = this.createGroup('', [ this.autoSetProcessorAffinityMaskForAllCheckbox, this.autoSetProcessorIOAffinityMaskForAllCheckbox, ], false); this.processorsSection.addItems(tableGroups); this.processorsTab = this.createTab(this.processorsTabId, localizedConstants.ProcessorsText, this.processorsSection); } private createProcessorTable(numaNode: NumaNode): azdata.TableComponent { const cssClass = 'no-borders'; let tableData = numaNode.processors.map(row => [localizedConstants.serverCPULabel(row.processorId), row.affinity, row.ioAffinity]); let processorTable = this.createTable(localizedConstants.processorLabel, [ { name: localizedConstants.processorColumnText, value: localizedConstants.processorColumnText, type: azdata.ColumnType.text, cssClass: cssClass, headerCssClass: cssClass, }, { name: localizedConstants.processorAffinityColumnText, value: localizedConstants.processorAffinityColumnText, type: azdata.ColumnType.checkBox, width: DefaultColumnCheckboxWidth, action: azdata.ActionOnCellCheckboxCheck.customAction, cssClass: cssClass, headerCssClass: cssClass, }, { name: localizedConstants.processorIOAffinityColumnText, value: localizedConstants.processorIOAffinityColumnText, type: azdata.ColumnType.checkBox, width: DefaultColumnCheckboxWidth, action: azdata.ActionOnCellCheckboxCheck.customAction, cssClass: cssClass, headerCssClass: cssClass, } ], tableData); this.disposables.push(processorTable.onCellAction(async (row) => { if (processorTable.selectedRows.length > 0) { const result = processorTable.data; let checkboxState = row; let columnToAdjust = checkboxState.column === AffinityType.ProcessorAffinity ? AffinityType.IOAffinity : AffinityType.ProcessorAffinity; if (result[checkboxState.row][columnToAdjust]) { result[checkboxState.row][columnToAdjust] = !checkboxState.checked; processorTable.updateCells = result[checkboxState.row]; } // uncheck the set all processors checkbox if (checkboxState.column === AffinityType.ProcessorAffinity) { this.autoSetProcessorAffinityMaskForAllCheckbox.checked = false; this.objectInfo.autoProcessorAffinityMaskForAll = false; this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].affinity = checkboxState.checked; this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].ioAffinity = false; } if (checkboxState.column === AffinityType.IOAffinity) { this.autoSetProcessorIOAffinityMaskForAllCheckbox.checked = false; this.objectInfo.autoProcessorAffinityIOMaskForAll = false; this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].ioAffinity = checkboxState.checked; this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].affinity = false; } this.onFormFieldChange(); } })); return processorTable; } private resetNumaNodes(): void { for (let node of this.objectInfo.numaNodes) { for (let cpu of node.processors) { cpu.ioAffinity = false; } } } private initializeSecuritySection(): void { const isWindows = this.objectInfo.platform === constants.Windows; // cannot change auth mode in sql managed instance or non windows instances const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance && isWindows; const radioServerGroupName = 'serverAuthenticationRadioGroup'; this.onlyWindowsAuthRadioButton = this.createRadioButton(localizedConstants.onlyWindowsAuthModeText, radioServerGroupName, this.objectInfo.authenticationMode === ServerLoginMode.Integrated, async () => { await this.handleAuthModeChange(); }); this.sqlServerAndWindowsAuthRadioButton = this.createRadioButton(localizedConstants.sqlServerAndWindowsAuthText, radioServerGroupName, this.objectInfo.authenticationMode === ServerLoginMode.Mixed, async () => { await this.handleAuthModeChange(); }); this.onlyWindowsAuthRadioButton.enabled = isEnabled; this.sqlServerAndWindowsAuthRadioButton.enabled = isEnabled; const serverAuthSection = this.createGroup(localizedConstants.serverAuthenticationText, [ this.onlyWindowsAuthRadioButton, this.sqlServerAndWindowsAuthRadioButton ], true); const radioLoginsGroupName = 'serverLoginsRadioGroup'; this.noneRadioButton = this.createRadioButton(localizedConstants.noLoginAuditingText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.None, async () => { await this.handleAuditLevelChange(); }); this.failedLoginsOnlyRadioButton = this.createRadioButton(localizedConstants.failedLoginsOnlyText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.Failure, async () => { await this.handleAuditLevelChange(); }); this.successfulLoginsOnlyRadioButton = this.createRadioButton(localizedConstants.successfulLoginsOnlyText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.Success, async () => { await this.handleAuditLevelChange(); }); this.bothFailedAndSuccessfulLoginsRadioButton = this.createRadioButton(localizedConstants.bothFailedAndSuccessfulLoginsText, radioLoginsGroupName, this.objectInfo.loginAuditing === AuditLevel.All, async () => { await this.handleAuditLevelChange(); }); // cannot change values in serverLogin section on Linux this.noneRadioButton.enabled = isWindows; this.failedLoginsOnlyRadioButton.enabled = isWindows; this.successfulLoginsOnlyRadioButton.enabled = isWindows; this.bothFailedAndSuccessfulLoginsRadioButton.enabled = isWindows; const serverLoginSection = this.createGroup(localizedConstants.loginAuditingText, [ this.noneRadioButton, this.failedLoginsOnlyRadioButton, this.successfulLoginsOnlyRadioButton, this.bothFailedAndSuccessfulLoginsRadioButton ], true); this.securitySection = this.createGroup('', [ serverAuthSection, serverLoginSection ], true); this.securityTab = this.createTab(this.securityTabId, localizedConstants.securityText, this.securitySection); } private async handleAuthModeChange(): Promise { if (this.onlyWindowsAuthRadioButton.checked) { this.objectInfo.authenticationMode = ServerLoginMode.Integrated; } if (this.sqlServerAndWindowsAuthRadioButton.checked) { this.objectInfo.authenticationMode = ServerLoginMode.Mixed; } if (this.objectInfo.authenticationMode !== this.originalObjectInfo.authenticationMode) { this.shouldRestartServer = true; } } private async handleAuditLevelChange(): Promise { if (this.noneRadioButton.checked) { this.objectInfo.loginAuditing = AuditLevel.None; } if (this.failedLoginsOnlyRadioButton.checked) { this.objectInfo.loginAuditing = AuditLevel.Failure; } if (this.successfulLoginsOnlyRadioButton.checked) { this.objectInfo.loginAuditing = AuditLevel.Success; } if (this.bothFailedAndSuccessfulLoginsRadioButton.checked) { this.objectInfo.loginAuditing = AuditLevel.All; } } private initializeDatabaseSettingsSection(): void { const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance; const dataLocationInputboxProps: azdata.InputBoxProperties = { ariaLabel: localizedConstants.dataLocationText, enabled: isEnabled, value: this.objectInfo.dataLocation, required: true }; const logLocationInputboxProps: azdata.InputBoxProperties = { ariaLabel: localizedConstants.logLocationText, enabled: isEnabled, value: this.objectInfo.logLocation, required: true }; const backupLocationInputboxProps: azdata.InputBoxProperties = { ariaLabel: localizedConstants.backupLocationText, enabled: isEnabled, value: this.objectInfo.backupLocation, required: true }; this.compressBackupCheckbox = this.createCheckbox(localizedConstants.compressBackupText, async (newValue) => { this.objectInfo.checkCompressBackup = newValue; }, this.objectInfo.checkCompressBackup); this.backupChecksumCheckbox = this.createCheckbox(localizedConstants.backupChecksumText, async (newValue) => { this.objectInfo.checkBackupChecksum = newValue; }, this.objectInfo.checkBackupChecksum); const checkBoxContainer = this.createGroup(localizedConstants.backupAndRestoreText, [this.compressBackupCheckbox, this.backupChecksumCheckbox], false); this.dataLocationInput = this.createInputBox(async (newValue) => { this.objectInfo.dataLocation = newValue; if (this.objectInfo.dataLocation !== this.originalObjectInfo.dataLocation) { this.shouldRestartServer = true; } }, dataLocationInputboxProps); const dataLocationButton = this.createBrowseButton(async () => { const newPath = await this.selectFolder(this.objectInfo.dataLocation); if (newPath) { this.dataLocationInput.value = newPath; this.objectInfo.dataLocation = newPath; } if (this.objectInfo.dataLocation !== this.originalObjectInfo.dataLocation) { this.shouldRestartServer = true; } }, isEnabled); const dataLocationInputContainer = this.createLabelInputContainer(localizedConstants.dataLocationText, [this.dataLocationInput, dataLocationButton]) this.logLocationInput = this.createInputBox(async (newValue) => { this.objectInfo.logLocation = newValue; if (this.objectInfo.logLocation !== this.originalObjectInfo.logLocation) { this.shouldRestartServer = true; } }, logLocationInputboxProps); const logLocationButton = this.createBrowseButton(async () => { const newPath = await this.selectFolder(this.objectInfo.logLocation); if (newPath) { this.logLocationInput.value = newPath; this.objectInfo.logLocation = newPath; } if (this.objectInfo.logLocation !== this.originalObjectInfo.logLocation) { this.shouldRestartServer = true; } }, isEnabled); const logLocationInputContainer = this.createLabelInputContainer(localizedConstants.logLocationText, [this.logLocationInput, logLocationButton]) this.backupLocationInput = this.createInputBox(async (newValue) => { this.objectInfo.backupLocation = newValue; }, backupLocationInputboxProps); const backupLocationButton = this.createBrowseButton(async () => { const newPath = await this.selectFolder(this.objectInfo.backupLocation); if (newPath) { this.backupLocationInput.value = newPath; this.objectInfo.backupLocation = newPath; } }, isEnabled); const backupLocationInputContainer = this.createLabelInputContainer(localizedConstants.backupLocationText, [this.backupLocationInput, backupLocationButton]) const defaultLocationsContainer = this.createGroup(localizedConstants.defaultLocationsLabel, [ dataLocationInputContainer, logLocationInputContainer, backupLocationInputContainer ], false); this.databaseSettingsSection = this.createGroup('', [ checkBoxContainer, defaultLocationsContainer ], false); this.databaseSettingsTab = this.createTab(this.databaseSettingsTabId, localizedConstants.databaseSettingsText, this.databaseSettingsSection); } public async selectFolder(location: string): Promise { let dataFolder = await this.objectManagementService.getDataFolder(this.options.connectionUri); return await azdata.window.openServerFileBrowserDialog(this.options.connectionUri, dataFolder, [{ label: localizedConstants.allFiles, filters: ['*'] }], true); } private initializeAdvancedSection(): void { const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance; this.allowTriggerToFireOthersDropdown = this.createDropdown(localizedConstants.allowTriggerToFireOthersLabel, async (newValue) => { this.objectInfo.allowTriggerToFireOthers = newValue === 'True'; }, ['True', 'False'], this.objectInfo.allowTriggerToFireOthers ? 'True' : 'False'); const allowTriggerToFireOthersContainer = this.createLabelInputContainer(localizedConstants.allowTriggerToFireOthersLabel, this.allowTriggerToFireOthersDropdown); this.blockedProcThresholdInput = this.createInputBox(async (newValue) => { this.objectInfo.blockedProcThreshold.value = +newValue; }, { ariaLabel: localizedConstants.blockedProcThresholdLabel, inputType: 'number', min: this.objectInfo.blockedProcThreshold.minimumValue, max: this.objectInfo.blockedProcThreshold.maximumValue, value: this.objectInfo.blockedProcThreshold.value.toString() }); const blockedProcThresholdContainer = this.createLabelInputContainer(localizedConstants.blockedProcThresholdLabel, this.blockedProcThresholdInput); this.cursorThresholdInput = this.createInputBox(async (newValue) => { this.objectInfo.cursorThreshold.value = +newValue; }, { ariaLabel: localizedConstants.cursorThresholdLabel, inputType: 'number', min: this.objectInfo.cursorThreshold.minimumValue, max: this.objectInfo.cursorThreshold.maximumValue, value: this.objectInfo.cursorThreshold.value.toString() }); const cursorThresholdContainer = this.createLabelInputContainer(localizedConstants.cursorThresholdLabel, this.cursorThresholdInput); this.defaultFullTextLanguageInput = this.createInputBox(async (newValue) => { this.objectInfo.defaultFullTextLanguage = newValue; }, { ariaLabel: localizedConstants.defaultFullTextLanguageLabel, value: this.objectInfo.defaultFullTextLanguage }); const defaultFullTextLanguageContainer = this.createLabelInputContainer(localizedConstants.defaultFullTextLanguageLabel, this.defaultFullTextLanguageInput); this.defaultLanguageDropdown = this.createDropdown(localizedConstants.defaultLanguageLabel, async (newValue) => { this.objectInfo.defaultLanguage = newValue; }, this.viewInfo.languageOptions, this.objectInfo.defaultLanguage); const defaultLanguageContainer = this.createLabelInputContainer(localizedConstants.defaultLanguageLabel, this.defaultLanguageDropdown); this.fullTextUpgradeOptionDropdown = this.createDropdown(localizedConstants.fullTextUpgradeOptionLabel, async (newValue) => { this.objectInfo.fullTextUpgradeOption = newValue; }, this.viewInfo.fullTextUpgradeOptions, this.objectInfo.fullTextUpgradeOption, !!this.objectInfo.fullTextUpgradeOption); const fullTextUpgradeOptionContainer = this.createLabelInputContainer(localizedConstants.fullTextUpgradeOptionLabel, this.fullTextUpgradeOptionDropdown); this.maxTextReplicationSizeInput = this.createInputBox(async (newValue) => { this.objectInfo.maxTextReplicationSize.value = +newValue; }, { ariaLabel: localizedConstants.maxTextReplicationSizeLabel, inputType: 'number', min: this.objectInfo.maxTextReplicationSize.minimumValue, max: this.objectInfo.maxTextReplicationSize.maximumValue, value: this.objectInfo.maxTextReplicationSize.value.toString() }); const maxTextReplicationSizeContainer = this.createLabelInputContainer(localizedConstants.maxTextReplicationSizeLabel, this.maxTextReplicationSizeInput); this.optimizeAdHocWorkloadsDropdown = this.createDropdown(localizedConstants.optimizeAdHocWorkloadsLabel, async (newValue) => { this.objectInfo.optimizeAdHocWorkloads = newValue === 'True'; }, ['True', 'False'], this.objectInfo.optimizeAdHocWorkloads ? 'True' : 'False'); const optimizeAdHocWorkloadsContainer = this.createLabelInputContainer(localizedConstants.optimizeAdHocWorkloadsLabel, this.optimizeAdHocWorkloadsDropdown); this.scanStartupProcsDropdown = this.createDropdown(localizedConstants.scanStartupProcsLabel, async (newValue) => { this.objectInfo.scanStartupProcs = newValue === 'True'; }, ['True', 'False'], this.objectInfo.scanStartupProcs ? 'True' : 'False', isEnabled); const scanStartupProcsContainer = this.createLabelInputContainer(localizedConstants.scanStartupProcsLabel, this.scanStartupProcsDropdown); this.twoDigitYearCutoffInput = this.createInputBox(async (newValue) => { this.objectInfo.twoDigitYearCutoff = +newValue; }, { ariaLabel: localizedConstants.twoDigitYearCutoffLabel, inputType: 'number', value: this.objectInfo.twoDigitYearCutoff.toString() }); const twoDigitYearCutoffContainer = this.createLabelInputContainer(localizedConstants.twoDigitYearCutoffLabel, this.twoDigitYearCutoffInput); this.costThresholdParallelismInput = this.createInputBox(async (newValue) => { this.objectInfo.costThresholdParallelism.value = +newValue; }, { ariaLabel: localizedConstants.costThresholdParallelismLabel, inputType: 'number', min: this.objectInfo.costThresholdParallelism.minimumValue, max: this.objectInfo.costThresholdParallelism.maximumValue, value: this.objectInfo.costThresholdParallelism.value.toString() }); const costThresholdParallelismContainer = this.createLabelInputContainer(localizedConstants.costThresholdParallelismLabel, this.costThresholdParallelismInput); this.locksInput = this.createInputBox(async (newValue) => { this.objectInfo.locks.value = +newValue; }, { ariaLabel: localizedConstants.locksLabel, inputType: 'number', enabled: isEnabled, max: this.objectInfo.locks.maximumValue, min: 0, value: this.objectInfo.locks.value.toString(), validationErrorMessage: localizedConstants.locksValidation(this.objectInfo.locks.minimumValue) }, async () => { return !(+this.locksInput.value < this.objectInfo.locks.minimumValue && +this.locksInput.value !== 0); }); const locksContainer = this.createLabelInputContainer(localizedConstants.locksLabel, this.locksInput); this.maxDegreeParallelismInput = this.createInputBox(async (newValue) => { this.objectInfo.maxDegreeParallelism.value = +newValue; }, { ariaLabel: localizedConstants.maxDegreeParallelismLabel, inputType: 'number', min: this.objectInfo.maxDegreeParallelism.minimumValue, max: this.objectInfo.maxDegreeParallelism.maximumValue, value: this.objectInfo.maxDegreeParallelism.value.toString() }); const maxDegreeParallelismContainer = this.createLabelInputContainer(localizedConstants.maxDegreeParallelismLabel, this.maxDegreeParallelismInput); this.queryWaitInput = this.createInputBox(async (newValue) => { this.objectInfo.queryWait.value = +newValue; }, { ariaLabel: localizedConstants.queryWaitLabel, inputType: 'number', min: this.objectInfo.queryWait.minimumValue, max: this.objectInfo.queryWait.maximumValue, value: this.objectInfo.queryWait.value.toString() }); const queryWaitContainer = this.createLabelInputContainer(localizedConstants.queryWaitLabel, this.queryWaitInput); const miscellaneousSection = this.createGroup('Miscellaneous', [ allowTriggerToFireOthersContainer, blockedProcThresholdContainer, cursorThresholdContainer, defaultFullTextLanguageContainer, defaultLanguageContainer, fullTextUpgradeOptionContainer, maxTextReplicationSizeContainer, optimizeAdHocWorkloadsContainer, scanStartupProcsContainer, twoDigitYearCutoffContainer ], true); const parallelismSection = this.createGroup('Parallelism', [ costThresholdParallelismContainer, locksContainer, maxDegreeParallelismContainer, queryWaitContainer ], true); const advancedTabContainer = this.createGroup('', [miscellaneousSection, parallelismSection]) this.advancedTab = this.createTab(this.advancedTabId, localizedConstants.AdvancedSectionHeader, advancedTabContainer); } }