Enabling options tab for database properties (#23448)

* Initial commit for adding a basic general tab for the database properties

* Refactoring for dialog inputs

* removed properties nodeType and using database node and additional cleanup, diabling the functionality.

* Changes according to STS data fetch

* Reuse database Dialog

* Undo contract file change

* more refactoring

* fetched scrollbar fix into this PR

* Tabbed panel is being used for horizontal tabs

* stying fix for general tab button

* final commit for today :)

* Updates according to STS changes

* missed updates

* Refactored updates

* moved options as discussed and added collapsible sections... need to fix scroll bar

* Fixing the horizontal scroll bar of tabbedpanel

* initial updates

* need to fix the error!

* rror fixed and options are loading with sample values

* need to load real values for all felds and map values to dropdown options

* Dd loading correctly, need to add validation to recovery field and save options back

* refactor

* removing nullable property

* All changes done except recoveryTime validation

* Refactoring

* all values are saving as expected, isDirty flag is fixed. Todo: recovery validation and tests

* added general section for the options tab

* modifying pageVerify and userAccess to string array

* updates to general section of options tb

* disabling couple of general properties for MI

* Adding server edition conditions and toggling the UI options

* adding numeric validation to the recovey time

* Removing serveInfo logic and using the unsupported options approach from STS

* addressing comments and little code refactor

* changes with nullOrUndefined helper method

* replacing dropdowns with checkboxes

* adding unit test for helper method

* removed commented sample code and added comments
This commit is contained in:
Sai Avishkar Sreerama
2023-07-06 19:22:20 -04:00
committed by GitHub
parent 1bc22d896b
commit acfa93fbb8
6 changed files with 246 additions and 15 deletions

View File

