diff --git a/extensions/sql-database-projects/images/dark/refresh.svg b/extensions/sql-database-projects/images/dark/refresh.svg
new file mode 100644
index 0000000000..f03579110b
--- /dev/null
+++ b/extensions/sql-database-projects/images/dark/refresh.svg
@@ -0,0 +1,3 @@
+
diff --git a/extensions/sql-database-projects/images/light/refresh.svg b/extensions/sql-database-projects/images/light/refresh.svg
new file mode 100644
index 0000000000..f03579110b
--- /dev/null
+++ b/extensions/sql-database-projects/images/light/refresh.svg
@@ -0,0 +1,3 @@
+
diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts
index 658470b9d9..bc82b9315e 100644
--- a/extensions/sql-database-projects/src/common/constants.ts
+++ b/extensions/sql-database-projects/src/common/constants.ts
@@ -79,8 +79,9 @@ export const noDataSourcesText = localize('noDataSourcesText', "No data sources
export const loadProfileButtonText = localize('loadProfileButtonText', "Load Profile...");
export const profileReadError = localize('profileReadError', "Could not load the profile file.");
export const sqlCmdTableLabel = localize('sqlCmdTableLabel', "SQLCMD Variables");
-export const sqlCmdVariableColumn = localize('sqlCmdVariableColumn', "Variable");
+export const sqlCmdVariableColumn = localize('sqlCmdVariableColumn', "Name");
export const sqlCmdValueColumn = localize('sqlCmdValueColumn', "Value");
+export const loadSqlCmdVarsButtonTitle = localize('reloadValuesFromProjectButtonTitle', "Reload values from project");
// Error messages
diff --git a/extensions/sql-database-projects/src/common/iconHelper.ts b/extensions/sql-database-projects/src/common/iconHelper.ts
index 900b688a04..4034daf158 100644
--- a/extensions/sql-database-projects/src/common/iconHelper.ts
+++ b/extensions/sql-database-projects/src/common/iconHelper.ts
@@ -20,6 +20,8 @@ export class IconPathHelper {
public static referenceGroup: IconPath;
public static referenceDatabase: IconPath;
+ public static refresh: IconPath;
+
public static setExtensionContext(extensionContext: vscode.ExtensionContext) {
IconPathHelper.extensionContext = extensionContext;
@@ -30,6 +32,8 @@ export class IconPathHelper {
IconPathHelper.referenceGroup = IconPathHelper.makeIcon('referenceGroup');
IconPathHelper.referenceDatabase = IconPathHelper.makeIcon('reference-database');
+
+ IconPathHelper.refresh = IconPathHelper.makeIcon('refresh');
}
private static makeIcon(name: string) {
diff --git a/extensions/sql-database-projects/src/common/uiConstants.ts b/extensions/sql-database-projects/src/common/uiConstants.ts
new file mode 100644
index 0000000000..fb41ad494b
--- /dev/null
+++ b/extensions/sql-database-projects/src/common/uiConstants.ts
@@ -0,0 +1,12 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the Source EULA. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+// CSS Styles
+export namespace cssStyles {
+ export const text = { 'user-select': 'text', 'cursor': 'text' };
+ 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;
+}
diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts
index a0b5ba9b9f..dd7daa50fc 100644
--- a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts
+++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts
@@ -12,8 +12,8 @@ import { Project } from '../models/project';
import { SqlConnectionDataSource } from '../models/dataSources/sqlConnectionStringSource';
import { IPublishSettings, IGenerateScriptSettings } from '../models/IPublishSettings';
import { DeploymentOptions } from '../../../mssql/src/mssql';
-
-const titleFontSize = 12;
+import { IconPathHelper } from '../common/iconHelper';
+import { cssStyles } from '../common/uiConstants';
interface DataSourceDropdownValue extends azdata.CategoryValue {
dataSource: SqlConnectionDataSource;
@@ -31,13 +31,14 @@ export class PublishDatabaseDialog {
private connectionsRadioButton: azdata.RadioButtonComponent | undefined;
private dataSourcesRadioButton: azdata.RadioButtonComponent | undefined;
private loadProfileButton: azdata.ButtonComponent | undefined;
- private sqlCmdVariablesTable: azdata.TableComponent | undefined;
- private sqlCmdVariablesFormComponent: azdata.FormComponent | undefined;
+ private sqlCmdVariablesTable: azdata.DeclarativeTableComponent | undefined;
+ private sqlCmdVariablesFormComponentGroup: azdata.FormComponentGroup | undefined;
+ private loadSqlCmdVarsButton: azdata.ButtonComponent | undefined;
private formBuilder: azdata.FormBuilder | undefined;
private connectionId: string | undefined;
private connectionIsDataSource: boolean | undefined;
- private profileSqlCmdVars: Record | undefined;
+ private sqlCmdVars: Record | undefined;
private deploymentOptions: DeploymentOptions | undefined;
private toDispose: vscode.Disposable[] = [];
@@ -97,23 +98,21 @@ export class PublishDatabaseDialog {
});
this.loadProfileButton = this.createLoadProfileButton(view);
- this.sqlCmdVariablesTable = view.modelBuilder.table().withProperties({
- title: constants.sqlCmdTableLabel,
- data: this.convertSqlCmdVarsToTableFormat(this.project.sqlCmdVariables),
- columns: [
+ this.sqlCmdVariablesTable = this.createSqlCmdTable(view);
+ this.loadSqlCmdVarsButton = this.createLoadSqlCmdVarsButton(view);
+
+ this.sqlCmdVariablesFormComponentGroup = {
+ components: [
{
- value: constants.sqlCmdVariableColumn
+ title: '',
+ component: this.loadSqlCmdVarsButton
},
{
- value: constants.sqlCmdValueColumn,
- }],
- width: 400,
- height: 400
- }).component();
-
- this.sqlCmdVariablesFormComponent = {
- title: constants.sqlCmdTableLabel,
- component: this.sqlCmdVariablesTable
+ title: '',
+ component: this.sqlCmdVariablesTable
+ }
+ ],
+ title: constants.sqlCmdTableLabel
};
this.formBuilder = view.modelBuilder.formContainer()
@@ -146,7 +145,7 @@ export class PublishDatabaseDialog {
// add SQLCMD variables table if the project has any
if (Object.keys(this.project.sqlCmdVariables).length > 0) {
- this.formBuilder.addFormItem(this.sqlCmdVariablesFormComponent, { titleFontSize: titleFontSize });
+ this.formBuilder.addFormItem(this.sqlCmdVariablesFormComponentGroup, { titleFontSize: cssStyles.titleFontSize });
}
let formModel = this.formBuilder.component();
@@ -220,14 +219,8 @@ export class PublishDatabaseDialog {
}
private getSqlCmdVariablesForPublish(): Record {
- // get SQLCMD variables from project
- let sqlCmdVariables = { ...this.project.sqlCmdVariables };
-
- // update with SQLCMD variables loaded from profile if there are any
- for (const key in this.profileSqlCmdVars) {
- sqlCmdVariables[key] = this.profileSqlCmdVars[key];
- }
-
+ // get SQLCMD variables from table
+ let sqlCmdVariables = { ...this.sqlCmdVars };
return sqlCmdVariables;
}
@@ -346,6 +339,69 @@ export class PublishDatabaseDialog {
}
}
+ private createSqlCmdTable(view: azdata.ModelView): azdata.DeclarativeTableComponent {
+ this.sqlCmdVars = { ...this.project.sqlCmdVariables };
+
+ const table = view.modelBuilder.declarativeTable().withProperties({
+ ariaLabel: constants.sqlCmdTableLabel,
+ data: this.convertSqlCmdVarsToTableFormat(this.sqlCmdVars),
+ columns: [
+ {
+ displayName: constants.sqlCmdVariableColumn,
+ valueType: azdata.DeclarativeDataType.string,
+ width: '50%',
+ isReadOnly: true,
+ headerCssStyles: cssStyles.tableHeader,
+ rowCssStyles: cssStyles.tableRow
+ },
+ {
+ displayName: constants.sqlCmdValueColumn,
+ valueType: azdata.DeclarativeDataType.string,
+ width: '50%',
+ isReadOnly: false,
+ headerCssStyles: cssStyles.tableHeader,
+ rowCssStyles: cssStyles.tableRow
+ }],
+ width: '100%'
+ }).component();
+
+ table.onDataChanged(() => {
+ this.sqlCmdVars = {};
+ table.data.forEach((row) => {
+ (>this.sqlCmdVars)[row[0]] = row[1];
+ });
+
+ this.tryEnableGenerateScriptAndOkButtons();
+ });
+
+ return table;
+ }
+
+ private createLoadSqlCmdVarsButton(view: azdata.ModelView): azdata.ButtonComponent {
+ let loadSqlCmdVarsButton: azdata.ButtonComponent = view.modelBuilder.button().withProperties({
+ label: constants.loadSqlCmdVarsButtonTitle,
+ title: constants.loadSqlCmdVarsButtonTitle,
+ ariaLabel: constants.loadSqlCmdVarsButtonTitle,
+ width: '210px',
+ iconPath: IconPathHelper.refresh,
+ height: '18px',
+ CSSStyles: { 'font-size': '13px' }
+ }).component();
+
+ loadSqlCmdVarsButton.onDidClick(async () => {
+ this.sqlCmdVars = { ...this.project.sqlCmdVariables };
+
+ const data = this.convertSqlCmdVarsToTableFormat(this.getSqlCmdVariablesForPublish());
+ await (this.sqlCmdVariablesTable).updateProperties({
+ data: data
+ });
+
+ this.tryEnableGenerateScriptAndOkButtons();
+ });
+
+ return loadSqlCmdVarsButton;
+ }
+
private createEditConnectionButton(view: azdata.ModelView): azdata.Component {
let editConnectionButton: azdata.ButtonComponent = view.modelBuilder.button().withProperties({
label: constants.editConnectionButtonText,
@@ -419,22 +475,25 @@ export class PublishDatabaseDialog {
this.connectionId = result.connectionId;
(this.targetConnectionTextBox).value = result.connectionString;
- this.deploymentOptions = result.options;
- this.profileSqlCmdVars = result.sqlCmdVariables;
- const data = this.convertSqlCmdVarsToTableFormat(this.getSqlCmdVariablesForPublish());
+ for (let key in result.sqlCmdVariables) {
+ (>this.sqlCmdVars)[key] = result.sqlCmdVariables[key];
+ }
- await (this.sqlCmdVariablesTable).updateProperties({
+ this.deploymentOptions = result.options;
+
+ const data = this.convertSqlCmdVarsToTableFormat(this.getSqlCmdVariablesForPublish());
+ await (this.sqlCmdVariablesTable).updateProperties({
data: data
});
if (Object.keys(result.sqlCmdVariables).length) {
// add SQLCMD Variables table if it wasn't there before
if (Object.keys(this.project.sqlCmdVariables).length === 0) {
- this.formBuilder?.addFormItem(this.sqlCmdVariablesFormComponent, { titleFontSize: titleFontSize });
+ this.formBuilder?.addFormItem(this.sqlCmdVariablesFormComponentGroup, { titleFontSize: cssStyles.titleFontSize });
}
} else if (Object.keys(this.project.sqlCmdVariables).length === 0) {
// remove the table if there are no SQLCMD variables in the project and loaded profile
- this.formBuilder?.removeFormItem(this.sqlCmdVariablesFormComponent);
+ this.formBuilder?.removeFormItem(this.sqlCmdVariablesFormComponentGroup);
}
}
});
@@ -453,8 +512,9 @@ export class PublishDatabaseDialog {
// only enable Generate Script and Ok buttons if all fields are filled
private tryEnableGenerateScriptAndOkButtons(): void {
- if (this.targetConnectionTextBox!.value && this.targetDatabaseTextBox!.value
- || this.connectionIsDataSource && this.targetDatabaseTextBox!.value) {
+ if ((this.targetConnectionTextBox!.value && this.targetDatabaseTextBox!.value
+ || this.connectionIsDataSource && this.targetDatabaseTextBox!.value)
+ && this.allSqlCmdVariablesFilled()) {
this.dialog.okButton.enabled = true;
this.dialog.customButtons[0].enabled = true;
} else {
@@ -462,4 +522,14 @@ export class PublishDatabaseDialog {
this.dialog.customButtons[0].enabled = false;
}
}
+
+ private allSqlCmdVariablesFilled(): boolean {
+ for (let key in this.sqlCmdVars) {
+ if (this.sqlCmdVars[key] === '' || this.sqlCmdVars[key] === undefined) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts
index 08de8a33f2..44d3b8cc8a 100644
--- a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts
+++ b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts
@@ -52,7 +52,6 @@ export async function load(profileUri: Uri, dacfxService: mssql.IDacFxService):
};
}
-
async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string, connectionString: string }> {
let targetConnectionString: string = '';
let connId: string = '';