Skip to content

Commit

Permalink
Database properties options fixes (#24361)
Browse files Browse the repository at this point in the history
* fix for File size input in DB properties can be decremented into the negative #24307

* Some DB Scoped Config options are sentence cased #24196

* cannot add a file with filestream data filegroup type #24359

* DB Scoped Secondary values aren't updated when hidden #24197

* DB Scoped Config shows secondary values for non-secondary options #24192

* Query store capture policy section is enabling on non-custom capture mode #24371

* queryStore WaitStatistics options should be a dropdown #24372
  • Loading branch information
ssreerama authored and siyangMicrosoft committed Oct 12, 2023
1 parent 8043572 commit e9b6d1b
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 29 deletions.
4 changes: 2 additions & 2 deletions extensions/mssql/src/objectManagement/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ export interface DatabaseViewInfo extends ObjectManagement.ObjectViewInfo<Databa
azureMaxSizes?: AzureEditionDetails[];
pageVerifyOptions?: string[];
restrictAccessOptions?: string[];
dscOnOffOptions?: string[];
propertiesOnOffOptions?: string[];
dscElevateOptions?: string[];
dscEnableDisableOptions?: string[];
rowDataFileGroupsOptions?: string[];
Expand All @@ -498,7 +498,7 @@ export interface QueryStoreOptions {
queryStoreCaptureMode: string;
sizeBasedCleanupMode: string;
staleQueryThresholdInDays: number;
waitStatisticsCaptureMode?: boolean;
waitStatisticsCaptureMode?: string;
capturePolicyOptions?: QueryStoreCapturePolicyOptions;
currentStorageSizeInMB: number;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ export const QueryStoreUsedText = localize('objectManagement.databaseProperties.
export const QueryStoreAvailableText = localize('objectManagement.databaseProperties.queryStoreAvailableText', "Query Store Available");
export const PurgeQueryDataButtonText = localize('objectManagement.databaseProperties.purgeQueryDataButtonText', "Purge Query Store Data");
export const YesText = localize('objectManagement.databaseProperties.yesText', "Yes");
export const NotAvailableText = localize('objectManagement.databaseProperties.notAvailableText', "N/A");
export const PurgeQueryStoreDataMessage = (databaseName: string) => localize('objectManagement.databaseProperties.purgeQueryStoreDataMessage', "Are you sure you want to purge the Query Store data from '{0}'?", databaseName);

// Util functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ export class TestObjectManagementService implements IObjectManagementService {
pageVerifyOptions: ['CHECKSUM', 'NONE', 'TORN_PAGE_DETECTION'],
dscElevateOptions: ['OFF', 'WHEN_SUPPORTED', 'FAIL_UNSUPPORTED'],
dscEnableDisableOptions: ['ENABLED', 'DISABLED'],
dscOnOffOptions: ['ON', 'OFF'],
propertiesOnOffOptions: ['ON', 'OFF'],
rowDataFileGroupsOptions: ['PRIMARY', 'RowDataGroup1', 'RowDataGroup2'],
fileStreamFileGroupsOptions: ['PRIMARY', 'FileStreamGroup1', 'FileStreamGroup2'],
fileTypesOptions: ['ROWS', 'LOG', 'FILESTREAM'],
Expand Down
46 changes: 23 additions & 23 deletions extensions/mssql/src/objectManagement/ui/databaseDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { CreateDatabaseDocUrl, DatabaseGeneralPropertiesDocUrl, DatabaseFilesPro
import { Database, DatabaseFile, DatabaseScopedConfigurationsInfo, DatabaseViewInfo, FileGrowthType, FileGroup, FileGroupType } from '../interfaces';
import { convertNumToTwoDecimalStringInMB } from '../utils';
import { isUndefinedOrNull } from '../../types';
import { deepClone } from '../../util/objects';
import { DatabaseFileDialog } from './databaseFileDialog';
import * as vscode from 'vscode';

Expand Down Expand Up @@ -82,7 +81,6 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
private readonly dscTabId: string = 'dscDatabaseId';
private dscTabSectionsContainer: azdata.Component[] = [];
private dscTable: azdata.TableComponent;
private dscOriginalData: DatabaseScopedConfigurationsInfo[];
private currentRowId: number;
private valueForPrimaryDropdown: azdata.DropDownComponent;
private valueForSecondaryDropdown: azdata.DropDownComponent;
Expand Down Expand Up @@ -110,7 +108,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
private queryStoreCaptureMode: azdata.DropDownComponent;
private sizeBasedCleanupMode: azdata.DropDownComponent;
private stateQueryThresholdInDays: azdata.InputBoxComponent;
private waitStatisticsCaptureMode: azdata.CheckBoxComponent;
private waitStatisticsCaptureMode: azdata.DropDownComponent;
private executionCount: azdata.InputBoxComponent;
private staleThreshold: azdata.DropDownComponent;
private totalCompileCPUTimeInMS: azdata.InputBoxComponent;
Expand Down Expand Up @@ -1297,7 +1295,8 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas

//#region Database Properties - Data Scoped configurations Tab
private async initializeDatabaseScopedConfigurationSection(): Promise<void> {
this.dscOriginalData = deepClone(this.objectInfo.databaseScopedConfigurations);
// Configurations that doesn't support secondary replica
let secondaryUnsupportedConfigsSet = new Set<number>([11, 12, 25, 6, 21]);
const dscNameColumn: azdata.TableColumn = {
type: azdata.ColumnType.text,
value: localizedConstants.DatabaseScopedOptionsColumnHeader,
Expand All @@ -1317,9 +1316,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
this.dscTable = this.modelView.modelBuilder.table().withProps({
columns: [dscNameColumn, primaryValueColumn, secondaryValueColumn],
data: this.objectInfo.databaseScopedConfigurations.map(metaData => {
return [metaData.name,
return [metaData.name.toLocaleUpperCase(),
metaData.valueForPrimary,
metaData.valueForSecondary]
secondaryUnsupportedConfigsSet.has(metaData.id) ? localizedConstants.NotAvailableText : metaData.valueForSecondary]
}),
height: getTableHeight(this.objectInfo.databaseScopedConfigurations.length, 1, DscTableRowLength),
width: DefaultTableWidth
Expand Down Expand Up @@ -1387,18 +1386,18 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Can only set OFF/Azure blob storage endpoint to the 'LEDGER_DIGEST_STORAGE_ENDPOINT (38)'s primary and secondary values
else if (this.currentRowObjectInfo.id === 38) {
await this.showDropdownsSection(isSecondaryCheckboxChecked);
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify([this.viewInfo.dscOnOffOptions[1]]) ||
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify([this.viewInfo.propertiesOnOffOptions[1]]) ||
this.valueForPrimaryDropdown.value !== this.currentRowObjectInfo.valueForPrimary) {
await this.valueForPrimaryDropdown.updateProperties({
values: [this.viewInfo.dscOnOffOptions[1]] // Only OFF is allowed for primary value
values: [this.viewInfo.propertiesOnOffOptions[1]] // Only OFF is allowed for primary value
, value: this.currentRowObjectInfo.valueForPrimary
, editable: true // This is to allow the user to enter the Azure blob storage endpoint
});
}
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify([this.viewInfo.dscOnOffOptions[1]]) ||
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify([this.viewInfo.propertiesOnOffOptions[1]]) ||
this.valueForSecondaryDropdown.value !== this.currentRowObjectInfo.valueForSecondary) {
await this.valueForSecondaryDropdown.updateProperties({
values: [this.viewInfo.dscOnOffOptions[1]] // Only OFF is allowed for secondary value
values: [this.viewInfo.propertiesOnOffOptions[1]] // Only OFF is allowed for secondary value
, value: this.currentRowObjectInfo.valueForSecondary
, editable: true // This is to allow the user to enter the Azure blob storage endpoint
});
Expand All @@ -1408,10 +1407,10 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Cannot set the 'GLOBAL_TEMPORARY_TABLE_AUTO_DROP (21)' option for the secondaries replica while this option is only allowed to be set for the primary.
else if (this.currentRowObjectInfo.id === 6 || this.currentRowObjectInfo.id === 21) {
await this.dscPrimaryValueDropdownGroup.updateCssStyles({ 'visibility': 'visible' });
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.dscOnOffOptions) ||
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.propertiesOnOffOptions) ||
this.valueForPrimaryDropdown.value !== this.currentRowObjectInfo.valueForPrimary) {
await this.valueForPrimaryDropdown.updateProperties({
values: this.viewInfo.dscOnOffOptions
values: this.viewInfo.propertiesOnOffOptions
, value: this.currentRowObjectInfo.valueForPrimary
});
}
Expand All @@ -1437,17 +1436,17 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// All other options accepts primary and seconday values as ON/OFF/PRIMARY(only secondary)
else {
await this.showDropdownsSection(isSecondaryCheckboxChecked);
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.dscOnOffOptions) ||
if (JSON.stringify(this.valueForPrimaryDropdown.values) !== JSON.stringify(this.viewInfo.propertiesOnOffOptions) ||
this.valueForPrimaryDropdown.value !== this.currentRowObjectInfo.valueForPrimary) {
await this.valueForPrimaryDropdown.updateProperties({
values: this.viewInfo.dscOnOffOptions
values: this.viewInfo.propertiesOnOffOptions
, value: this.currentRowObjectInfo.valueForPrimary
});
}
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify(this.viewInfo.dscOnOffOptions) ||
if (JSON.stringify(this.valueForSecondaryDropdown.values) !== JSON.stringify(this.viewInfo.propertiesOnOffOptions) ||
this.valueForSecondaryDropdown.value !== this.currentRowObjectInfo.valueForSecondary) {
await this.valueForSecondaryDropdown.updateProperties({
values: this.viewInfo.dscOnOffOptions
values: this.viewInfo.propertiesOnOffOptions
, value: this.currentRowObjectInfo.valueForSecondary
});
}
Expand Down Expand Up @@ -1488,7 +1487,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Apply Primary To Secondary checkbox
this.setSecondaryCheckboxForInputType = this.createCheckbox(localizedConstants.SetSecondaryText, async (checked) => {
await this.dscSecondaryValueInputGroup.updateCssStyles({ 'visibility': checked ? 'hidden' : 'visible' });
this.currentRowObjectInfo.valueForSecondary = checked ? this.currentRowObjectInfo.valueForPrimary : this.dscOriginalData[this.currentRowId].valueForSecondary;
this.currentRowObjectInfo.valueForSecondary = this.currentRowObjectInfo.valueForPrimary;
await this.valueForSecondaryInput.updateProperties({ value: this.currentRowObjectInfo.valueForSecondary });
if (this.dscTable.data[this.currentRowId][2] !== this.currentRowObjectInfo.valueForSecondary) {
this.dscTable.data[this.currentRowId][2] = this.currentRowObjectInfo.valueForSecondary;
Expand Down Expand Up @@ -1550,7 +1549,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
// Apply Primary To Secondary checkbox
this.setSecondaryCheckboxForDropdowns = this.createCheckbox(localizedConstants.SetSecondaryText, async (checked) => {
await this.dscSecondaryValueDropdownGroup.updateCssStyles({ 'visibility': checked ? 'hidden' : 'visible' });
this.currentRowObjectInfo.valueForSecondary = checked ? this.currentRowObjectInfo.valueForPrimary : this.dscOriginalData[this.currentRowId].valueForSecondary;
this.currentRowObjectInfo.valueForSecondary = this.currentRowObjectInfo.valueForPrimary;
await this.valueForSecondaryDropdown.updateProperties({ value: this.currentRowObjectInfo.valueForSecondary });
}, true);
this.dscSecondaryCheckboxForDropdownGroup = this.createGroup('', [this.setSecondaryCheckboxForDropdowns], false, true);
Expand Down Expand Up @@ -1727,10 +1726,10 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas

// Wait Statistics Capture Mode - supported from 2017 or higher
if (!isUndefinedOrNull(this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode)) {
this.waitStatisticsCaptureMode = this.createCheckbox(localizedConstants.WaitStatisticsCaptureModeText, async (checked) => {
this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode = checked;
}, this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode, this.areQueryStoreOptionsEnabled);
containers.push(this.waitStatisticsCaptureMode);
this.waitStatisticsCaptureMode = this.createDropdown(localizedConstants.WaitStatisticsCaptureModeText, async (newValue) => {
this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode = newValue as string;
}, this.viewInfo.propertiesOnOffOptions, this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode.toUpperCase(), this.areQueryStoreOptionsEnabled, DefaultInputWidth);
containers.push(this.createLabelInputContainer(localizedConstants.WaitStatisticsCaptureModeText, this.waitStatisticsCaptureMode));
}
const retentionSection = this.createGroup(localizedConstants.WaitStatisticsCaptureModeText, containers, true);
this.queryStoreTabSectionsContainer.push(retentionSection);
Expand Down Expand Up @@ -1848,7 +1847,8 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
if (!isUndefinedOrNull(this.objectInfo.queryStoreOptions.waitStatisticsCaptureMode)) {
this.waitStatisticsCaptureMode.enabled = this.areQueryStoreOptionsEnabled
}
await this.toggleQueryCapturePolicySection(this.areQueryStoreOptionsEnabled);
await this.toggleQueryCapturePolicySection(this.areQueryStoreOptionsEnabled &&
this.queryStoreCaptureMode.value === localizedConstants.QueryStoreCapturemodeCustomText);
}

private async toggleQueryCapturePolicySection(enable: boolean): Promise<void> {
Expand Down
10 changes: 7 additions & 3 deletions extensions/mssql/src/objectManagement/ui/databaseFileDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
errors.push(localizedConstants.FileNameExistsError(this.result.name.trim()));
}
// If new file, verify if the file name with extension already exists
if (this.options.isNewFile && !!this.options.files.find(file => { return (path.join(file.path, file.fileNameWithExtension) === path.join(this.result.path, this.result.fileNameWithExtension)) })) {
if (this.options.isNewFile && !!this.options.files.find(file => {
return (this.result.name === file.name &&
path.join(file.path, file.fileNameWithExtension) === path.join(this.result.path, this.result.fileNameWithExtension))
})) {
errors.push(localizedConstants.FileAlreadyExistsError(path.join(this.result.path, this.result.fileNameWithExtension)));
}
}
Expand Down Expand Up @@ -157,7 +160,8 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
ariaLabel: localizedConstants.SizeInMbText,
inputType: 'number',
enabled: this.options.databaseFile.type !== localizedConstants.FilestreamFileType,
value: String(this.options.databaseFile.sizeInMb)
value: String(this.options.databaseFile.sizeInMb),
min: 1
});
const fileSizeContainer = this.createLabelInputContainer(localizedConstants.SizeInMbText, this.fileSizeInput);
containers.push(fileSizeContainer);
Expand Down Expand Up @@ -332,7 +336,7 @@ export class DatabaseFileDialog extends DialogBase<DatabaseFile> {
}
// File Stream
else if (selectedOption === localizedConstants.FilestreamFileType) {
fileGroupDdOptions = this.options.filestreamFilegroups;
fileGroupDdOptions = this.options.filestreamFilegroups.length > 0 ? this.options.filestreamFilegroups : [localizedConstants.FileGroupForFilestreamTypeText];
fileGroupDdValue = this.result.fileGroup;
visibility = 'hidden';
maxSizeGroupMarginTop = '-130px';
Expand Down

0 comments on commit e9b6d1b

Please sign in to comment.