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 @@ +info_notification_inverse \ 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; }