Make sql project publish SQLCMD table editable (#11812)

* make table editable

* add button to load values from sqlproj

* use form component group

* match mockups

* move UI constants to a separate file

* fix error
This commit is contained in:
Kim Santiago
2020-08-18 12:04:12 -07:00
committed by GitHub
parent b16c6f3faa
commit 17856855f6
7 changed files with 130 additions and 38 deletions

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.1328 0.296875C10.9974 0.53125 11.7891 0.898438 12.5078 1.39844C13.2266 1.89323 13.8438 2.48177 14.3594 3.16406C14.8802 3.84115 15.2839 4.59375 15.5703 5.42188C15.8568 6.24479 16 7.10417 16 8C16 8.73438 15.9036 9.44271 15.7109 10.125C15.5234 10.8073 15.2552 11.4453 14.9062 12.0391C14.5625 12.6328 14.1458 13.1745 13.6562 13.6641C13.1719 14.1484 12.6328 14.5651 12.0391 14.9141C11.4453 15.2578 10.8073 15.526 10.125 15.7188C9.44271 15.9062 8.73438 16 8 16C7.26562 16 6.55729 15.9062 5.875 15.7188C5.19271 15.526 4.55469 15.2578 3.96094 14.9141C3.36719 14.5651 2.82552 14.1484 2.33594 13.6641C1.85156 13.1745 1.4349 12.6328 1.08594 12.0391C0.742188 11.4453 0.473958 10.8099 0.28125 10.1328C0.09375 9.45052 0 8.73958 0 8C0 7.27083 0.0963542 6.5625 0.289062 5.875C0.481771 5.1875 0.755208 4.54167 1.10938 3.9375C1.46875 3.32812 1.90365 2.77604 2.41406 2.28125C2.92448 1.78125 3.5 1.35417 4.14062 1H2V0H6V4H5V1.67969C4.39062 1.97135 3.83854 2.33854 3.34375 2.78125C2.85417 3.21875 2.4349 3.71354 2.08594 4.26562C1.73698 4.8125 1.46875 5.40365 1.28125 6.03906C1.09375 6.67448 1 7.32812 1 8C1 8.64062 1.08333 9.26042 1.25 9.85938C1.41667 10.4531 1.65104 11.0104 1.95312 11.5312C2.26042 12.0469 2.6276 12.5182 3.05469 12.9453C3.48177 13.3724 3.95312 13.7396 4.46875 14.0469C4.98958 14.349 5.54688 14.5833 6.14062 14.75C6.73438 14.9167 7.35417 15 8 15C8.64062 15 9.25781 14.9167 9.85156 14.75C10.4505 14.5833 11.0078 14.349 11.5234 14.0469C12.0443 13.7396 12.5182 13.3724 12.9453 12.9453C13.3724 12.5182 13.737 12.0469 14.0391 11.5312C14.3464 11.0104 14.5833 10.4531 14.75 9.85938C14.9167 9.26562 15 8.64583 15 8C15 7.21875 14.8724 6.46615 14.6172 5.74219C14.3672 5.01823 14.0156 4.35938 13.5625 3.76562C13.1094 3.17188 12.5677 2.65885 11.9375 2.22656C11.3125 1.78906 10.6224 1.46615 9.86719 1.25781L10.1328 0.296875Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.1328 0.296875C10.9974 0.53125 11.7891 0.898438 12.5078 1.39844C13.2266 1.89323 13.8438 2.48177 14.3594 3.16406C14.8802 3.84115 15.2839 4.59375 15.5703 5.42188C15.8568 6.24479 16 7.10417 16 8C16 8.73438 15.9036 9.44271 15.7109 10.125C15.5234 10.8073 15.2552 11.4453 14.9062 12.0391C14.5625 12.6328 14.1458 13.1745 13.6562 13.6641C13.1719 14.1484 12.6328 14.5651 12.0391 14.9141C11.4453 15.2578 10.8073 15.526 10.125 15.7188C9.44271 15.9062 8.73438 16 8 16C7.26562 16 6.55729 15.9062 5.875 15.7188C5.19271 15.526 4.55469 15.2578 3.96094 14.9141C3.36719 14.5651 2.82552 14.1484 2.33594 13.6641C1.85156 13.1745 1.4349 12.6328 1.08594 12.0391C0.742188 11.4453 0.473958 10.8099 0.28125 10.1328C0.09375 9.45052 0 8.73958 0 8C0 7.27083 0.0963542 6.5625 0.289062 5.875C0.481771 5.1875 0.755208 4.54167 1.10938 3.9375C1.46875 3.32812 1.90365 2.77604 2.41406 2.28125C2.92448 1.78125 3.5 1.35417 4.14062 1H2V0H6V4H5V1.67969C4.39062 1.97135 3.83854 2.33854 3.34375 2.78125C2.85417 3.21875 2.4349 3.71354 2.08594 4.26562C1.73698 4.8125 1.46875 5.40365 1.28125 6.03906C1.09375 6.67448 1 7.32812 1 8C1 8.64062 1.08333 9.26042 1.25 9.85938C1.41667 10.4531 1.65104 11.0104 1.95312 11.5312C2.26042 12.0469 2.6276 12.5182 3.05469 12.9453C3.48177 13.3724 3.95312 13.7396 4.46875 14.0469C4.98958 14.349 5.54688 14.5833 6.14062 14.75C6.73438 14.9167 7.35417 15 8 15C8.64062 15 9.25781 14.9167 9.85156 14.75C10.4505 14.5833 11.0078 14.349 11.5234 14.0469C12.0443 13.7396 12.5182 13.3724 12.9453 12.9453C13.3724 12.5182 13.737 12.0469 14.0391 11.5312C14.3464 11.0104 14.5833 10.4531 14.75 9.85938C14.9167 9.26562 15 8.64583 15 8C15 7.21875 14.8724 6.46615 14.6172 5.74219C14.3672 5.01823 14.0156 4.35938 13.5625 3.76562C13.1094 3.17188 12.5677 2.65885 11.9375 2.22656C11.3125 1.78906 10.6224 1.46615 9.86719 1.25781L10.1328 0.296875Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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<string, string> | undefined;
private sqlCmdVars: Record<string, string> | 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: <azdata.TableComponent>this.sqlCmdVariablesTable
title: '',
component: <azdata.DeclarativeTableComponent>this.sqlCmdVariablesTable
}
],
title: constants.sqlCmdTableLabel
};
this.formBuilder = <azdata.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<string, string> {
// 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<azdata.DeclarativeTableProperties>({
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) => {
(<Record<string, string>>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 (<azdata.DeclarativeTableComponent>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;
(<azdata.InputBoxComponent>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) {
(<Record<string, string>>this.sqlCmdVars)[key] = result.sqlCmdVariables[key];
}
await (<azdata.TableComponent>this.sqlCmdVariablesTable).updateProperties({
this.deploymentOptions = result.options;
const data = this.convertSqlCmdVarsToTableFormat(this.getSqlCmdVariablesForPublish());
await (<azdata.DeclarativeTableComponent>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(<azdata.FormComponent>this.sqlCmdVariablesFormComponent, { titleFontSize: titleFontSize });
this.formBuilder?.addFormItem(<azdata.FormComponentGroup>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(<azdata.FormComponent>this.sqlCmdVariablesFormComponent);
this.formBuilder?.removeFormItem(<azdata.FormComponentGroup>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;
}
}

View File

@@ -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 = '';