diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 3baa4b7c49..fa73bc285f 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -89,6 +89,26 @@ export const profile = localize('profile', "Profile"); export const selectConnection = localize('selectConnection', "Select connection"); export const connection = localize('connection', "Connection"); +// Add Database Reference dialog strings + +export const addDatabaseReferenceDialogName = localize('addDatabaseReferencedialogName', "Add database reference"); +export const addDatabaseReferenceOkButtonText = localize('addDatabaseReferenceOkButtonText', "Add reference"); +export const referenceRadioButtonsGroupTitle = localize('referenceRadioButtonsGroupTitle', "Type"); +export const systemDatabaseRadioButtonTitle = localize('systemDatabaseRadioButtonTitle', "System database"); +export const dacpacText = localize('dacpacText', "Data-tier application (.dacpac)"); +export const dacpacPlaceholder = localize('dacpacPlaceholder', "Select .dacpac"); +export const loadDacpacButton = localize('loadDacpacButton', "Select .dacpac"); +export const locationDropdown = localize('locationDropdown', "Location"); +export const sameDatabase = localize('sameDatabase', "Same database"); +export const differentDbSameServer = localize('differentDbSameServer', "Different database, same server"); +export const differentDbDifferentServer = localize('differentDbDifferentServer', "Different database, different server"); +export const systemDbLocationDropdownValues = [differentDbSameServer]; +export const locationDropdownValues = [sameDatabase, differentDbSameServer, differentDbDifferentServer]; +export const databaseName = localize('databaseName', "Database name"); +export const databaseVariable = localize('databaseVariable', "Database variable"); +export const serverName = localize('serverName', "Server name"); +export const serverVariable = localize('serverVariable', "Server variable"); + // Error messages export const multipleSqlProjFiles = localize('multipleSqlProjFilesSelected', "Multiple .sqlproj files selected; please select only one."); diff --git a/extensions/sql-database-projects/src/common/uiConstants.ts b/extensions/sql-database-projects/src/common/uiConstants.ts index 3e113ca4d1..63601421f5 100644 --- a/extensions/sql-database-projects/src/common/uiConstants.ts +++ b/extensions/sql-database-projects/src/common/uiConstants.ts @@ -9,6 +9,10 @@ export namespace cssStyles { export const tableHeader = { ...text, 'text-align': 'left', 'border': 'none', 'font-size': '12px', 'font-weight': 'normal', 'color': '#666666' }; export const tableRow = { ...text, 'border-top': 'solid 1px #ccc', 'border-bottom': 'solid 1px #ccc', 'border-left': 'none', 'border-right': 'none', 'font-size': '12px' }; export const titleFontSize = 13; + export const publishDialogLabelWidth = '205px'; export const publishDialogTextboxWidth = '190px'; + + export const addDatabaseReferenceDialogLabelWidth = '215px'; + export const addDatabaseReferenceInputboxWidth = '220px'; } diff --git a/extensions/sql-database-projects/src/dialogs/addDatabaseReferenceDialog.ts b/extensions/sql-database-projects/src/dialogs/addDatabaseReferenceDialog.ts new file mode 100644 index 0000000000..5ab0b4d97b --- /dev/null +++ b/extensions/sql-database-projects/src/dialogs/addDatabaseReferenceDialog.ts @@ -0,0 +1,402 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as constants from '../common/constants'; + +import { Project, SystemDatabase, DatabaseReferenceLocation } from '../models/project'; +import { cssStyles } from '../common/uiConstants'; +import { IconPathHelper } from '../common/iconHelper'; +import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings } from '../models/IDatabaseReferenceSettings'; + +export enum ReferenceType { + project, + systemDb, + dacpac +} + +interface Deferred { + resolve: (result: T | Promise) => void; + reject: (reason: any) => void; +} + +export class AddDatabaseReferenceDialog { + public dialog: azdata.window.Dialog; + public addDatabaseReferenceTab: azdata.window.DialogTab; + private view: azdata.ModelView | undefined; + private formBuilder: azdata.FormBuilder | undefined; + private systemDatabaseDropdown: azdata.DropDownComponent | undefined; + private systemDatabaseFormComponent: azdata.FormComponent | undefined; + public dacpacTextbox: azdata.InputBoxComponent | undefined; + private dacpacFormComponent: azdata.FormComponent | undefined; + public locationDropdown: azdata.DropDownComponent | undefined; + public databaseNameTextbox: azdata.InputBoxComponent | undefined; + public databaseVariableTextbox: azdata.InputBoxComponent | undefined; + public serverNameTextbox: azdata.InputBoxComponent | undefined; + public serverVariableTextbox: azdata.InputBoxComponent | undefined; + + public currentReferenceType: ReferenceType | undefined; + private referenceLocationMap: Map; + + private toDispose: vscode.Disposable[] = []; + private initDialogComplete: Deferred | undefined; + private initDialogPromise: Promise = new Promise((resolve, reject) => this.initDialogComplete = { resolve, reject }); + + public addReference: ((proj: Project, settings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings) => any) | undefined; + + constructor(private project: Project) { + this.dialog = azdata.window.createModelViewDialog(constants.addDatabaseReferenceDialogName); + this.addDatabaseReferenceTab = azdata.window.createTab(constants.addDatabaseReferenceDialogName); + + this.referenceLocationMap = new Map([ + [constants.sameDatabase, DatabaseReferenceLocation.sameDatabase], + [constants.differentDbSameServer, DatabaseReferenceLocation.differentDatabaseSameServer], + [constants.differentDbDifferentServer, DatabaseReferenceLocation.differentDatabaseDifferentServer] + ]); + } + + public async openDialog(): Promise { + this.initializeDialog(); + this.dialog.okButton.label = constants.addDatabaseReferenceOkButtonText; + this.dialog.okButton.enabled = false; + this.toDispose.push(this.dialog.okButton.onClick(async () => await this.addReferenceClick())); + + this.dialog.cancelButton.label = constants.cancelButtonText; + + azdata.window.openDialog(this.dialog); + await this.initDialogPromise; + } + + private dispose(): void { + this.toDispose.forEach(disposable => disposable.dispose()); + } + + private initializeDialog(): void { + this.initializeTab(); + this.dialog.content = [this.addDatabaseReferenceTab]; + } + + private initializeTab(): void { + this.addDatabaseReferenceTab.registerContent(async view => { + this.view = view; + const radioButtonGroup = this.createRadioButtons(); + this.systemDatabaseFormComponent = this.createSystemDatabaseDropdown(); + this.dacpacFormComponent = this.createDacpacTextbox(); + const locationDropdown = this.createLocationDropdown(); + const variableSection = this.createVariableSection(); + + this.formBuilder = view.modelBuilder.formContainer() + .withFormItems([ + { + title: '', + components: [ + radioButtonGroup, + this.systemDatabaseFormComponent, + locationDropdown, + variableSection + ] + } + ], { + horizontal: false + }) + .withLayout({ + width: '100%' + }); + + let formModel = this.formBuilder.component(); + await view.initializeModel(formModel); + + this.initDialogComplete?.resolve(); + }); + } + + public async addReferenceClick(): Promise { + let referenceSettings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings; + + if (this.currentReferenceType === ReferenceType.systemDb) { + referenceSettings = { + databaseName: this.databaseNameTextbox?.value, + systemDb: this.systemDatabaseDropdown?.value === constants.master ? SystemDatabase.master : SystemDatabase.msdb + }; + } else { // this.currentReferenceType === ReferenceType.dacpac + referenceSettings = { + databaseName: this.databaseNameTextbox?.value, + databaseLocation: this.referenceLocationMap.get(this.locationDropdown?.value), + dacpacFileLocation: vscode.Uri.file(this.dacpacTextbox?.value), + databaseVariable: this.databaseVariableTextbox?.value + }; + // TODO: add project reference support + } + + await this.addReference!(this.project, referenceSettings); + + this.dispose(); + } + + private createRadioButtons(): azdata.FormComponent { + // TODO: add project reference button + const systemDatabaseRadioButton = this.view!.modelBuilder.radioButton() + .withProperties({ + name: 'referenceType', + label: constants.systemDatabaseRadioButtonTitle + }).component(); + + systemDatabaseRadioButton.checked = true; + systemDatabaseRadioButton.onDidClick(() => { + this.systemDbRadioButtonClick(); + }); + + const dacpacRadioButton = this.view!.modelBuilder.radioButton() + .withProperties({ + name: 'referenceType', + label: constants.dacpacText + }).component(); + + dacpacRadioButton.onDidClick(() => { + this.dacpacRadioButtonClick(); + }); + + this.currentReferenceType = ReferenceType.systemDb; + let flexRadioButtonsModel: azdata.FlexContainer = this.view!.modelBuilder.flexContainer() + .withLayout({ flexFlow: 'column' }) + .withItems([systemDatabaseRadioButton, dacpacRadioButton]) + .withProperties({ ariaRole: 'radiogroup' }) + .component(); + + return { + component: flexRadioButtonsModel, + title: constants.referenceRadioButtonsGroupTitle + }; + } + + public systemDbRadioButtonClick(): void { + this.formBuilder!.removeFormItem(this.dacpacFormComponent); + this.formBuilder!.insertFormItem(this.systemDatabaseFormComponent, 2); + + // update dropdown values because only different database, same server is a valid location for system db references + this.locationDropdown!.values = constants.systemDbLocationDropdownValues; + + this.currentReferenceType = ReferenceType.systemDb; + this.updateEnabledInputBoxes(true); + this.tryEnableAddReferenceButton(); + } + + public dacpacRadioButtonClick(): void { + this.formBuilder!.removeFormItem(this.systemDatabaseFormComponent); + this.formBuilder!.insertFormItem(this.dacpacFormComponent, 2); + + this.locationDropdown!.values = constants.locationDropdownValues; + this.locationDropdown!.value = constants.differentDbSameServer; + + this.currentReferenceType = ReferenceType.dacpac; + this.updateEnabledInputBoxes(); + this.tryEnableAddReferenceButton(); + } + + private createSystemDatabaseDropdown(): azdata.FormComponent { + this.systemDatabaseDropdown = this.view!.modelBuilder.dropDown().withProperties({ + values: [constants.master, constants.msdb], + ariaLabel: constants.databaseNameLabel + }).component(); + + // only master is a valid system db reference for projects targetting Azure + if (this.project.getProjectTargetPlatform().toLowerCase().includes('azure')) { + this.systemDatabaseDropdown.values?.splice(1); + } + + return { + component: this.systemDatabaseDropdown, + title: constants.databaseNameLabel + }; + } + + private createDacpacTextbox(): azdata.FormComponent { + this.dacpacTextbox = this.view!.modelBuilder.inputBox().withProperties({ + ariaLabel: constants.dacpacText, + placeHolder: constants.dacpacPlaceholder, + width: '405px' + }).component(); + + this.dacpacTextbox.onTextChanged(() => { + this.tryEnableAddReferenceButton(); + }); + + const loadDacpacButton = this.createLoadDacpacButton(); + const databaseRow = this.view!.modelBuilder.flexContainer().withItems([this.dacpacTextbox], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component(); + databaseRow.insertItem(loadDacpacButton, 1); + + return { + component: databaseRow, + title: constants.dacpacText + }; + } + + private createLoadDacpacButton(): azdata.ButtonComponent { + const loadDacpacButton = this.view!.modelBuilder.button().withProperties({ + ariaLabel: constants.loadDacpacButton, + iconPath: IconPathHelper.folder, + height: '16px', + width: '15px' + }).component(); + + loadDacpacButton.onDidClick(async () => { + let fileUris = await vscode.window.showOpenDialog( + { + canSelectFiles: true, + canSelectFolders: false, + canSelectMany: false, + defaultUri: vscode.workspace.workspaceFolders ? (vscode.workspace.workspaceFolders as vscode.WorkspaceFolder[])[0].uri : undefined, + openLabel: constants.selectString, + filters: { + [constants.dacpacFiles]: ['dacpac'], + } + } + ); + + if (!fileUris || fileUris.length === 0) { + return; + } + + this.dacpacTextbox!.value = fileUris[0].fsPath; + }); + + return loadDacpacButton; + } + + private createLocationDropdown(): azdata.FormComponent { + this.locationDropdown = this.view!.modelBuilder.dropDown().withProperties({ + ariaLabel: constants.locationDropdown, + values: constants.systemDbLocationDropdownValues + }).component(); + + this.locationDropdown.onValueChanged(() => { + this.updateEnabledInputBoxes(); + this.tryEnableAddReferenceButton(); + }); + + return { + component: this.locationDropdown, + title: constants.locationDropdown + }; + } + + /** + * Update the enabled input boxes based on what the location of the database reference selected in the dropdown is + * @param isSystemDb + */ + public updateEnabledInputBoxes(isSystemDb: boolean = false): void { + if (this.locationDropdown?.value === constants.sameDatabase) { + this.databaseNameTextbox!.enabled = false; + this.databaseVariableTextbox!.enabled = false; + this.serverNameTextbox!.enabled = false; + this.serverVariableTextbox!.enabled = false; + + // clear values in disabled fields + this.databaseNameTextbox!.value = ''; + this.databaseVariableTextbox!.value = ''; + this.serverNameTextbox!.value = ''; + this.serverVariableTextbox!.value = ''; + } else if (this.locationDropdown?.value === constants.differentDbSameServer) { + this.databaseNameTextbox!.enabled = true; + this.databaseVariableTextbox!.enabled = !isSystemDb; // database variable is only enabled for non-system database references + this.serverNameTextbox!.enabled = false; + this.serverVariableTextbox!.enabled = false; + + // clear values in disabled fields + this.databaseVariableTextbox!.value = isSystemDb ? '' : this.databaseVariableTextbox!.value; + this.serverNameTextbox!.value = ''; + this.serverVariableTextbox!.value = ''; + } else if (this.locationDropdown?.value === constants.differentDbDifferentServer) { + this.databaseNameTextbox!.enabled = true; + this.databaseVariableTextbox!.enabled = true; + this.serverNameTextbox!.enabled = true; + this.serverVariableTextbox!.enabled = true; + } + } + + private createVariableSection(): azdata.FormComponent { + // database name row + this.databaseNameTextbox = this.createInputBox(constants.databaseName, true); + const databaseNameRow = this.view!.modelBuilder.flexContainer().withItems([this.createLabel(constants.databaseName, true), this.databaseNameTextbox], { flex: '0 0 auto' }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component(); + + // database variable row + this.databaseVariableTextbox = this.createInputBox(constants.databaseVariable, false); + const databaseVariableRow = this.view!.modelBuilder.flexContainer().withItems([this.createLabel(constants.databaseVariable), this.databaseVariableTextbox], { flex: '0 0 auto' }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component(); + + // server name row + this.serverNameTextbox = this.createInputBox(constants.serverName, false); + const serverNameRow = this.view!.modelBuilder.flexContainer().withItems([this.createLabel(constants.serverName, true), this.serverNameTextbox], { flex: '0 0 auto' }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component(); + + // server variable row + this.serverVariableTextbox = this.createInputBox(constants.serverVariable, false); + const serverVariableRow = this.view!.modelBuilder.flexContainer().withItems([this.createLabel(constants.serverVariable, true), this.serverVariableTextbox], { flex: '0 0 auto' }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component(); + + const variableSection = this.view!.modelBuilder.flexContainer().withItems([databaseNameRow, databaseVariableRow, serverNameRow, serverVariableRow]).withLayout({ flexFlow: 'column' }).component(); + + return { + component: variableSection, + title: '' + }; + } + + private createLabel(value: string, required: boolean = false): azdata.TextComponent { + const label = this.view!.modelBuilder.text().withProperties({ + value: value, + width: cssStyles.addDatabaseReferenceDialogLabelWidth, + requiredIndicator: required + }).component(); + + return label; + } + + private createInputBox(ariaLabel: string, enabled: boolean): azdata.InputBoxComponent { + const inputBox = this.view!.modelBuilder.inputBox().withProperties({ + ariaLabel: ariaLabel, + enabled: enabled, + width: cssStyles.addDatabaseReferenceInputboxWidth + }).component(); + + inputBox.onTextChanged(() => { + this.tryEnableAddReferenceButton(); + }); + + return inputBox; + } + + /** + * Only enable Add reference button if all enabled fields are filled + */ + public tryEnableAddReferenceButton(): void { + switch (this.currentReferenceType) { + case ReferenceType.systemDb: { + this.dialog.okButton.enabled = !!this.databaseNameTextbox?.value; + break; + } + case ReferenceType.dacpac: { + this.dialog.okButton.enabled = this.dacpacFieldsRequiredFieldsFilled(); + break; + } + case ReferenceType.project: { + // TODO + } + } + } + + private dacpacFieldsRequiredFieldsFilled(): boolean { + return !!this.dacpacTextbox?.value && + ((this.locationDropdown?.value === constants.sameDatabase) + || (this.locationDropdown?.value === constants.differentDbSameServer && this.differentDatabaseSameServerRequiredFieldsFilled()) + || ((this.locationDropdown?.value === constants.differentDbDifferentServer && this.differentDatabaseDifferentServerRequiredFieldsFilled()))); + } + + private differentDatabaseSameServerRequiredFieldsFilled(): boolean { + return !!this.databaseNameTextbox?.value; + } + + private differentDatabaseDifferentServerRequiredFieldsFilled(): boolean { + return !!this.databaseNameTextbox?.value && !!this.serverNameTextbox?.value && !!this.serverVariableTextbox?.value; + } +} diff --git a/extensions/sql-database-projects/src/models/IDatabaseReferenceSettings.ts b/extensions/sql-database-projects/src/models/IDatabaseReferenceSettings.ts new file mode 100644 index 0000000000..b8c412b8bd --- /dev/null +++ b/extensions/sql-database-projects/src/models/IDatabaseReferenceSettings.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DatabaseReferenceLocation, SystemDatabase } from './project'; +import { Uri } from 'vscode'; + +export interface IDatabaseReferenceSettings { + databaseName: string; +} + +export interface ISystemDatabaseReferenceSettings extends IDatabaseReferenceSettings { + systemDb: SystemDatabase; +} + +export interface IDacpacReferenceSettings extends IDatabaseReferenceSettings { + databaseLocation: DatabaseReferenceLocation; + dacpacFileLocation: Uri; + databaseVariable?: string; + serverName?: string; + serverVariable?: string; +} diff --git a/extensions/sql-database-projects/src/models/project.ts b/extensions/sql-database-projects/src/models/project.ts index bdc26eb9e2..e05f0f2fe4 100644 --- a/extensions/sql-database-projects/src/models/project.ts +++ b/extensions/sql-database-projects/src/models/project.ts @@ -697,7 +697,8 @@ export enum EntryType { export enum DatabaseReferenceLocation { sameDatabase, - differentDatabaseSameServer + differentDatabaseSameServer, + differentDatabaseDifferentServer } export enum TargetPlatform { diff --git a/extensions/sql-database-projects/src/test/dialogs/addDatabaseReferenceDialog.test.ts b/extensions/sql-database-projects/src/test/dialogs/addDatabaseReferenceDialog.test.ts new file mode 100644 index 0000000000..415fb1faee --- /dev/null +++ b/extensions/sql-database-projects/src/test/dialogs/addDatabaseReferenceDialog.test.ts @@ -0,0 +1,114 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as should from 'should'; +import * as path from 'path'; +import * as baselines from '../baselines/baselines'; +import * as templates from '../../templates/templates'; +import * as testUtils from '../testUtils'; +import * as constants from '../../common/constants'; +import { AddDatabaseReferenceDialog, ReferenceType } from '../../dialogs/addDatabaseReferenceDialog'; + +describe('Add Database Reference Dialog', () => { + before(async function (): Promise { + await templates.loadTemplates(path.join(__dirname, '..', '..', '..', 'resources', 'templates')); + await baselines.loadBaselines(); + }); + + it('Should open dialog successfully', async function (): Promise { + const project = await testUtils.createTestProject(baselines.newProjectFileBaseline); + const dialog = new AddDatabaseReferenceDialog(project); + await dialog.openDialog(); + should.notEqual(dialog.addDatabaseReferenceTab, undefined); + }); + + it('Should enable ok button correctly', async function (): Promise { + const project = await testUtils.createTestProject(baselines.newProjectFileBaseline); + const dialog = new AddDatabaseReferenceDialog(project); + await dialog.openDialog(); + + should(dialog.dialog.okButton.enabled).equal(false); + should(dialog.currentReferenceType).equal(ReferenceType.systemDb); + dialog.tryEnableAddReferenceButton(); + should(dialog.dialog.okButton.enabled).equal(false); + + // fill in db name and ok button should be enabled + dialog.databaseNameTextbox!.value = 'dbName'; + dialog.tryEnableAddReferenceButton(); + should(dialog.dialog.okButton.enabled).equal(true, 'Ok button should be enabled after the database name textbox is filled'); + + // change to dacpac reference + dialog.dacpacRadioButtonClick(); + should(dialog.currentReferenceType).equal(ReferenceType.dacpac); + should(dialog.locationDropdown?.value).equal(constants.differentDbSameServer); + should(dialog.dialog.okButton.enabled).equal(false, 'Ok button should not be enabled because dacpac input box is not filled'); + + // fill in dacpac textbox + dialog.dacpacTextbox!.value = 'testDb.dacpac'; + dialog.tryEnableAddReferenceButton(); + should(dialog.dialog.okButton.enabled).equal(true, 'Ok button should be enabled after the dacpac textbox is filled'); + + // change location to different database, different server + dialog.locationDropdown!.value = constants.differentDbDifferentServer; + dialog.tryEnableAddReferenceButton(); + should(dialog.dialog.okButton.enabled).equal(false, 'Ok button should not be enabled because server fields are not filled'); + + // fill in server fields + dialog.serverNameTextbox!.value = 'serverName'; + dialog.serverVariableTextbox!.value = '$(serverName)'; + dialog.tryEnableAddReferenceButton(); + should(dialog.dialog.okButton.enabled).equal(true, 'Ok button should be enabled after server fields are filled'); + + // change location to same database + dialog.locationDropdown!.value = constants.sameDatabase; + dialog.tryEnableAddReferenceButton(); + should(dialog.dialog.okButton.enabled).equal(true, 'Ok button should be enabled because only dacpac location is needed for a reference located on the same database'); + + // change reference type back to system db + dialog.systemDbRadioButtonClick(); + should(dialog.databaseNameTextbox?.value).equal('', `Database name textbox should be empty. Actual:${dialog.databaseNameTextbox?.value}`); + should(dialog.dialog.okButton.enabled).equal(false, 'Ok button should not be enabled because database name is not filled out'); + }); + + it('Should enable and disable input boxes depending on the reference type', async function (): Promise { + const project = await testUtils.createTestProject(baselines.newProjectFileBaseline); + const dialog = new AddDatabaseReferenceDialog(project); + await dialog.openDialog(); + + // dialog starts with system db + should(dialog.currentReferenceType).equal(ReferenceType.systemDb); + validateInputBoxEnabledStates(dialog, { databaseNameEnabled: true, databaseVariableEnabled: false, serverNameEnabled: false, serverVariabledEnabled: false}); + + // change to dacpac reference + dialog.dacpacRadioButtonClick(); + should(dialog.currentReferenceType).equal(ReferenceType.dacpac); + should(dialog.locationDropdown!.value).equal(constants.differentDbSameServer); + validateInputBoxEnabledStates(dialog, { databaseNameEnabled: true, databaseVariableEnabled: true, serverNameEnabled: false, serverVariabledEnabled: false}); + + // change location to different db, different server + dialog.locationDropdown!.value = constants.differentDbDifferentServer; + dialog.updateEnabledInputBoxes(); + validateInputBoxEnabledStates(dialog, { databaseNameEnabled: true, databaseVariableEnabled: true, serverNameEnabled: true, serverVariabledEnabled: true}); + + // change location to same db + dialog.locationDropdown!.value = constants.sameDatabase; + dialog.updateEnabledInputBoxes(); + validateInputBoxEnabledStates(dialog, { databaseNameEnabled: false, databaseVariableEnabled: false, serverNameEnabled: false, serverVariabledEnabled: false}); + }); +}); + +interface inputBoxExpectedStates { + databaseNameEnabled: boolean; + databaseVariableEnabled: boolean; + serverNameEnabled: boolean; + serverVariabledEnabled: boolean; +} + +function validateInputBoxEnabledStates(dialog: AddDatabaseReferenceDialog, expectedStates: inputBoxExpectedStates): void { + should(dialog.databaseNameTextbox?.enabled).equal(expectedStates.databaseNameEnabled); + should(dialog.databaseVariableTextbox?.enabled).equal(expectedStates.databaseVariableEnabled); + should(dialog.serverNameTextbox?.enabled).equal(expectedStates.serverNameEnabled); + should(dialog.serverVariableTextbox?.enabled).equal(expectedStates.serverVariabledEnabled); +} diff --git a/extensions/sql-database-projects/src/test/publishDatabaseDialog.test.ts b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts similarity index 85% rename from extensions/sql-database-projects/src/test/publishDatabaseDialog.test.ts rename to extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts index 035a97f39d..0853f246ac 100644 --- a/extensions/sql-database-projects/src/test/publishDatabaseDialog.test.ts +++ b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts @@ -7,20 +7,20 @@ import * as should from 'should'; import * as path from 'path'; import * as os from 'os'; import * as vscode from 'vscode'; -import * as baselines from './baselines/baselines'; -import * as templates from '../templates/templates'; -import * as testUtils from './testUtils'; +import * as baselines from '../baselines/baselines'; +import * as templates from '../../templates/templates'; +import * as testUtils from '../testUtils'; import * as TypeMoq from 'typemoq'; -import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog'; -import { Project } from '../models/project'; -import { SqlDatabaseProjectTreeViewProvider } from '../controllers/databaseProjectTreeViewProvider'; -import { ProjectsController } from '../controllers/projectController'; -import { IPublishSettings, IGenerateScriptSettings } from '../models/IPublishSettings'; +import { PublishDatabaseDialog } from '../../dialogs/publishDatabaseDialog'; +import { Project } from '../../models/project'; +import { SqlDatabaseProjectTreeViewProvider } from '../../controllers/databaseProjectTreeViewProvider'; +import { ProjectsController } from '../../controllers/projectController'; +import { IPublishSettings, IGenerateScriptSettings } from '../../models/IPublishSettings'; describe.skip('Publish Database Dialog', () => { before(async function (): Promise { - await templates.loadTemplates(path.join(__dirname, '..', '..', 'resources', 'templates')); + await templates.loadTemplates(path.join(__dirname, '..', '..', '..', 'resources', 'templates')); await baselines.loadBaselines(); });