From f3fcaa21da15e1784b2d2baccff4ddf55ac749dc Mon Sep 17 00:00:00 2001
From: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com>
Date: Fri, 28 Oct 2022 19:43:43 -0700
Subject: [PATCH] Show Trust server certificate on dialog and fix bool
select-box defaults (#21020)
---
extensions/cms/package.json | 7 ++--
extensions/mssql/package.json | 7 ++--
.../base/browser/ui/selectBox/selectBox.ts | 6 +--
src/sql/media/icons/common-icons.css | 10 +++++
src/sql/media/icons/info_inverse.svg | 1 +
.../workbench/browser/modal/dialogHelper.ts | 12 ++++--
src/sql/workbench/common/sqlWorkbenchUtils.ts | 37 +++++++++++++++++++
.../connection/browser/connectionWidget.ts | 19 +++++++---
.../browser/media/connectionDialog.css | 10 +++++
9 files changed, 91 insertions(+), 18 deletions(-)
create mode 100644 src/sql/media/icons/info_inverse.svg
diff --git a/extensions/cms/package.json b/extensions/cms/package.json
index eb99baf9f5..a4d4bc88e6 100644
--- a/extensions/cms/package.json
+++ b/extensions/cms/package.json
@@ -224,7 +224,7 @@
"description": "%cms.connectionOptions.encrypt.description%",
"groupName": "%cms.connectionOptions.groupName.security%",
"valueType": "boolean",
- "defaultValue": null,
+ "defaultValue": "true",
"objectType": null,
"categoryValues": null,
"isRequired": false,
@@ -253,11 +253,12 @@
"description": "%cms.connectionOptions.trustServerCertificate.description%",
"groupName": "%cms.connectionOptions.groupName.security%",
"valueType": "boolean",
- "defaultValue": null,
+ "defaultValue": "false",
"objectType": null,
"categoryValues": null,
"isRequired": false,
- "isArray": false
+ "isArray": false,
+ "showOnConnectionDialog": true
},
{
"specialValueType": null,
diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json
index a979a9d048..9ad87a4f93 100644
--- a/extensions/mssql/package.json
+++ b/extensions/mssql/package.json
@@ -1042,7 +1042,7 @@
"description": "%mssql.connectionOptions.encrypt.description%",
"groupName": "%mssql.connectionOptions.groupName.security%",
"valueType": "boolean",
- "defaultValue": null,
+ "defaultValue": "true",
"objectType": null,
"categoryValues": null,
"isRequired": false,
@@ -1071,11 +1071,12 @@
"description": "%mssql.connectionOptions.trustServerCertificate.description%",
"groupName": "%mssql.connectionOptions.groupName.security%",
"valueType": "boolean",
- "defaultValue": null,
+ "defaultValue": "false",
"objectType": null,
"categoryValues": null,
"isRequired": false,
- "isArray": false
+ "isArray": false,
+ "showOnConnectionDialog": true
},
{
"specialValueType": null,
diff --git a/src/sql/base/browser/ui/selectBox/selectBox.ts b/src/sql/base/browser/ui/selectBox/selectBox.ts
index f30872c363..832f45434a 100644
--- a/src/sql/base/browser/ui/selectBox/selectBox.ts
+++ b/src/sql/base/browser/ui/selectBox/selectBox.ts
@@ -77,7 +77,7 @@ export class SelectBox extends vsSelectBox {
this.populateOptionsDictionary(optionItems);
this._dialogOptions = optionItems;
const option = this._optionsDictionary.get(selectedOption);
- if (option) {
+ if (option !== undefined) {
super.select(option);
}
@@ -195,10 +195,10 @@ export class SelectBox extends vsSelectBox {
public selectWithOptionName(optionName?: string): void {
let option: number | undefined;
- if (optionName) {
+ if (optionName !== undefined) {
option = this._optionsDictionary.get(optionName);
}
- if (option) {
+ if (option !== undefined) {
this.select(option);
} else {
this.select(0);
diff --git a/src/sql/media/icons/common-icons.css b/src/sql/media/icons/common-icons.css
index 418e1f294c..47cd368c77 100644
--- a/src/sql/media/icons/common-icons.css
+++ b/src/sql/media/icons/common-icons.css
@@ -106,6 +106,16 @@
content: url("help_inverse.svg");
}
+.codicon.info-icon,
+.vs .codicon.info-icon {
+ background-image: url("info.svg");
+}
+
+.vs-dark .codicon.info-icon,
+.hc-black .codicon.info-icon {
+ background-image: url("info_inverse.svg");
+}
+
.vs .codicon.success,
.vs-dark .codicon.success,
.hc-black .codicon.success {
diff --git a/src/sql/media/icons/info_inverse.svg b/src/sql/media/icons/info_inverse.svg
new file mode 100644
index 0000000000..f32f61aa9c
--- /dev/null
+++ b/src/sql/media/icons/info_inverse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/sql/workbench/browser/modal/dialogHelper.ts b/src/sql/workbench/browser/modal/dialogHelper.ts
index 85a587d66c..8812f1e420 100644
--- a/src/sql/workbench/browser/modal/dialogHelper.ts
+++ b/src/sql/workbench/browser/modal/dialogHelper.ts
@@ -6,12 +6,11 @@
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
import { Button } from 'sql/base/browser/ui/button/button';
import { append, $ } from 'vs/base/browser/dom';
-
import * as types from 'vs/base/common/types';
-
import * as azdata from 'azdata';
+import { wrapStringWithNewLine } from 'sql/workbench/common/sqlWorkbenchUtils';
-export function appendRow(container: HTMLElement, label: string, labelClass: string, cellContainerClass: string, rowContainerClass?: string | Array, showRequiredIndicator: boolean = false): HTMLElement {
+export function appendRow(container: HTMLElement, label: string, labelClass: string, cellContainerClass: string, rowContainerClass?: string | Array, showRequiredIndicator: boolean = false, title?: string, titleMaxWidth?: number): HTMLElement {
let rowContainer = append(container, $('tr'));
if (rowContainerClass) {
if (types.isString(rowContainerClass)) {
@@ -22,6 +21,13 @@ export function appendRow(container: HTMLElement, label: string, labelClass: str
}
const labelContainer = append(append(rowContainer, $(`td.${labelClass}`)), $('div.dialog-label-container'));
labelContainer.style.display = 'flex';
+
+ if (title) {
+ labelContainer.classList.add("codicon");
+ labelContainer.classList.add("info-icon");
+ labelContainer.title = titleMaxWidth ? wrapStringWithNewLine(title, titleMaxWidth) : title;
+ }
+
append(labelContainer, $('div')).innerText = label;
if (showRequiredIndicator) {
const indicator = append(labelContainer, $('span.required-indicator'));
diff --git a/src/sql/workbench/common/sqlWorkbenchUtils.ts b/src/sql/workbench/common/sqlWorkbenchUtils.ts
index dcb13395c9..c31410031a 100644
--- a/src/sql/workbench/common/sqlWorkbenchUtils.ts
+++ b/src/sql/workbench/common/sqlWorkbenchUtils.ts
@@ -19,3 +19,40 @@ export function getSqlConfigValue(workspaceConfigService: IConfigurationServi
let config = workspaceConfigService.getValue<{ [key: string]: any }>(ConnectionConstants.sqlConfigSectionName);
return config ? config[configName] : undefined;
}
+
+/**
+ * Wraps provided string using \n that qualifies as line break to wrap text in title attributes (tooltips).
+ * @param str string to be wrapped
+ * @param maxWidth max width to be allowed for wrapped text
+ * @returns wrapped string
+ */
+export function wrapStringWithNewLine(str: string | undefined, maxWidth: number): string | undefined {
+ if (!str) {
+ return str;
+ }
+ let newLineStr = `\n`;
+ let res = '';
+ while (str.length > maxWidth) {
+ let found = false;
+ // Inserts new line at first whitespace of the line
+ for (let i = maxWidth - 1; i >= 0; i--) {
+ if (testWhitespace(str.charAt(i))) {
+ res = res + [str.slice(0, i), newLineStr].join('');
+ str = str.slice(i + 1);
+ found = true;
+ break;
+ }
+ }
+ // Inserts new line at maxWidth position, the word is too long to wrap
+ if (!found) {
+ res += [str.slice(0, maxWidth), newLineStr].join('');
+ str = str.slice(maxWidth);
+ }
+ }
+ return res + str;
+}
+
+function testWhitespace(x: string) {
+ var white = new RegExp(/^\s$/);
+ return white.test(x.charAt(0));
+}
diff --git a/src/sql/workbench/services/connection/browser/connectionWidget.ts b/src/sql/workbench/services/connection/browser/connectionWidget.ts
index e29c588b95..dc07a4696d 100644
--- a/src/sql/workbench/services/connection/browser/connectionWidget.ts
+++ b/src/sql/workbench/services/connection/browser/connectionWidget.ts
@@ -63,6 +63,8 @@ export class ConnectionWidget extends lifecycle.Disposable {
private _defaultDatabaseName: string = localize('defaultDatabaseOption', "");
private _loadingDatabaseName: string = localize('loadingDatabaseOption', "Loading...");
private _serverGroupDisplayString: string = localize('serverGroup', "Server group");
+ private _trueInputValue: string = localize('boolean.true', 'True');
+ private _falseInputValue: string = localize('boolean.false', 'False');
private _token: string;
private _connectionStringOptions: ConnectionStringOptions;
protected _container: HTMLElement;
@@ -257,10 +259,12 @@ export class ConnectionWidget extends lifecycle.Disposable {
if (this._customOptions.length > 0) {
this._customOptionWidgets = [];
this._customOptions.forEach((option, i) => {
- let customOptionsContainer = DialogHelper.appendRow(this._tableContainer, option.displayName, 'connection-label', 'connection-input', 'custom-connection-options');
+ let customOptionsContainer = DialogHelper.appendRow(this._tableContainer, option.displayName, 'connection-label', 'connection-input', 'custom-connection-options', false, option.description, 100);
switch (option.valueType) {
case ServiceOptionType.boolean:
- this._customOptionWidgets[i] = new SelectBox([localize('boolean.true', 'True'), localize('boolean.false', 'False')], option.defaultValue, this._contextViewService, customOptionsContainer, { ariaLabel: option.displayName });
+ // Convert 'defaultValue' to string for comparison as it can be boolean here.
+ let optionValue = (option.defaultValue.toString() === true.toString()) ? this._trueInputValue : this._falseInputValue;
+ this._customOptionWidgets[i] = new SelectBox([this._trueInputValue, this._falseInputValue], optionValue, this._contextViewService, customOptionsContainer, { ariaLabel: option.displayName });
DialogHelper.appendInputSelectBox(customOptionsContainer, this._customOptionWidgets[i] as SelectBox);
this._register(styler.attachSelectBoxStyler(this._customOptionWidgets[i] as SelectBox, this._themeService));
break;
@@ -774,10 +778,13 @@ export class ConnectionWidget extends lifecycle.Disposable {
if (this._customOptionWidgets) {
this._customOptionWidgets.forEach((widget, i) => {
- if (widget instanceof SelectBox) {
- widget.selectWithOptionName(this.getModelValue(connectionInfo.options[this._customOptions[i].name]));
- } else {
- widget.value = this.getModelValue(connectionInfo.options[this._customOptions[i].name]);
+ let value = this.getModelValue(connectionInfo.options[this._customOptions[i].name]);
+ if (value !== '') {
+ if (widget instanceof SelectBox) {
+ widget.selectWithOptionName(value);
+ } else {
+ widget.value = value;
+ }
}
});
}
diff --git a/src/sql/workbench/services/connection/browser/media/connectionDialog.css b/src/sql/workbench/services/connection/browser/media/connectionDialog.css
index a3fb18d637..46fba21083 100644
--- a/src/sql/workbench/services/connection/browser/media/connectionDialog.css
+++ b/src/sql/workbench/services/connection/browser/media/connectionDialog.css
@@ -111,6 +111,16 @@
font-weight: 600;
}
+.custom-connection-options .connection-label .dialog-label-container,
+.vs-dark .custom-connection-options .connection-label .dialog-label-container,
+.hc-black .custom-connection-options .connection-label .dialog-label-container {
+ background-size: 9px;
+ background-repeat: no-repeat;
+ background-position: right;
+ padding-right: 18px;
+ float: left;
+}
+
.hide-azure-accounts .azure-account-row {
display: none;
}