@@ -9,13 +9,17 @@ import { IObjectManagementService } from 'mssql';
import * as localizedConstants from '../localizedConstants';
import { CreateDatabaseDocUrl, DatabasePropertiesDocUrl } from '../constants';
import { Database, DatabaseViewInfo } from '../interfaces';
import { convertNumToTwoDecimalStringinMB } from '../utils';
import { convertNumToTwoDecimalStringInMB } from '../utils';
import { isUndefinedOrNull } from '../../types';
export class DatabaseDialog extends ObjectManagementDialogBase<Database, DatabaseViewInfo> {
// Database Properties tabs
private generalTab: azdata.Tab;
private optionsTab: azdata.Tab;
private optionsTabSectionsContainer: azdata.Component[] = [];
//Database properties options
// Database properties options
// General Tab
private nameInput: azdata.InputBoxComponent;
private backupSection: azdata.GroupContainer;
private lastDatabaseBackupInput: azdata.InputBoxComponent;
@@ -30,6 +34,18 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
private memoryAllocatedInput: azdata.InputBoxComponent;
private memoryUsedInput: azdata.InputBoxComponent;
private collationInput: azdata.InputBoxComponent;
// Options Tab
private autoCreateIncrementalStatisticsInput: azdata.CheckBoxComponent;
private autoCreateStatisticsInput: azdata.CheckBoxComponent;
private autoShrinkInput: azdata.CheckBoxComponent;
private autoUpdateStatisticsInput: azdata.CheckBoxComponent;
private autoUpdateStatisticsAsynchronouslyInput: azdata.CheckBoxComponent;
private isLedgerDatabaseInput!: azdata.CheckBoxComponent;
private pageVerifyInput!: azdata.DropDownComponent;
private targetRecoveryTimeInSecInput!: azdata.InputBoxComponent;
private databaseReadOnlyInput!: azdata.CheckBoxComponent;
private encryptionEnabledInput: azdata.CheckBoxComponent;
private restrictAccessInput!: azdata.DropDownComponent;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
super(objectManagementService, options);
@@ -53,18 +69,36 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
this.initializeBackupSection();
this.initializeDatabaseSection();
//Initilaize options Tab sections
this.initializeOptionsGeneralSection();
this.initializeAutomaticSection();
if (!isUndefinedOrNull(this.objectInfo.isLedgerDatabase)) {
this.initializeLedgerSection();
}
if (!isUndefinedOrNull(this.objectInfo.pageVerify) && !isUndefinedOrNull(this.objectInfo.targetRecoveryTimeInSec)) {
this.initializeRecoverySection();
}
this.initializeStateSection();
// Initilaize general Tab
this.generalTab = {
title: localizedConstants.GeneralSectionHeader,
id: 'generalId',
id: 'general',
content: this.createGroup('', [
this.databaseSection,
this.backupSection
], false)
};
// Initilaize Options Tab
this.optionsTab = {
title: localizedConstants.OptionsSectionHeader,
id: 'options',
content: this.createGroup('', this.optionsTabSectionsContainer, false)
};
// Initilaize tab group with tabbed panel
const propertiesTabGroup = { title: '', tabs: [this.generalTab] };
const propertiesTabGroup = { title: '', tabs: [this.generalTab, this.optionsTab] };
const propertiesTabbedPannel = this.modelView.modelBuilder.tabbedPanel()
.withTabs([propertiesTabGroup])
.withProps({
@@ -137,9 +171,11 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
//#region Database Properties - General Tab
private initializeBackupSection(): void {
// Last Database Backup
this.lastDatabaseBackupInput = this.createInputBox(localizedConstants.LastDatabaseBackupText, async () => { }, this.objectInfo.lastDatabaseBackup, this.options.isNewObject);
const lastDatabaseBackupContainer = this.createLabelInputContainer(localizedConstants.LastDatabaseBackupText, this.lastDatabaseBackupInput);
// Last Database Log Backup
this.lastDatabaseLogBackupInput = this.createInputBox(localizedConstants.LastDatabaseLogBackupText, async () => { }, this.objectInfo.lastDatabaseLogBackup, this.options.isNewObject);
const lastDatabaseLogBackupContainer = this.createLabelInputContainer(localizedConstants.LastDatabaseLogBackupText, this.lastDatabaseLogBackupInput);
@@ -150,33 +186,43 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
}
private initializeDatabaseSection(): void {
// Database Name
this.nameInput = this.createInputBox(localizedConstants.NamePropertyText, async () => { }, this.objectInfo.name, this.options.isNewObject);
const nameContainer = this.createLabelInputContainer(localizedConstants.NamePropertyText, this.nameInput);
// Database Status
this.statusInput = this.createInputBox(localizedConstants.StatusText, async () => { }, this.objectInfo.status, this.options.isNewObject);
const statusContainer = this.createLabelInputContainer(localizedConstants.StatusText, this.statusInput);
// Database Owner
this.ownerInput = this.createInputBox(localizedConstants.OwnerPropertyText, async () => { }, this.objectInfo.owner, this.options.isNewObject);
const ownerContainer = this.createLabelInputContainer(localizedConstants.OwnerPropertyText, this.ownerInput);
// Created Date
this.dateCreatedInput = this.createInputBox(localizedConstants.DateCreatedText, async () => { }, this.objectInfo.dateCreated, this.options.isNewObject);
const dateCreatedContainer = this.createLabelInputContainer(localizedConstants.DateCreatedText, this.dateCreatedInput);
this.sizeInput = this.createInputBox(localizedConstants.SizeText, async () => { }, convertNumToTwoDecimalStringinMB(this.objectInfo.sizeInMb), this.options.isNewObject);
// Size
this.sizeInput = this.createInputBox(localizedConstants.SizeText, async () => { }, convertNumToTwoDecimalStringInMB(this.objectInfo.sizeInMb), this.options.isNewObject);
const sizeContainer = this.createLabelInputContainer(localizedConstants.SizeText, this.sizeInput);
this.spaceAvailabeInput = this.createInputBox(localizedConstants.SpaceAvailableText, async () => { }, convertNumToTwoDecimalStringinMB(this.objectInfo.spaceAvailableInMb), this.options.isNewObject);
// Space Available
this.spaceAvailabeInput = this.createInputBox(localizedConstants.SpaceAvailableText, async () => { }, convertNumToTwoDecimalStringInMB(this.objectInfo.spaceAvailableInMb), this.options.isNewObject);
const spaceAvailabeContainer = this.createLabelInputContainer(localizedConstants.SpaceAvailableText, this.spaceAvailabeInput);
// Number of Users
this.numberOfUsersInput = this.createInputBox(localizedConstants.NumberOfUsersText, async () => { }, this.objectInfo.numberOfUsers.toString(), this.options.isNewObject);
const numberOfUsersContainer = this.createLabelInputContainer(localizedConstants.NumberOfUsersText, this.numberOfUsersInput);
this.memoryAllocatedInput = this.createInputBox(localizedConstants.MemoryAllocatedText, async () => { }, convertNumToTwoDecimalStringinMB(this.objectInfo.memoryAllocatedToMemoryOptimizedObjectsInMb), this.options.isNewObject);
// Memory Allocated To Memory Optimized Objects
this.memoryAllocatedInput = this.createInputBox(localizedConstants.MemoryAllocatedText, async () => { }, convertNumToTwoDecimalStringInMB(this.objectInfo.memoryAllocatedToMemoryOptimizedObjectsInMb), this.options.isNewObject);
const memoryAllocatedContainer = this.createLabelInputContainer(localizedConstants.MemoryAllocatedText, this.memoryAllocatedInput);
this.memoryUsedInput = this.createInputBox(localizedConstants.MemoryUsedText, async () => { }, convertNumToTwoDecimalStringinMB(this.objectInfo.memoryUsedByMemoryOptimizedObjectsInMb), this.options.isNewObject);
// Memory Used By Memory Optimized Objects
this.memoryUsedInput = this.createInputBox(localizedConstants.MemoryUsedText, async () => { }, convertNumToTwoDecimalStringInMB(this.objectInfo.memoryUsedByMemoryOptimizedObjectsInMb), this.options.isNewObject);
const memoryUsedContainer = this.createLabelInputContainer(localizedConstants.MemoryUsedText, this.memoryUsedInput);
// Collation
this.collationInput = this.createInputBox(localizedConstants.CollationText, async () => { }, this.objectInfo.collationName, this.options.isNewObject);
const collationContainer = this.createLabelInputContainer(localizedConstants.CollationText, this.collationInput);
@@ -195,6 +241,144 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
}
//#endregion
//#region Database Properties - Options Tab
private initializeOptionsGeneralSection(): void {
let containers: azdata.Component[] = [];
// Collation
let collationDropbox = this.createDropdown(localizedConstants.CollationText, async (newValue) => {
this.objectInfo.collationName = newValue as string;
}, this.viewInfo.collationNames, this.objectInfo.collationName);
containers.push(this.createLabelInputContainer(localizedConstants.CollationText, collationDropbox));
// Recovery Model
let displayOptionsArray = this.viewInfo.recoveryModels.length === 0 ? [this.objectInfo.recoveryModel] : this.viewInfo.recoveryModels;
let isEnabled = this.viewInfo.recoveryModels.length === 0 ? false : true;
let recoveryDropbox = this.createDropdown(localizedConstants.RecoveryModelText, async (newValue) => {
this.objectInfo.recoveryModel = newValue as string;
}, displayOptionsArray, this.objectInfo.recoveryModel, isEnabled);
containers.push(this.createLabelInputContainer(localizedConstants.RecoveryModelText, recoveryDropbox));
// Compatibility Level
let compatibilityDropbox = this.createDropdown(localizedConstants.CompatibilityLevelText, async (newValue) => {
this.objectInfo.compatibilityLevel = newValue as string;
}, this.viewInfo.compatibilityLevels, this.objectInfo.compatibilityLevel);
containers.push(this.createLabelInputContainer(localizedConstants.CompatibilityLevelText, compatibilityDropbox));
// Containment Type
displayOptionsArray = this.viewInfo.containmentTypes.length === 0 ? [this.objectInfo.containmentType] : this.viewInfo.containmentTypes;
isEnabled = this.viewInfo.containmentTypes.length === 0 ? false : true;
let containmentDropbox = this.createDropdown(localizedConstants.ContainmentTypeText, async (newValue) => {
this.objectInfo.containmentType = newValue as string;
}, displayOptionsArray, this.objectInfo.containmentType, isEnabled);
containers.push(this.createLabelInputContainer(localizedConstants.ContainmentTypeText, containmentDropbox));
const optionsGeneralSection = this.createGroup('', containers, true, true);
this.optionsTabSectionsContainer.push(optionsGeneralSection);
}
private initializeAutomaticSection(): void {
// Auto Create Incremental Statistics
this.autoCreateIncrementalStatisticsInput = this.createCheckbox(localizedConstants.AutoCreateIncrementalStatisticsText, async (checked) => {
this.objectInfo.autoCreateIncrementalStatistics = checked;
}, this.objectInfo.autoCreateIncrementalStatistics);
// Auto Create Statistics
this.autoCreateStatisticsInput = this.createCheckbox(localizedConstants.AutoCreateStatisticsText, async (checked) => {
this.objectInfo.autoCreateStatistics = checked;
}, this.objectInfo.autoCreateStatistics);
// Auto Shrink
this.autoShrinkInput = this.createCheckbox(localizedConstants.AutoShrinkText, async (checked) => {
this.objectInfo.autoShrink = checked;
}, this.objectInfo.autoShrink);
// Auto Update Statistics
this.autoUpdateStatisticsInput = this.createCheckbox(localizedConstants.AutoUpdateStatisticsText, async (checked) => {
this.objectInfo.autoUpdateStatistics = checked;
}, this.objectInfo.autoUpdateStatistics);
//Auto Update Statistics Asynchronously
this.autoUpdateStatisticsAsynchronouslyInput = this.createCheckbox(localizedConstants.AutoUpdateStatisticsAsynchronouslyText, async (checked) => {
this.objectInfo.autoUpdateStatisticsAsynchronously = checked;
}, this.objectInfo.autoUpdateStatisticsAsynchronously);
const automaticSection = this.createGroup(localizedConstants.AutomaticSectionHeader, [
this.autoCreateIncrementalStatisticsInput,
this.autoCreateStatisticsInput,
this.autoShrinkInput,
this.autoUpdateStatisticsInput,
this.autoUpdateStatisticsAsynchronouslyInput
], true);
this.optionsTabSectionsContainer.push(automaticSection);
}
private initializeLedgerSection(): void {
// Ledger Database
this.isLedgerDatabaseInput = this.createCheckbox(localizedConstants.IsLedgerDatabaseText, async (checked) => {
this.objectInfo.isLedgerDatabase = checked;
}, this.objectInfo.isLedgerDatabase);
const ledgerSection = this.createGroup(localizedConstants.LedgerSectionHeader, [
this.isLedgerDatabaseInput
], true);
this.optionsTabSectionsContainer.push(ledgerSection);
}
private initializeRecoverySection(): void {
// Page Verify
this.pageVerifyInput = this.createDropdown(localizedConstants.PageVerifyText, async (newValue) => {
this.objectInfo.pageVerify = newValue;
}, this.viewInfo.pageVerifyOptions, this.objectInfo.pageVerify, true);
const pageVerifyContainer = this.createLabelInputContainer(localizedConstants.PageVerifyText, this.pageVerifyInput);
// Recovery Time In Seconds
this.targetRecoveryTimeInSecInput = this.createInputBox(localizedConstants.TargetRecoveryTimeInSecondsText, async (newValue) => {
this.objectInfo.targetRecoveryTimeInSec = Number(newValue);
}, this.objectInfo.targetRecoveryTimeInSec.toString(), true, 'number');
const targetRecoveryTimeContainer = this.createLabelInputContainer(localizedConstants.TargetRecoveryTimeInSecondsText, this.targetRecoveryTimeInSecInput);
const recoverySection = this.createGroup(localizedConstants.RecoverySectionHeader, [
pageVerifyContainer,
targetRecoveryTimeContainer
], true);
this.optionsTabSectionsContainer.push(recoverySection);
}
private initializeStateSection(): void {
let containers: azdata.Component[] = [];
// Database Read-Only
if (!isUndefinedOrNull(this.objectInfo.databaseReadOnly)) {
this.databaseReadOnlyInput = this.createCheckbox(localizedConstants.DatabaseReadOnlyText, async (checked) => {
this.objectInfo.databaseReadOnly = checked;
}, this.objectInfo.databaseReadOnly);
containers.push(this.databaseReadOnlyInput);
}
// Database Status
this.statusInput = this.createInputBox(localizedConstants.StatusText, async () => { }, this.objectInfo.status, this.options.isNewObject);
containers.push(this.createLabelInputContainer(localizedConstants.DatabaseStateText, this.statusInput));
// Encryption Enabled
this.encryptionEnabledInput = this.createCheckbox(localizedConstants.EncryptionEnabledText, async (checked) => {
this.objectInfo.encryptionEnabled = checked;
}, this.objectInfo.encryptionEnabled);
containers.push(this.encryptionEnabledInput);
// Restrict Access
if (!isUndefinedOrNull(this.objectInfo.restrictAccess)) {
this.restrictAccessInput = this.createDropdown(localizedConstants.RestrictAccessText, async (newValue) => {
this.objectInfo.restrictAccess = newValue;
}, this.viewInfo.restrictAccessOptions, this.objectInfo.restrictAccess, true);
containers.push(this.createLabelInputContainer(localizedConstants.RestrictAccessText, this.restrictAccessInput));
}
const stateSection = this.createGroup(localizedConstants.StateSectionHeader, containers, true);
this.optionsTabSectionsContainer.push(stateSection);
}
//#endregion
private initializeConfigureSLOSection(): azdata.GroupContainer {
let containers: azdata.Component[] = [];
if (this.viewInfo.azureEditions?.length > 0) {