Server properties fixes (#23667)

* server properties fixes
This commit is contained in:
Barbara Valdez
2023-07-06 12:58:01 -07:00
committed by GitHub
parent 3b3ef7bf6c
commit 32356cabc5
7 changed files with 62 additions and 17 deletions

View File

@@ -15,7 +15,7 @@ import * as uiLoc from '../ui/localizedConstants';
import { UserDialog } from './ui/userDialog'; import { UserDialog } from './ui/userDialog';
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as constants from '../constants'; import * as constants from '../constants';
import { refreshParentNode } from './utils'; import { refreshParentNode, escapeSingleQuotes } from './utils';
import { TelemetryReporter } from '../telemetry'; import { TelemetryReporter } from '../telemetry';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './ui/objectManagementDialogBase'; import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './ui/objectManagementDialogBase';
import { ServerRoleDialog } from './ui/serverRoleDialog'; import { ServerRoleDialog } from './ui/serverRoleDialog';
@@ -113,8 +113,8 @@ async function handleObjectPropertiesDialogCommand(context: azdata.ObjectExplore
try { try {
const parentUrn = context.nodeInfo ? await getParentUrn(context) : undefined; const parentUrn = context.nodeInfo ? await getParentUrn(context) : undefined;
const objectType = context.nodeInfo ? context.nodeInfo.nodeType as ObjectManagement.NodeType : (context.connectionProfile.databaseName === '' ? ObjectManagement.NodeType.Server : ObjectManagement.NodeType.Database); const objectType = context.nodeInfo ? context.nodeInfo.nodeType as ObjectManagement.NodeType : (context.connectionProfile.databaseName === '' ? ObjectManagement.NodeType.Server : ObjectManagement.NodeType.Database);
const objectName = context.nodeInfo ? context.nodeInfo.label : objectManagementLoc.PropertiesHeader; const objectName = context.nodeInfo ? context.nodeInfo.label : (!context.connectionProfile.databaseName ? context.connectionProfile.serverName : context.connectionProfile.databaseName);
const objectUrn = context.nodeInfo ? context.nodeInfo!.metadata!.urn : undefined; const objectUrn = context.nodeInfo ? context.nodeInfo!.metadata!.urn : (context.connectionProfile.databaseName === '' ? 'Server' : `Server/Database[@Name='${escapeSingleQuotes(context.connectionProfile.databaseName)}']`);
const options: ObjectManagementDialogOptions = { const options: ObjectManagementDialogOptions = {
connectionUri: connectionUri, connectionUri: connectionUri,

View File

@@ -43,5 +43,3 @@ export const enum TelemetryActions {
} }
export const ObjectManagementViewName = 'ObjectManagement'; export const ObjectManagementViewName = 'ObjectManagement';
export const AzureSQLMI = 'Azure SQL Database Managed Instance';

View File

@@ -482,7 +482,7 @@ export interface Server extends ObjectManagement.SqlObject {
rootDirectory: string; rootDirectory: string;
serverCollation: string; serverCollation: string;
serviceTier: string; serviceTier: string;
storageSpaceUsageInGB: number; storageSpaceUsageInMB: number;
minServerMemory: number; minServerMemory: number;
maxServerMemory: number; maxServerMemory: number;
} }

View File

@@ -252,11 +252,11 @@ export const IsHadrEnabledText = localize('objectManagement.isHadrEnabled', "Is
export const IsPolyBaseInstalledText = localize('objectManagement.isPolyBaseInstalled', "Is PolyBase Installed"); export const IsPolyBaseInstalledText = localize('objectManagement.isPolyBaseInstalled', "Is PolyBase Installed");
export const IsXTPSupportedText = localize('objectManagement.isXTPSupported', "Is XTP Supported"); export const IsXTPSupportedText = localize('objectManagement.isXTPSupported', "Is XTP Supported");
export const ProductText = localize('objectManagement.product', "Product"); export const ProductText = localize('objectManagement.product', "Product");
export const ReservedStorageSizeInMBText = localize('objectManagement.reservedStorageSizeInMB', "Reserved Storage Size"); export const ReservedStorageSizeInMBText = localize('objectManagement.reservedStorageSizeInMB', "Reserved Storage Size (MB)");
export const RootDirectoryText = localize('objectManagement.rootDirectory', "Root Directory"); export const RootDirectoryText = localize('objectManagement.rootDirectory', "Root Directory");
export const ServerCollationText = localize('objectManagement.serverCollation', "Server Collation"); export const ServerCollationText = localize('objectManagement.serverCollation', "Server Collation");
export const ServiceTierText = localize('objectManagement.serviceTier', "Service Tier"); export const ServiceTierText = localize('objectManagement.serviceTier', "Service Tier");
export const StorageSpaceUsageInGBText = localize('objectManagement.storageSpaceUsageInGB', "Storage Space Usage"); export const StorageSpaceUsageInMBText = localize('objectManagement.storageSpaceUsageInMB', "Storage Space Usage (MB)");
export const VersionText = localize('objectManagement.versionText', "Version"); export const VersionText = localize('objectManagement.versionText', "Version");

View File

@@ -6,7 +6,7 @@ import * as azdata from 'azdata';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService } from 'mssql'; import { IObjectManagementService } from 'mssql';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { AzureSQLMI, ViewServerPropertiesDocUrl } from '../constants'; import { ViewServerPropertiesDocUrl } from '../constants';
import { Server, ServerViewInfo } from '../interfaces'; import { Server, ServerViewInfo } from '../interfaces';
export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, ServerViewInfo> { export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, ServerViewInfo> {
@@ -29,23 +29,32 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
private rootDirectoryInput: azdata.InputBoxComponent; private rootDirectoryInput: azdata.InputBoxComponent;
private serverCollationInput: azdata.InputBoxComponent; private serverCollationInput: azdata.InputBoxComponent;
private serviceTierInput: azdata.InputBoxComponent; private serviceTierInput: azdata.InputBoxComponent;
private storageSpaceUsageInGBInput: azdata.InputBoxComponent; private storageSpaceUsageInMBInput: azdata.InputBoxComponent;
private versionInput: azdata.InputBoxComponent; private versionInput: azdata.InputBoxComponent;
private memoryTab: azdata.Tab; private memoryTab: azdata.Tab;
private memorySection: azdata.GroupContainer; private memorySection: azdata.GroupContainer;
private minServerMemoryInput: azdata.InputBoxComponent; private minServerMemoryInput: azdata.InputBoxComponent;
private maxServerMemoryInput: azdata.InputBoxComponent; private maxServerMemoryInput: azdata.InputBoxComponent;
private engineEdition: azdata.DatabaseEngineEdition;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) { constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
super(objectManagementService, options); super(objectManagementService, options);
this.dialogObject.customButtons[1].enabled = false;
} }
protected override get helpUrl(): string { protected override get helpUrl(): string {
return ViewServerPropertiesDocUrl; return ViewServerPropertiesDocUrl;
} }
protected override onFormFieldChange(): void {
this.dialogObject.customButtons[1].enabled = false;
this.dialogObject.okButton.enabled = this.isDirty;
}
protected async initializeUI(): Promise<void> { protected async initializeUI(): Promise<void> {
const serverInfo = await azdata.connection.getServerInfo(this.options.objectExplorerContext.connectionProfile.id);
this.engineEdition = serverInfo.engineEditionId;
this.initializeGeneralSection(); this.initializeGeneralSection();
this.initializeMemorySection(); this.initializeMemorySection();
const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab] }; const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab] };
@@ -98,7 +107,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
this.productInput = this.createInputBox(localizedConstants.ProductText, async () => { }, this.objectInfo.product, this.options.isNewObject); this.productInput = this.createInputBox(localizedConstants.ProductText, async () => { }, this.objectInfo.product, this.options.isNewObject);
const productContainer = this.createLabelInputContainer(localizedConstants.ProductText, this.productInput); const productContainer = this.createLabelInputContainer(localizedConstants.ProductText, this.productInput);
this.reservedStorageSizeInMBInput = this.createInputBox(localizedConstants.ReservedStorageSizeInMBText, async () => { }, this.objectInfo.reservedStorageSizeMB.toString().concat(' MB'), this.options.isNewObject); this.reservedStorageSizeInMBInput = this.createInputBox(localizedConstants.ReservedStorageSizeInMBText, async () => { }, localizedConstants.StringValueInMB(this.objectInfo.reservedStorageSizeMB.toString()), this.options.isNewObject);
const reservedStorageSizeInMBContainer = this.createLabelInputContainer(localizedConstants.ReservedStorageSizeInMBText, this.reservedStorageSizeInMBInput); const reservedStorageSizeInMBContainer = this.createLabelInputContainer(localizedConstants.ReservedStorageSizeInMBText, this.reservedStorageSizeInMBInput);
this.rootDirectoryInput = this.createInputBox(localizedConstants.RootDirectoryText, async () => { }, this.objectInfo.rootDirectory, this.options.isNewObject); this.rootDirectoryInput = this.createInputBox(localizedConstants.RootDirectoryText, async () => { }, this.objectInfo.rootDirectory, this.options.isNewObject);
@@ -110,8 +119,8 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
this.serviceTierInput = this.createInputBox(localizedConstants.ServiceTierText, async () => { }, this.objectInfo.serviceTier, this.options.isNewObject); this.serviceTierInput = this.createInputBox(localizedConstants.ServiceTierText, async () => { }, this.objectInfo.serviceTier, this.options.isNewObject);
const serviceTierContainer = this.createLabelInputContainer(localizedConstants.ServiceTierText, this.serviceTierInput); const serviceTierContainer = this.createLabelInputContainer(localizedConstants.ServiceTierText, this.serviceTierInput);
this.storageSpaceUsageInGBInput = this.createInputBox(localizedConstants.StorageSpaceUsageInGBText, async () => { }, this.objectInfo.storageSpaceUsageInGB.toString().concat(' GB'), this.options.isNewObject); this.storageSpaceUsageInMBInput = this.createInputBox(localizedConstants.StorageSpaceUsageInMBText, async () => { }, localizedConstants.StringValueInMB(this.objectInfo.storageSpaceUsageInMB.toString()), this.options.isNewObject);
const storageSpaceUsageInGbContainer = this.createLabelInputContainer(localizedConstants.StorageSpaceUsageInGBText, this.storageSpaceUsageInGBInput); const storageSpaceUsageInMbContainer = this.createLabelInputContainer(localizedConstants.StorageSpaceUsageInMBText, this.storageSpaceUsageInMBInput);
this.versionInput = this.createInputBox(localizedConstants.VersionText, async () => { }, this.objectInfo.version, this.options.isNewObject); this.versionInput = this.createInputBox(localizedConstants.VersionText, async () => { }, this.objectInfo.version, this.options.isNewObject);
const versionContainer = this.createLabelInputContainer(localizedConstants.VersionText, this.versionInput); const versionContainer = this.createLabelInputContainer(localizedConstants.VersionText, this.versionInput);
@@ -136,9 +145,9 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
versionContainer versionContainer
]; ];
if (this.objectInfo.platform === AzureSQLMI) { if (this.engineEdition === azdata.DatabaseEngineEdition.SqlManagedInstance) {
platformItems.unshift(hardwareGenerationContainer); platformItems.unshift(hardwareGenerationContainer);
sqlServerItems.push(reservedStorageSizeInMBContainer, serviceTierContainer, storageSpaceUsageInGbContainer); sqlServerItems.push(reservedStorageSizeInMBContainer, serviceTierContainer, storageSpaceUsageInMbContainer);
// remove isXTPSupported // remove isXTPSupported
sqlServerItems.splice(3, 1); sqlServerItems.splice(3, 1);
} }
@@ -152,14 +161,15 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
} }
private initializeMemorySection(): void { private initializeMemorySection(): void {
const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance;
this.minServerMemoryInput = this.createInputBox(localizedConstants.minServerMemoryText, async (newValue) => { this.minServerMemoryInput = this.createInputBox(localizedConstants.minServerMemoryText, async (newValue) => {
this.objectInfo.minServerMemory = +newValue; this.objectInfo.minServerMemory = +newValue;
}, this.objectInfo.minServerMemory.toString(), true, 'number'); }, this.objectInfo.minServerMemory.toString(), isEnabled, 'number');
const minMemoryContainer = this.createLabelInputContainer(localizedConstants.minServerMemoryText, this.minServerMemoryInput); const minMemoryContainer = this.createLabelInputContainer(localizedConstants.minServerMemoryText, this.minServerMemoryInput);
this.maxServerMemoryInput = this.createInputBox(localizedConstants.maxServerMemoryText, async (newValue) => { this.maxServerMemoryInput = this.createInputBox(localizedConstants.maxServerMemoryText, async (newValue) => {
this.objectInfo.maxServerMemory = +newValue; this.objectInfo.maxServerMemory = +newValue;
}, this.objectInfo.maxServerMemory.toString(), true, 'number'); }, this.objectInfo.maxServerMemory.toString(), isEnabled, 'number');
const maxMemoryContainer = this.createLabelInputContainer(localizedConstants.maxServerMemoryText, this.maxServerMemoryInput); const maxMemoryContainer = this.createLabelInputContainer(localizedConstants.maxServerMemoryText, this.maxServerMemoryInput);
this.memorySection = this.createGroup('', [ this.memorySection = this.createGroup('', [

View File

@@ -47,3 +47,8 @@ export function isValidSQLPassword(password: string, userName: string = 'sa'): b
export function convertNumToTwoDecimalStringinMB(value: number): string { export function convertNumToTwoDecimalStringinMB(value: number): string {
return localizedConstants.StringValueInMB(value?.toFixed(2)); return localizedConstants.StringValueInMB(value?.toFixed(2));
} }
// Escape single quotes
export function escapeSingleQuotes(value: string): string {
return value.replace(/'/g, "\'");
}

View File

@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { escapeSingleQuotes } from '../../objectManagement/utils';
import 'mocha';
import * as should from 'should';
describe('escapeSingleQuotes Method Tests', () => {
it('Should return original string if no single quotes', function (): void {
const dbName = "My Database";
const testString: string = "Server/Database[@Name='My Database']";
const ret = `Server/Database[@Name='${escapeSingleQuotes(dbName)}']`;
should(ret).equal(testString);
});
it('Should return original string if it contains single quotes', function (): void {
const dbName = "My'Database";
const testString: string = "Server/Database[@Name='My'Database']";
const ret = `Server/Database[@Name='${escapeSingleQuotes(dbName)}']`;
should(ret).equal(testString);
});
it('Should return escaped original string if it contains an escaped single quote', function (): void {
const dbName = "My Database\'WithEscapedSingleQuote";
const testString: string = "Server/Database[@Name='My Database\'WithEscapedSingleQuote']";
const ret = `Server/Database[@Name='${escapeSingleQuotes(dbName)}']`;
should(ret).equal(testString);
});
});