mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 01:25:38 -05:00
Enabling Files tab to the database properties (#24138)
* initial changes for loadin dsc table with real values from smo * Displaying diff columns for DSC for diff sql server * checkbox maiants the selection * elevate option fails to load correct value when set to when_supported option * all working till maxdop, todo pause option, save * commented MAXDOP changes, as it is causing issues * primary,sec,checkbox working as expected, TODO:MaxDop etc options,saving,tests * Undo MAXDOP commented code * refactored with service data * column header width adjustments * Maxdop and pause resume options completed, apply button is failing now * Removed option names from loc and using Id instead as names may change in future like in doc * Apply button fixed * refactored to reduce table reload * Ledger digest completed * refactor done: maxdop secondary shows wrong data from pause_resume * refactor more: all working but table focus disturbs on update table * adds conditions for unsupported dsc to <2016 server * maxdop secondary checkbox fix * rows still loses focus after value change due to update table row data * Fixed updating secondary dropdown value * reusing the private method and removed the duplicated codes * initial commit - fullText and owner need revision * Enter key in input type allows the change to update the table data, reduces the live update issues * Setting focus to the current row * loading data, need stylings-increase col length, etc * using the existed setTableData method * Adding new file dialog * creating addFile, but not displaying in table, issue with appendData * Adding row to the table, options are getting from STS * all working except InPercent value * code review comment updates * Input type checkbox update table additional validation * all except path * fixing the input type focus and reverting the enterKeyPress logic * browse path is created, need stylings,refactor,filestream selection and add * fixing the flickering issue with data refresh * new file options toggle and grid display string updates * moving code inline and using actual component * cleanup * Add file saving is done, except one styling issue with autogrowth section * add,remove working, need to edit file * add, edit, remove - all working, need css fixes and -1 fix * addressing code review comments * adding local changes adn fixing for edit file * adjusting css * addressing code review comment for using loc var instead of duplicated line of code to get the rowinfo * all fixed, need testing and refactor * vBump STS and fixing required field causing the apply button not enable for other options on main branch * fixing autogrowth radio buttons change updates * all working except some css * disabled size for filestream * fixing filegroups and filetypes scnearios, added filename validation for newfile, todo:editingNew file * added max and min values to the inputs * editing filename validation completed, all done exccept CSS * all fixed except scroll bar * edit db file header, filename enable issue fix * PR comment supporting updates for STS * min updates * modfying addButtonsForTable method and reusing it for edit button * code review comment updates * Dialogbase addbuttons to table refactored * more typo fixes * removing fulltext index prop * service fix * using path.join instead of hardcoded separators * final commit changes
This commit is contained in:
committed by
GitHub
parent
9557e77982
commit
c4b1765745
@@ -5,14 +5,15 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase';
|
||||
import { DefaultInputWidth, DefaultTableWidth, getTableHeight } from '../../ui/dialogBase';
|
||||
import { DefaultInputWidth, DefaultTableWidth, DefaultMinTableRowCount, DefaultMaxTableRowCount, getTableHeight, DialogButton } from '../../ui/dialogBase';
|
||||
import { IObjectManagementService } from 'mssql';
|
||||
import * as localizedConstants from '../localizedConstants';
|
||||
import { CreateDatabaseDocUrl, DatabaseGeneralPropertiesDocUrl, DatabaseOptionsPropertiesDocUrl, DatabaseScopedConfigurationPropertiesDocUrl } from '../constants';
|
||||
import { Database, DatabaseScopedConfigurationsInfo, DatabaseViewInfo } from '../interfaces';
|
||||
import { CreateDatabaseDocUrl, DatabaseGeneralPropertiesDocUrl, DatabaseFilesPropertiesDocUrl, DatabaseOptionsPropertiesDocUrl, DatabaseScopedConfigurationPropertiesDocUrl } from '../constants';
|
||||
import { Database, DatabaseFile, DatabaseScopedConfigurationsInfo, DatabaseViewInfo, FileGrowthType } from '../interfaces';
|
||||
import { convertNumToTwoDecimalStringInMB } from '../utils';
|
||||
import { isUndefinedOrNull } from '../../types';
|
||||
import { deepClone } from '../../util/objects';
|
||||
import { DatabaseFileDialog } from './databaseFileDialog';
|
||||
|
||||
const MAXDOP_Max_Limit = 32767;
|
||||
const PAUSED_RESUMABLE_INDEX_Max_Limit = 71582;
|
||||
@@ -21,6 +22,7 @@ const DscTableRowLength = 15;
|
||||
export class DatabaseDialog extends ObjectManagementDialogBase<Database, DatabaseViewInfo> {
|
||||
// Database Properties tabs
|
||||
private generalTab: azdata.Tab;
|
||||
private filesTab: azdata.Tab;
|
||||
private optionsTab: azdata.Tab;
|
||||
private dscTab: azdata.Tab;
|
||||
private optionsTabSectionsContainer: azdata.Component[] = [];
|
||||
@@ -43,6 +45,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
private memoryAllocatedInput: azdata.InputBoxComponent;
|
||||
private memoryUsedInput: azdata.InputBoxComponent;
|
||||
private collationInput: azdata.InputBoxComponent;
|
||||
// Files Tab
|
||||
private readonly filesTabId: string = 'filesDatabaseId';
|
||||
private databaseFilesTable: azdata.TableComponent;
|
||||
// Options Tab
|
||||
private readonly optionsTabId: string = 'optionsDatabaseId';
|
||||
private autoCreateIncrementalStatisticsInput: azdata.CheckBoxComponent;
|
||||
@@ -91,6 +96,9 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
case this.generalTabId:
|
||||
helpUrl = DatabaseGeneralPropertiesDocUrl;
|
||||
break;
|
||||
case this.filesTabId:
|
||||
helpUrl = DatabaseFilesPropertiesDocUrl;
|
||||
break;
|
||||
case this.optionsTabId:
|
||||
helpUrl = DatabaseOptionsPropertiesDocUrl;
|
||||
break;
|
||||
@@ -113,11 +121,11 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
}
|
||||
this.formContainer.addItems(components);
|
||||
} else {
|
||||
// Initilaize general Tab sections
|
||||
// Initialize general Tab sections
|
||||
this.initializeBackupSection();
|
||||
this.initializeDatabaseSection();
|
||||
|
||||
//Initilaize options Tab sections
|
||||
//Initialize options Tab sections
|
||||
this.initializeOptionsGeneralSection();
|
||||
this.initializeAutomaticSection();
|
||||
if (!isUndefinedOrNull(this.objectInfo.isLedgerDatabase)) {
|
||||
@@ -130,7 +138,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
|
||||
|
||||
const tabs: azdata.Tab[] = [];
|
||||
// Initilaize general Tab
|
||||
// Initialize general Tab
|
||||
this.generalTab = {
|
||||
title: localizedConstants.GeneralSectionHeader,
|
||||
id: this.generalTabId,
|
||||
@@ -141,7 +149,20 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
};
|
||||
tabs.push(this.generalTab);
|
||||
|
||||
// Initilaize Options Tab
|
||||
// Initialize Files Tab
|
||||
// Files tab is only enabled for SQL Server properties view
|
||||
if (!isUndefinedOrNull(this.objectInfo.isFilesTabSupported)) {
|
||||
const filesGeneralSection = this.initializeFilesGeneralSection();
|
||||
const databaseFilesSection = this.initializeDatabaseFilesSection();
|
||||
this.filesTab = {
|
||||
title: localizedConstants.FilesSectionHeader,
|
||||
id: this.filesTabId,
|
||||
content: this.createGroup('', [filesGeneralSection, databaseFilesSection], false)
|
||||
};
|
||||
tabs.push(this.filesTab);
|
||||
}
|
||||
|
||||
// Initialize Options Tab
|
||||
this.optionsTab = {
|
||||
title: localizedConstants.OptionsSectionHeader,
|
||||
id: this.optionsTabId,
|
||||
@@ -149,7 +170,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
};
|
||||
tabs.push(this.optionsTab);
|
||||
|
||||
// Initilaize DSC Tab section
|
||||
// Initialize DSC Tab section
|
||||
if (!isUndefinedOrNull(this.objectInfo.databaseScopedConfigurations)) {
|
||||
await this.initializeDatabaseScopedConfigurationSection();
|
||||
this.dscTabSectionsContainer.push(await this.initializeDscValueDropdownTypeSection())
|
||||
@@ -162,7 +183,7 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
tabs.push(this.dscTab);
|
||||
}
|
||||
|
||||
// Initilaize tab group with tabbed panel
|
||||
// Initialize tab group with tabbed panel
|
||||
const propertiesTabGroup = { title: '', tabs: tabs };
|
||||
const propertiesTabbedPannel = this.modelView.modelBuilder.tabbedPanel()
|
||||
.withTabs([propertiesTabGroup])
|
||||
@@ -396,6 +417,216 @@ export class DatabaseDialog extends ObjectManagementDialogBase<Database, Databas
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Database Properties - Files Tab
|
||||
private initializeFilesGeneralSection(): azdata.GroupContainer {
|
||||
let containers: azdata.Component[] = [];
|
||||
// Database name
|
||||
this.nameInput = this.createInputBox(async () => { }, {
|
||||
ariaLabel: localizedConstants.DatabaseNameText,
|
||||
inputType: 'text',
|
||||
enabled: this.options.isNewObject,
|
||||
value: this.objectInfo.name
|
||||
});
|
||||
containers.push(this.createLabelInputContainer(localizedConstants.DatabaseNameText, this.nameInput));
|
||||
|
||||
// Owner
|
||||
let loginNames = this.viewInfo.loginNames?.options;
|
||||
|
||||
if (loginNames?.length > 0) {
|
||||
// Removing <default> login name from the list and adding current owner if not exists
|
||||
if (!this.viewInfo.loginNames?.options.find(owner => owner === this.objectInfo.owner)) {
|
||||
loginNames[0] = this.objectInfo.owner;
|
||||
} else {
|
||||
loginNames.splice(0, 1);
|
||||
}
|
||||
let ownerDropbox = this.createDropdown(localizedConstants.OwnerText, async () => {
|
||||
this.objectInfo.owner = ownerDropbox.value as string;
|
||||
}, loginNames, this.objectInfo.owner);
|
||||
containers.push(this.createLabelInputContainer(localizedConstants.OwnerText, ownerDropbox));
|
||||
}
|
||||
return this.createGroup('', containers, false);
|
||||
}
|
||||
|
||||
private initializeDatabaseFilesSection(): azdata.GroupContainer {
|
||||
this.databaseFilesTable = this.modelView.modelBuilder.table().withProps({
|
||||
columns: [{
|
||||
type: azdata.ColumnType.text,
|
||||
value: localizedConstants.LogicalNameText
|
||||
}, {
|
||||
type: azdata.ColumnType.text,
|
||||
value: localizedConstants.FileTypeText
|
||||
}, {
|
||||
type: azdata.ColumnType.text,
|
||||
value: localizedConstants.FilegroupText
|
||||
}, {
|
||||
type: azdata.ColumnType.text,
|
||||
value: localizedConstants.SizeInMbText
|
||||
}, {
|
||||
type: azdata.ColumnType.text,
|
||||
value: localizedConstants.AutogrowthMaxsizeText
|
||||
}, {
|
||||
type: azdata.ColumnType.text,
|
||||
value: localizedConstants.PathText
|
||||
}, {
|
||||
type: azdata.ColumnType.text,
|
||||
value: localizedConstants.FileNameText
|
||||
}],
|
||||
data: this.objectInfo.files?.map(file => {
|
||||
return this.convertToDataView(file);
|
||||
|
||||
}),
|
||||
height: getTableHeight(this.objectInfo.files?.length, DefaultMinTableRowCount, DefaultMaxTableRowCount),
|
||||
width: DefaultTableWidth,
|
||||
forceFitColumns: azdata.ColumnSizingMode.DataFit,
|
||||
CSSStyles: {
|
||||
'margin-left': '10px'
|
||||
}
|
||||
}).component();
|
||||
const addButtonComponent: DialogButton = {
|
||||
buttonAriaLabel: localizedConstants.AddButton,
|
||||
buttonHandler: (button) => this.onAddDatabaseFilesButtonClicked(button)
|
||||
};
|
||||
const removeButtonComponent: DialogButton = {
|
||||
buttonAriaLabel: localizedConstants.RemoveButton,
|
||||
buttonHandler: () => this.onRemoveDatabaseFilesButtonClicked()
|
||||
};
|
||||
const editbuttonComponent: DialogButton = {
|
||||
buttonAriaLabel: localizedConstants.EditButton,
|
||||
buttonHandler: (button) => this.onEditDatabaseFilesButtonClicked(button)
|
||||
};
|
||||
const databaseFilesButtonContainer = this.addButtonsForTable(this.databaseFilesTable, addButtonComponent, removeButtonComponent, editbuttonComponent);
|
||||
|
||||
return this.createGroup(localizedConstants.DatabaseFilesText, [this.databaseFilesTable, databaseFilesButtonContainer], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the file object to a data view object
|
||||
* @param file database file object
|
||||
* @returns data view object
|
||||
*/
|
||||
private convertToDataView(file: DatabaseFile): any[] {
|
||||
return [
|
||||
file.name,
|
||||
file.type,
|
||||
file.fileGroup,
|
||||
file.sizeInMb,
|
||||
file.isAutoGrowthEnabled ? localizedConstants.AutoGrowthValueStringGenerator(file.type !== localizedConstants.FilestreamFileType
|
||||
, file.autoFileGrowth.toString()
|
||||
, file.autoFileGrowthType === FileGrowthType.Percent
|
||||
, file.maxSizeLimitInMb) : localizedConstants.NoneText,
|
||||
file.path,
|
||||
file.fileNameWithExtension
|
||||
];
|
||||
}
|
||||
|
||||
private async onAddDatabaseFilesButtonClicked(button: azdata.ButtonComponent): Promise<void> {
|
||||
// Open file dialog to create file
|
||||
const result = await this.openDatabaseFileDialog(button);
|
||||
if (!isUndefinedOrNull(result)) {
|
||||
this.objectInfo.files?.push(result);
|
||||
var newData = this.objectInfo.files?.map(file => {
|
||||
return this.convertToDataView(file);
|
||||
});
|
||||
await this.setTableData(this.databaseFilesTable, newData, DefaultMaxTableRowCount)
|
||||
}
|
||||
}
|
||||
|
||||
private async onEditDatabaseFilesButtonClicked(button: azdata.ButtonComponent): Promise<void> {
|
||||
if (this.databaseFilesTable.selectedRows.length === 1) {
|
||||
const result = await this.openDatabaseFileDialog(button);
|
||||
if (!isUndefinedOrNull(result)) {
|
||||
this.objectInfo.files[this.databaseFilesTable.selectedRows[0]] = result;
|
||||
var newData = this.objectInfo.files?.map(file => {
|
||||
return this.convertToDataView(file);
|
||||
});
|
||||
await this.setTableData(this.databaseFilesTable, newData, DefaultMaxTableRowCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the selected database file from the table
|
||||
*/
|
||||
private async onRemoveDatabaseFilesButtonClicked(): Promise<void> {
|
||||
if (this.databaseFilesTable.selectedRows.length === 1) {
|
||||
this.objectInfo.files?.splice(this.databaseFilesTable.selectedRows[0], 1);
|
||||
var newData = this.objectInfo.files?.map(file => {
|
||||
return this.convertToDataView(file);
|
||||
});
|
||||
await this.setTableData(this.databaseFilesTable, newData, DefaultMaxTableRowCount)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the selected row to enable/disable the remove button
|
||||
* @returns true if the remove button should be enabled, false otherwise
|
||||
*/
|
||||
protected override get removeButtonEnabled(): boolean {
|
||||
let isEnabled = true;
|
||||
if (this.databaseFilesTable.selectedRows !== undefined) {
|
||||
const selectedRowId = this.objectInfo.files[this.databaseFilesTable.selectedRows[0]].id;
|
||||
// Cannot delete a Primary row data file, Id is always 1.
|
||||
if (this.databaseFilesTable.selectedRows.length === 1 && selectedRowId === 1) {
|
||||
isEnabled = false;
|
||||
}
|
||||
// Cannot remove a log file if there are no other log files, LogFiletype is always a Log file type
|
||||
else if (this.objectInfo.files[this.databaseFilesTable.selectedRows[0]].type === localizedConstants.LogFiletype) {
|
||||
isEnabled = false;
|
||||
this.objectInfo.files.forEach(file => {
|
||||
if (file.id !== selectedRowId && file.type === localizedConstants.LogFiletype) {
|
||||
isEnabled = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
private async openDatabaseFileDialog(button: azdata.ButtonComponent): Promise<DatabaseFile> {
|
||||
const defaultFileSizeInMb: number = 8
|
||||
const defaultFileGrowthInMb: number = 64
|
||||
const defaultFileGrowthInPercent: number = 10;
|
||||
const defaultMaxFileSizeLimitedToInMb: number = 100;
|
||||
const selectedFile = this.databaseFilesTable.selectedRows !== undefined ? this.objectInfo.files[this.databaseFilesTable?.selectedRows[0]] : undefined;
|
||||
if (!isUndefinedOrNull(selectedFile) && selectedFile.type === localizedConstants.FilestreamFileType) {
|
||||
selectedFile.autoFileGrowth = defaultFileGrowthInMb;
|
||||
}
|
||||
const isNewFile: boolean = button.ariaLabel === localizedConstants.AddButton;
|
||||
const isEditingNewFile: boolean = button.ariaLabel === localizedConstants.EditButton && selectedFile.id === undefined;
|
||||
const databaseFile: DatabaseFile = isNewFile ? {
|
||||
id: undefined,
|
||||
name: '',
|
||||
type: localizedConstants.RowsDataFileType,
|
||||
path: this.objectInfo.files[0].path,
|
||||
fileGroup: this.viewInfo.rowDataFileGroupsOptions[0],
|
||||
fileNameWithExtension: '',
|
||||
sizeInMb: defaultFileSizeInMb,
|
||||
isAutoGrowthEnabled: true,
|
||||
autoFileGrowth: defaultFileGrowthInMb,
|
||||
autoFileGrowthType: FileGrowthType.KB,
|
||||
maxSizeLimitInMb: defaultMaxFileSizeLimitedToInMb
|
||||
} : selectedFile;
|
||||
|
||||
const dialog = new DatabaseFileDialog({
|
||||
title: (isNewFile || isEditingNewFile) ? localizedConstants.AddDatabaseFilesText : localizedConstants.EditDatabaseFilesText(databaseFile.name),
|
||||
viewInfo: this.viewInfo,
|
||||
files: this.objectInfo.files,
|
||||
isNewFile: isNewFile,
|
||||
isEditingNewFile: isEditingNewFile,
|
||||
databaseFile: databaseFile,
|
||||
defaultFileConstants: {
|
||||
defaultFileSizeInMb: defaultFileSizeInMb,
|
||||
defaultFileGrowthInMb: defaultFileGrowthInMb,
|
||||
defaultFileGrowthInPercent: defaultFileGrowthInPercent,
|
||||
defaultMaxFileSizeLimitedToInMb: defaultMaxFileSizeLimitedToInMb
|
||||
}
|
||||
});
|
||||
await dialog.open();
|
||||
return await dialog.waitForClose();
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Database Properties - Options Tab
|
||||
private initializeOptionsGeneralSection(): void {
|
||||
let containers: azdata.Component[] = [];
|
||||
|
||||
Reference in New Issue
Block a user