diff --git a/extensions/sql-database-projects/images/connect.svg b/extensions/sql-database-projects/images/connect.svg
new file mode 100644
index 0000000000..29e7182774
--- /dev/null
+++ b/extensions/sql-database-projects/images/connect.svg
@@ -0,0 +1,3 @@
+
diff --git a/extensions/sql-database-projects/images/dark/edit.svg b/extensions/sql-database-projects/images/dark/edit.svg
deleted file mode 100644
index 345362da0a..0000000000
--- a/extensions/sql-database-projects/images/dark/edit.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/extensions/sql-database-projects/images/dark/folder_blue.svg b/extensions/sql-database-projects/images/folder_blue.svg
similarity index 100%
rename from extensions/sql-database-projects/images/dark/folder_blue.svg
rename to extensions/sql-database-projects/images/folder_blue.svg
diff --git a/extensions/sql-database-projects/images/light/edit.svg b/extensions/sql-database-projects/images/light/edit.svg
deleted file mode 100644
index 345362da0a..0000000000
--- a/extensions/sql-database-projects/images/light/edit.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/extensions/sql-database-projects/images/light/folder_blue.svg b/extensions/sql-database-projects/images/light/folder_blue.svg
deleted file mode 100644
index 64cbba1769..0000000000
--- a/extensions/sql-database-projects/images/light/folder_blue.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/extensions/sql-database-projects/images/light/refresh.svg b/extensions/sql-database-projects/images/light/refresh.svg
deleted file mode 100644
index f03579110b..0000000000
--- a/extensions/sql-database-projects/images/light/refresh.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/extensions/sql-database-projects/images/dark/refresh.svg b/extensions/sql-database-projects/images/refresh.svg
similarity index 100%
rename from extensions/sql-database-projects/images/dark/refresh.svg
rename to extensions/sql-database-projects/images/refresh.svg
diff --git a/extensions/sql-database-projects/images/selectConnection.svg b/extensions/sql-database-projects/images/selectConnection.svg
new file mode 100644
index 0000000000..44d7aa82f9
--- /dev/null
+++ b/extensions/sql-database-projects/images/selectConnection.svg
@@ -0,0 +1,10 @@
+
diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts
index fa73bc285f..9e11c2585d 100644
--- a/extensions/sql-database-projects/src/common/constants.ts
+++ b/extensions/sql-database-projects/src/common/constants.ts
@@ -87,7 +87,8 @@ export const sqlCmdValueColumn = localize('sqlCmdValueColumn', "Value");
export const loadSqlCmdVarsButtonTitle = localize('reloadValuesFromProjectButtonTitle', "Reload values from project");
export const profile = localize('profile', "Profile");
export const selectConnection = localize('selectConnection', "Select connection");
-export const connection = localize('connection', "Connection");
+export const server = localize('server', "Server");
+export const defaultUser = localize('default', "default");
// Add Database Reference dialog strings
diff --git a/extensions/sql-database-projects/src/common/iconHelper.ts b/extensions/sql-database-projects/src/common/iconHelper.ts
index 4af64960b3..b92bb4d2ec 100644
--- a/extensions/sql-database-projects/src/common/iconHelper.ts
+++ b/extensions/sql-database-projects/src/common/iconHelper.ts
@@ -22,7 +22,8 @@ export class IconPathHelper {
public static refresh: IconPath;
public static folder_blue: IconPath;
- public static edit: IconPath;
+ public static selectConnection: IconPath;
+ public static connect: IconPath;
public static folder: IconPath;
@@ -37,19 +38,27 @@ export class IconPathHelper {
IconPathHelper.referenceGroup = IconPathHelper.makeIcon('referenceGroup');
IconPathHelper.referenceDatabase = IconPathHelper.makeIcon('reference-database');
- IconPathHelper.refresh = IconPathHelper.makeIcon('refresh');
- IconPathHelper.folder_blue = IconPathHelper.makeIcon('folder_blue');
- IconPathHelper.edit = IconPathHelper.makeIcon('edit');
+ IconPathHelper.refresh = IconPathHelper.makeIcon('refresh', true);
+ IconPathHelper.folder_blue = IconPathHelper.makeIcon('folder_blue', true);
+ IconPathHelper.selectConnection = IconPathHelper.makeIcon('selectConnection', true);
+ IconPathHelper.connect = IconPathHelper.makeIcon('connect', true);
IconPathHelper.folder = IconPathHelper.makeIcon('folder');
}
- private static makeIcon(name: string) {
+ private static makeIcon(name: string, sameIcon: boolean = false) {
const folder = 'images';
- return {
- dark: IconPathHelper.extensionContext.asAbsolutePath(`${folder}/dark/${name}.svg`),
- light: IconPathHelper.extensionContext.asAbsolutePath(`${folder}/light/${name}.svg`)
- };
+ if (sameIcon) {
+ return {
+ dark: IconPathHelper.extensionContext.asAbsolutePath(`${folder}/${name}.svg`),
+ light: IconPathHelper.extensionContext.asAbsolutePath(`${folder}/${name}.svg`)
+ };
+ } else {
+ return {
+ dark: IconPathHelper.extensionContext.asAbsolutePath(`${folder}/dark/${name}.svg`),
+ light: IconPathHelper.extensionContext.asAbsolutePath(`${folder}/light/${name}.svg`)
+ };
+ }
}
}
diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts
index 6ed2aaae98..a1985129d9 100644
--- a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts
+++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts
@@ -269,7 +269,8 @@ export class PublishDatabaseDialog {
value: '',
ariaLabel: constants.targetConnectionLabel,
placeHolder: constants.selectConnection,
- width: cssStyles.publishDialogTextboxWidth
+ width: cssStyles.publishDialogTextboxWidth,
+ enabled: false
}).component();
this.targetConnectionTextBox.onTextChanged(() => {
@@ -350,13 +351,13 @@ export class PublishDatabaseDialog {
this.targetConnectionTextBox = this.createTargetConnectionComponent(view);
const selectConnectionButton: azdata.Component = this.createSelectConnectionButton(view);
- const connectionLabel = view.modelBuilder.text().withProperties({
- value: constants.connection,
+ const serverLabel = view.modelBuilder.text().withProperties({
+ value: constants.server,
requiredIndicator: true,
width: cssStyles.publishDialogLabelWidth
}).component();
- const connectionRow = view.modelBuilder.flexContainer().withItems([connectionLabel, this.targetConnectionTextBox], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
+ const connectionRow = view.modelBuilder.flexContainer().withItems([serverLabel, this.targetConnectionTextBox], { flex: '0 0 auto', CSSStyles: { 'margin-right': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
connectionRow.insertItem(selectConnectionButton, 2, { CSSStyles: { 'margin-right': '0px' } });
return connectionRow;
@@ -410,7 +411,7 @@ export class PublishDatabaseDialog {
headerCssStyles: cssStyles.tableHeader,
rowCssStyles: cssStyles.tableRow
}],
- width: '410px'
+ width: '420px'
}).component();
table.onDataChanged(() => {
@@ -453,7 +454,7 @@ export class PublishDatabaseDialog {
private createSelectConnectionButton(view: azdata.ModelView): azdata.Component {
let selectConnectionButton: azdata.ButtonComponent = view.modelBuilder.button().withProperties({
ariaLabel: constants.selectConnection,
- iconPath: IconPathHelper.edit,
+ iconPath: IconPathHelper.selectConnection,
height: '16px',
width: '16px'
}).component();
@@ -462,29 +463,47 @@ export class PublishDatabaseDialog {
let connection = await azdata.connection.openConnectionDialog();
this.connectionId = connection.connectionId;
- // show connection name if there is one, otherwise show connection string
+ // show connection name if there is one, otherwise show connection in format that shows in OE
+ let connectionTextboxValue: string;
if (connection.options['connectionName']) {
- this.targetConnectionTextBox!.value = connection.options['connectionName'];
+ connectionTextboxValue = connection.options['connectionName'];
} else {
- this.targetConnectionTextBox!.value = await azdata.connection.getConnectionString(connection.connectionId, false);
+ let user = connection.options['user'];
+ if (!user) {
+ user = constants.defaultUser;
+ }
+
+ connectionTextboxValue = `${connection.options['server']} (${user})`;
}
- // populate database dropdown with the databases for this connection
- const databaseValues = (await azdata.connection.listDatabases(this.connectionId))
- // filter out system dbs
- .filter(db => constants.systemDbs.find(systemdb => db === systemdb) === undefined);
-
- this.targetDatabaseDropDown!.values = databaseValues;
+ this.updateConnectionComponents(connectionTextboxValue, this.connectionId);
// change the database inputbox value to the connection's database if there is one
if (connection.options.database && connection.options.database !== constants.master) {
this.targetDatabaseDropDown!.value = connection.options.database;
}
+
+ // change icon to the one without a plus sign
+ selectConnectionButton.iconPath = IconPathHelper.connect;
});
return selectConnectionButton;
}
+ private async updateConnectionComponents(connectionTextboxValue: string, connectionId: string) {
+ this.targetConnectionTextBox!.value = connectionTextboxValue;
+ this.targetConnectionTextBox!.placeHolder = connectionTextboxValue;
+
+ // populate database dropdown with the databases for this connection
+ if (connectionId) {
+ const databaseValues = (await azdata.connection.listDatabases(connectionId))
+ // filter out system dbs
+ .filter(db => constants.systemDbs.find(systemdb => db === systemdb) === undefined);
+
+ this.targetDatabaseDropDown!.values = databaseValues;
+ }
+ }
+
private createLoadProfileButton(view: azdata.ModelView): azdata.ButtonComponent {
let loadProfileButton: azdata.ButtonComponent = view.modelBuilder.button().withProperties({
ariaLabel: constants.loadProfilePlaceholderText,
@@ -512,10 +531,12 @@ export class PublishDatabaseDialog {
if (this.readPublishProfile) {
const result = await this.readPublishProfile(fileUris[0]);
+ // clear out old database dropdown values. They'll get populated later if there was a connection specified in the profile
+ (this.targetDatabaseDropDown).values = [];
(this.targetDatabaseDropDown).value = result.databaseName;
this.connectionId = result.connectionId;
- (this.targetConnectionTextBox).value = result.connectionString;
+ await this.updateConnectionComponents(result.connection, this.connectionId);
for (let key in result.sqlCmdVariables) {
(>this.sqlCmdVars)[key] = result.sqlCmdVariables[key];
@@ -538,8 +559,9 @@ export class PublishDatabaseDialog {
this.formBuilder?.removeFormItem(this.sqlCmdVariablesFormComponentGroup);
}
- // show file path in text box
+ // show file path in text box and hover text
this.loadProfileTextBox!.value = fileUris[0].fsPath;
+ this.loadProfileTextBox!.placeHolder = fileUris[0].fsPath;
}
});
diff --git a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts
index 44d3b8cc8a..a758fe84bb 100644
--- a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts
+++ b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts
@@ -17,7 +17,7 @@ import { SqlConnectionDataSource } from '../dataSources/sqlConnectionStringSourc
export interface PublishProfile {
databaseName: string;
connectionId: string;
- connectionString: string;
+ connection: string;
sqlCmdVariables: Record;
options?: mssql.DeploymentOptions;
}
@@ -46,38 +46,46 @@ export async function load(profileUri: Uri, dacfxService: mssql.IDacFxService):
return {
databaseName: targetDbName,
connectionId: connectionInfo.connectionId,
- connectionString: connectionInfo.connectionString,
+ connection: connectionInfo.connection,
sqlCmdVariables: sqlCmdVariables,
options: optionsResult.deploymentOptions
};
}
-async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string, connectionString: string }> {
- let targetConnectionString: string = '';
+async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string, connection: string }> {
+ let targetConnection: string = '';
let connId: string = '';
if (xmlDoc.documentElement.getElementsByTagName(constants.targetConnectionString).length > 0) {
- targetConnectionString = xmlDoc.documentElement.getElementsByTagName(constants.TargetConnectionString)[0].textContent;
+ const targetConnectionString = xmlDoc.documentElement.getElementsByTagName(constants.TargetConnectionString)[0].textContent;
const dataSource = new SqlConnectionDataSource('temp', targetConnectionString);
+ let server: string = '';
+ let username: string = '';
const connectionProfile = dataSource.getConnectionProfile();
try {
if (dataSource.integratedSecurity) {
- connId = (await azdata.connection.connect(connectionProfile, false, false)).connectionId;
+ const connection = await azdata.connection.connect(connectionProfile, false, false);
+ connId = connection.connectionId;
+ server = dataSource.server;
+ username = constants.defaultUser;
}
else {
- connId = (await azdata.connection.openConnectionDialog(undefined, connectionProfile)).connectionId;
+ const connection = await azdata.connection.openConnectionDialog(undefined, connectionProfile);
+ connId = connection.connectionId;
+ server = connection.options['server'];
+ username = connection.options['username'];
}
+
+ targetConnection = `${server} (${username})`;
} catch (err) {
throw new Error(constants.unableToCreatePublishConnection(utils.getErrorMessage(err)));
}
}
- // mask password in connection string
- targetConnectionString = await azdata.connection.getConnectionString(connId, false);
return {
connectionId: connId,
- connectionString: targetConnectionString
+ connection: targetConnection
};
}
diff --git a/extensions/sql-database-projects/src/test/publishProfile.test.ts b/extensions/sql-database-projects/src/test/publishProfile.test.ts
index adcfbc6a9a..daf0a7d000 100644
--- a/extensions/sql-database-projects/src/test/publishProfile.test.ts
+++ b/extensions/sql-database-projects/src/test/publishProfile.test.ts
@@ -43,16 +43,14 @@ describe('Publish profile tests', function (): void {
testContext.dacFxService.setup(x => x.getOptionsFromProfile(TypeMoq.It.isAny())).returns(async () => {
return Promise.resolve(mockDacFxOptionsResult);
});
- const connectionString = 'Data Source=testserver;Integrated Security=true;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True';
sinon.stub(azdata.connection, 'connect').resolves(connectionResult);
- sinon.stub(azdata.connection, 'getConnectionString').resolves(connectionString);
let result = await load(vscode.Uri.file(profilePath), testContext.dacFxService.object);
should(result.databaseName).equal('targetDb');
should(Object.keys(result.sqlCmdVariables).length).equal(1);
should(result.sqlCmdVariables['ProdDatabaseName']).equal('MyProdDatabase');
should(result.connectionId).equal('connId');
- should(result.connectionString).equal('Data Source=testserver;Integrated Security=true;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True');
+ should(result.connection).equal('testserver (default)');
should(result.options).equal(mockDacFxOptionsResult.deploymentOptions);
});
@@ -62,21 +60,22 @@ describe('Publish profile tests', function (): void {
const connectionResult = {
providerName: 'MSSQL',
connectionId: 'connId',
- options: {}
+ options: {
+ 'server': 'testserver',
+ 'username': 'testUser'
+ }
};
testContext.dacFxService.setup(x => x.getOptionsFromProfile(TypeMoq.It.isAny())).returns(async () => {
return Promise.resolve(mockDacFxOptionsResult);
});
- const connectionString = 'Data Source=testserver;User Id=testUser;Password=******;Integrated Security=false;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True';
sinon.stub(azdata.connection, 'openConnectionDialog').resolves(connectionResult);
- sinon.stub(azdata.connection, 'getConnectionString').resolves(connectionString);
let result = await load(vscode.Uri.file(profilePath), testContext.dacFxService.object);
should(result.databaseName).equal('targetDb');
should(Object.keys(result.sqlCmdVariables).length).equal(1);
should(result.sqlCmdVariables['ProdDatabaseName']).equal('MyProdDatabase');
should(result.connectionId).equal('connId');
- should(result.connectionString).equal('Data Source=testserver;User Id=testUser;Password=******;Integrated Security=false;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True');
+ should(result.connection).equal('testserver (testUser)');
should(result.options).equal(mockDacFxOptionsResult.deploymentOptions);
});
@@ -85,9 +84,7 @@ describe('Publish profile tests', function (): void {
let profilePath = await testUtils.createTestFile(baselines.publishProfileIntegratedSecurityBaseline, 'publishProfile.publish.xml');
const projController = new ProjectsController(new SqlDatabaseProjectTreeViewProvider());
- const connectionString = 'Data Source=testserver;Integrated Security=true;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True';
sinon.stub(azdata.connection, 'connect').throws(new Error('Could not connect'));
- sinon.stub(azdata.connection, 'getConnectionString').resolves(connectionString);
await testUtils.shouldThrowSpecificError(async () => await projController.readPublishProfileCallback(vscode.Uri.file(profilePath)), constants.unableToCreatePublishConnection('Could not connect'));
});