diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 8fdca5916f..6a10302e04 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -139,22 +139,24 @@ export const done = localize('done', "Done"); export const nameMustNotBeEmpty = localize('nameMustNotBeEmpty', "Name must not be empty"); // Deploy +export const SqlServerName = 'SQL server'; +export const AzureSqlServerName = 'Azure SQL server'; export const selectPublishOption = localize('selectPublishOption', "Select where to publish the project to"); -export const publishToExistingServer = localize('publishToExistingServer', "Publish to existing server"); -export const publishToDockerContainer = localize('publishToDockerContainer', "Publish to new server in a container"); -export const enterPortNumber = localize('enterPortNumber', "Enter SQL server port number or press enter to use the default value"); -export const serverPortNumber = localize('serverPortNumber', "SQL server port number"); -export const serverPassword = localize('serverPassword', "SQL Server admin password"); -export const confirmServerPassword = localize('confirmServerPassword', "Confirm SQL Server admin password"); -export const baseDockerImage = localize('baseDockerImage', "Base SQL Server Docker image"); +export function publishToExistingServer(name: string) { return localize('publishToExistingServer', "Publish to an existing {0}", name); } +export function publishToDockerContainer(name: string) { return localize('publishToDockerContainer', "Publish to new {0} local development container", name); } +export function enterPortNumber(name: string) { return localize('enterPortNumber', "Enter {0} port number or press enter to use the default value", name); } +export function serverPortNumber(name: string) { return localize('serverPortNumber', "{0} port number", name); } +export function serverPassword(name: string) { return localize('serverPassword', "{0} admin password", name); } +export function confirmServerPassword(name: string) { return localize('confirmServerPassword', "Confirm {0} admin password", name); } +export function baseDockerImage(name: string) { return localize('baseDockerImage', "Base {0} Docker image", name); } export const publishTo = localize('publishTo', "Publish Target"); export const enterConnectionStringEnvName = localize('enterConnectionStringEnvName', "Enter connection string environment variable name"); export const enterConnectionStringTemplate = localize('enterConnectionStringTemplate', "Enter connection string template"); -export const enterPassword = localize('enterPassword', "Enter SQL Server admin password"); -export const confirmPassword = localize('confirmPassword', "Confirm SQL server admin password"); -export const selectBaseImage = localize('selectBaseImage', "Select the base SQL Server docker image"); -export const invalidSQLPasswordMessage = localize('invalidSQLPassword', "SQL Server password doesn't meet the password complexity requirement. For more information see https://docs.microsoft.com/sql/relational-databases/security/password-policy"); -export const passwordNotMatch = localize('passwordNotMatch', "SQL Server password doesn't match the confirmation password"); +export function enterPassword(name: string) { return localize('enterPassword', "Enter {0} admin password", name); } +export function confirmPassword(name: string) { return localize('confirmPassword', "Confirm {0} admin password", name); } +export function selectBaseImage(name: string) { return localize('selectBaseImage', "Select the base {0} docker image", name); } +export function invalidSQLPasswordMessage(name: string) { return localize('invalidSQLPassword', "{0} password doesn't meet the password complexity requirement. For more information see https://docs.microsoft.com/sql/relational-databases/security/password-policy", name); } +export function passwordNotMatch(name: string) { return localize('passwordNotMatch', "{0} password doesn't match the confirmation password", name); } export const portMustBeNumber = localize('portMustNotBeNumber', "Port must a be number"); export const valueCannotBeEmpty = localize('valueCannotBeEmpty', "Value cannot be empty"); export const dockerImageLabelPrefix = 'source=sqldbproject'; @@ -533,3 +535,8 @@ export const defaultDSP = targetPlatformToVersion.get(defaultTargetPlatform)!; export function getTargetPlatformFromVersion(version: string): string { return Array.from(targetPlatformToVersion.keys()).filter(k => targetPlatformToVersion.get(k) === version)[0]; } + +export enum PublishTargetType { + existingServer = 'existingServer', + docker = 'docker', +} diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index 999fce5fc4..e560b5ca1f 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -339,14 +339,14 @@ export class ProjectsController { * Create flow for Publishing a database using only VS Code-native APIs such as QuickPick */ private async publishDatabase(project: Project): Promise { - const publishTarget = await launchPublishTargetOption(); + const publishTarget = await launchPublishTargetOption(project); // Return when user hits escape if (!publishTarget) { return undefined; } - if (publishTarget === constants.publishToDockerContainer) { + if (publishTarget === constants.PublishTargetType.docker) { const deployProfile = await launchPublishToDockerContainerQuickpick(project); if (deployProfile?.deploySettings) { await this.publishToDockerContainer(project, deployProfile); diff --git a/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts b/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts index eb81126935..ba9bfcc680 100644 --- a/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts +++ b/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts @@ -119,10 +119,11 @@ async function launchEulaQuickPick(baseImage: string): Promise { */ export async function launchPublishToDockerContainerQuickpick(project: Project): Promise { + const name = uiUtils.getPublishServerName(project.getProjectTargetVersion()); let localDbSetting: ILocalDbSetting | undefined; // Deploy to docker selected let portNumber = await vscode.window.showInputBox({ - title: constants.enterPortNumber, + title: constants.enterPortNumber(name), ignoreFocusOut: true, value: constants.defaultPortNumber, validateInput: input => !utils.validateSqlServerPortNumber(input) ? constants.portMustBeNumber : undefined @@ -136,10 +137,10 @@ export async function launchPublishToDockerContainerQuickpick(project: Project): let password: string | undefined = ''; password = await vscode.window.showInputBox({ - title: constants.enterPassword, + title: constants.enterPassword(name), ignoreFocusOut: true, value: password, - validateInput: input => !utils.isValidSQLPassword(input) ? constants.invalidSQLPasswordMessage : undefined, + validateInput: input => !utils.isValidSQLPassword(input) ? constants.invalidSQLPasswordMessage(name) : undefined, password: true } ); @@ -151,10 +152,10 @@ export async function launchPublishToDockerContainerQuickpick(project: Project): let confirmPassword: string | undefined = ''; confirmPassword = await vscode.window.showInputBox({ - title: constants.confirmPassword, + title: constants.confirmPassword(name), ignoreFocusOut: true, value: confirmPassword, - validateInput: input => input !== password ? constants.passwordNotMatch : undefined, + validateInput: input => input !== password ? constants.passwordNotMatch(name) : undefined, password: true } ); @@ -167,7 +168,7 @@ export async function launchPublishToDockerContainerQuickpick(project: Project): const baseImages = uiUtils.getDockerBaseImages(); const baseImage = await vscode.window.showQuickPick( baseImages.map(x => x.name), - { title: constants.selectBaseImage, ignoreFocusOut: true }); + { title: constants.selectBaseImage(name), ignoreFocusOut: true }); // Return when user hits escape if (!baseImage) { diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts index 6e667efdb4..c047340257 100644 --- a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts +++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts @@ -14,7 +14,7 @@ import { IDeploySettings } from '../models/IDeploySettings'; import { DeploymentOptions } from 'mssql'; import { IconPathHelper } from '../common/iconHelper'; import { cssStyles } from '../common/uiConstants'; -import { getAgreementDisplayText, getConnectionName, getDockerBaseImages } from './utils'; +import { getAgreementDisplayText, getConnectionName, getDockerBaseImages, getPublishServerName } from './utils'; import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; import { IDeployProfile } from '../models/deploy/deployProfile'; import { Deferred } from '../common/promise'; @@ -367,6 +367,7 @@ export class PublishDatabaseDialog { } private createPublishTypeRadioButtons(view: azdataType.ModelView): azdataType.Component { + const name = getPublishServerName(this.project.getProjectTargetVersion()); const publishToLabel = view.modelBuilder.text().withProps({ value: constants.publishTo, width: cssStyles.publishDialogLabelWidth @@ -374,7 +375,7 @@ export class PublishDatabaseDialog { this.existingServerRadioButton = view.modelBuilder.radioButton() .withProps({ name: 'publishType', - label: constants.publishToExistingServer + label: constants.publishToExistingServer(name) }).component(); this.existingServerRadioButton.checked = true; @@ -385,7 +386,7 @@ export class PublishDatabaseDialog { this.dockerServerRadioButton = view.modelBuilder.radioButton() .withProps({ name: 'publishType', - label: constants.publishToDockerContainer + label: constants.publishToDockerContainer(name) }).component(); this.dockerServerRadioButton.onDidChangeCheckedState((checked) => { @@ -539,10 +540,11 @@ export class PublishDatabaseDialog { } private createLocalDbInfoRow(view: azdataType.ModelView): azdataType.FlexContainer { + const name = getPublishServerName(this.project.getProjectTargetVersion()); this.serverPortTextBox = view.modelBuilder.inputBox().withProps({ value: constants.defaultPortNumber, - ariaLabel: constants.serverPortNumber, - placeHolder: constants.serverPortNumber, + ariaLabel: constants.serverPortNumber(name), + placeHolder: constants.serverPortNumber(name), width: cssStyles.publishDialogTextboxWidth, enabled: true, inputType: 'number', @@ -552,26 +554,26 @@ export class PublishDatabaseDialog { this.serverPortTextBox.onTextChanged(() => { this.tryEnableGenerateScriptAndOkButtons(); }); - const serverPortRow = this.createFormRow(view, constants.serverPortNumber, this.serverPortTextBox); + const serverPortRow = this.createFormRow(view, constants.serverPortNumber(name), this.serverPortTextBox); this.serverAdminPasswordTextBox = view.modelBuilder.inputBox().withProps({ value: '', - ariaLabel: constants.serverPassword, - placeHolder: constants.serverPassword, + ariaLabel: constants.serverPassword(name), + placeHolder: constants.serverPassword(name), width: cssStyles.publishDialogTextboxWidth, enabled: true, inputType: 'password', - validationErrorMessage: constants.invalidSQLPasswordMessage + validationErrorMessage: constants.invalidSQLPasswordMessage(name) }).withValidation(component => !utils.isEmptyString(component.value) && utils.isValidSQLPassword(component.value || '')).component(); - const serverPasswordRow = this.createFormRow(view, constants.serverPassword, this.serverAdminPasswordTextBox); + const serverPasswordRow = this.createFormRow(view, constants.serverPassword(name), this.serverAdminPasswordTextBox); this.serverConfigAdminPasswordTextBox = view.modelBuilder.inputBox().withProps({ value: '', - ariaLabel: constants.confirmServerPassword, - placeHolder: constants.confirmServerPassword, + ariaLabel: constants.confirmServerPassword(name), + placeHolder: constants.confirmServerPassword(name), width: cssStyles.publishDialogTextboxWidth, enabled: true, inputType: 'password', - validationErrorMessage: constants.passwordNotMatch + validationErrorMessage: constants.passwordNotMatch(name) }).withValidation(component => component.value === this.serverAdminPasswordTextBox?.value).component(); this.serverAdminPasswordTextBox.onTextChanged(() => { this.tryEnableGenerateScriptAndOkButtons(); @@ -582,18 +584,18 @@ export class PublishDatabaseDialog { this.serverConfigAdminPasswordTextBox.onTextChanged(() => { this.tryEnableGenerateScriptAndOkButtons(); }); - const serverConfirmPasswordRow = this.createFormRow(view, constants.confirmServerPassword, this.serverConfigAdminPasswordTextBox); + const serverConfirmPasswordRow = this.createFormRow(view, constants.confirmServerPassword(name), this.serverConfigAdminPasswordTextBox); const baseImages = getDockerBaseImages(); this.baseDockerImageDropDown = view.modelBuilder.dropDown().withProps({ values: baseImages.map(x => x.name), - ariaLabel: constants.baseDockerImage, + ariaLabel: constants.baseDockerImage(name), width: cssStyles.publishDialogTextboxWidth, enabled: true }).component(); const agreementInfo = baseImages[0].agreementInfo; - const dropDownRow = this.createFormRow(view, constants.baseDockerImage, this.baseDockerImageDropDown); + const dropDownRow = this.createFormRow(view, constants.baseDockerImage(name), this.baseDockerImageDropDown); this.eulaCheckBox = view.modelBuilder.checkBox().withProps({ ariaLabel: getAgreementDisplayText(agreementInfo), required: true diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts index b9dbd9d0c1..7876944fee 100644 --- a/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts +++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts @@ -11,6 +11,7 @@ import { promptForPublishProfile } from './publishDatabaseDialog'; import { getDefaultPublishDeploymentOptions, getVscodeMssqlApi } from '../common/utils'; import { IConnectionInfo } from 'vscode-mssql'; import { IDeploySettings } from '../models/IDeploySettings'; +import { getPublishServerName } from './utils'; /** * Create flow for Publishing a database using only VS Code-native APIs such as QuickPick @@ -206,11 +207,11 @@ export async function getPublishDatabaseSettings(project: Project, promptForConn return settings; } -export async function launchPublishTargetOption(): Promise { +export async function launchPublishTargetOption(project: Project): Promise { // Show options to user for deploy to existing server or docker - + const name = getPublishServerName(project.getProjectTargetVersion()); const publishOption = await vscode.window.showQuickPick( - [constants.publishToExistingServer, constants.publishToDockerContainer], + [constants.publishToExistingServer(name), constants.publishToDockerContainer(name)], { title: constants.selectPublishOption, ignoreFocusOut: true }); // Return when user hits escape @@ -218,6 +219,13 @@ export async function launchPublishTargetOption(): Promise { return undefined; } - return publishOption; + switch (publishOption) { + case constants.publishToExistingServer(name): + return constants.PublishTargetType.existingServer; + case constants.publishToDockerContainer(name): + return constants.PublishTargetType.docker; + default: + return constants.PublishTargetType.existingServer; + } } diff --git a/extensions/sql-database-projects/src/dialogs/utils.ts b/extensions/sql-database-projects/src/dialogs/utils.ts index d8668ce8d7..a2e49df05b 100644 --- a/extensions/sql-database-projects/src/dialogs/utils.ts +++ b/extensions/sql-database-projects/src/dialogs/utils.ts @@ -3,6 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { SqlTargetPlatform } from 'sqldbproj'; import * as constants from '../common/constants'; import { AgreementInfo, DockerImageInfo } from '../models/deploy/deployProfile'; @@ -30,6 +31,13 @@ export function getAgreementDisplayText(agreementInfo: AgreementInfo): string { return constants.eulaAgreementText(agreementInfo.link!.text); } +/** + * Returns the title for SQL server based on the target version + */ +export function getPublishServerName(target: string): string { + return target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ? constants.AzureSqlServerName : constants.SqlServerName; +} + export function getDockerBaseImages(): DockerImageInfo[] { return [ {