diff --git a/src/sql/base/parts/editableDropdown/browser/actions.ts b/src/sql/base/parts/editableDropdown/browser/actions.ts deleted file mode 100644 index 698e9f30aa..0000000000 --- a/src/sql/base/parts/editableDropdown/browser/actions.ts +++ /dev/null @@ -1,20 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Action } from 'vs/base/common/actions'; - -export class ToggleDropdownAction extends Action { - private static readonly ID = 'dropdownAction.toggle'; - private static readonly ICON = 'dropdown-arrow'; - - constructor(private _fn: () => any, label: string) { - super(ToggleDropdownAction.ID, label, ToggleDropdownAction.ICON); - } - - public run(): Promise { - this._fn(); - return Promise.resolve(true); - } -} diff --git a/src/sql/base/parts/editableDropdown/browser/dropdown.ts b/src/sql/base/parts/editableDropdown/browser/dropdown.ts index cfdbde34f2..3f49ea414e 100644 --- a/src/sql/base/parts/editableDropdown/browser/dropdown.ts +++ b/src/sql/base/parts/editableDropdown/browser/dropdown.ts @@ -4,25 +4,24 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/dropdownList'; - -import { DropdownDataSource, DropdownFilter, DropdownModel, DropdownRenderer, DropdownController } from './dropdownTree'; - -import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; -import { mixin } from 'vs/base/common/objects'; -import { InputBox, IInputBoxStyles } from 'sql/base/browser/ui/inputBox/inputBox'; -import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; -import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; +import { IInputBoxStyles, InputBox } from 'sql/base/browser/ui/inputBox/inputBox'; +import { DropdownDataSource, IDropdownListItem, DropdownListRenderer, SELECT_OPTION_ENTRY_TEMPLATE_ID } from 'sql/base/parts/editableDropdown/browser/dropdownList'; import * as DOM from 'vs/base/browser/dom'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Color } from 'vs/base/common/color'; -import * as nls from 'vs/nls'; -import { Event, Emitter } from 'vs/base/common/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; -import { ITree } from 'vs/base/parts/tree/browser/tree'; +import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; +import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { IListStyles, List } from 'vs/base/browser/ui/list/listWidget'; +import { Color } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { Emitter, Event } from 'vs/base/common/event'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { Disposable } from 'vs/base/common/lifecycle'; import { clamp } from 'vs/base/common/numbers'; +import { mixin } from 'vs/base/common/objects'; +import { ScrollbarVisibility } from 'vs/base/common/scrollable'; +import * as nls from 'vs/nls'; + export interface IDropdownOptions extends IDropdownStyles { /** @@ -53,10 +52,6 @@ export interface IDropdownOptions extends IDropdownStyles { * Value to use as aria-label for the input box */ ariaLabel?: string; - /** - * Label for the dropdown action - */ - actionLabel: string; } export interface IDropdownStyles { @@ -69,22 +64,17 @@ const errorMessage = nls.localize('editableDropdown.errorValidate', "Must be an const defaults: IDropdownOptions = { strictSelection: true, maxHeight: 300, - errorMessage: errorMessage, - contextBorder: Color.fromHex('#696969'), - actionLabel: nls.localize('dropdownAction.toggle', "Toggle dropdown") + errorMessage: errorMessage }; -export class Dropdown extends Disposable { +export class Dropdown extends Disposable implements IListVirtualDelegate { private _el: HTMLElement; private _inputContainer: HTMLElement; - private _treeContainer: HTMLElement; + private _selectListContainer: HTMLElement; private _input: InputBox; - private _tree: ITree; + private _selectList: List; private _options: IDropdownOptions; private _dataSource = new DropdownDataSource(); - private _filter = new DropdownFilter(); - private _renderer = new DropdownRenderer(); - private _controller = new DropdownController(); public fireOnTextChange?: boolean; private _onBlur = this._register(new Emitter()); @@ -114,7 +104,7 @@ export class Dropdown extends Disposable { this._inputContainer = DOM.append(this._el, DOM.$('.dropdown-input.select-container')); this._inputContainer.style.width = '100%'; - this._treeContainer = DOM.$('.dropdown-tree'); + this._selectListContainer = DOM.$('div'); this._input = new InputBox(this._inputContainer, contextViewService, { validationOptions: { @@ -138,7 +128,7 @@ export class Dropdown extends Disposable { const inputTracker = this._register(DOM.trackFocus(this._input.inputElement)); inputTracker.onDidBlur(() => { - if (!this._tree.isDOMFocused()) { + if (!this._selectList.isDOMFocused()) { this._onBlur.fire(); } }); @@ -152,7 +142,7 @@ export class Dropdown extends Disposable { e.stopPropagation(); break; case KeyCode.Escape: - if (this._treeContainer.parentElement) { + if (this._isDropDownVisible) { this._input.validate(); this._onBlur.fire(); this._hideList(); @@ -166,53 +156,76 @@ export class Dropdown extends Disposable { e.stopPropagation(); break; case KeyCode.DownArrow: - if (!this._treeContainer.parentElement) { + if (!this._isDropDownVisible) { this._showList(); } - this._tree.domFocus(); - this._tree.focusFirst(); + setTimeout(() => { + this._selectList.domFocus(); + this._selectList.focusFirst(); + }, 0); e.stopPropagation(); e.preventDefault(); break; } })); - this._tree = new Tree(this._treeContainer, { - dataSource: this._dataSource, - filter: this._filter, - renderer: this._renderer, - controller: this._controller - }, { paddingOnRow: false, indentPixels: 0, twistiePixels: 0 }); - - const treeTracker = this._register(DOM.trackFocus(this._tree.getHTMLElement())); - - treeTracker.onDidBlur(() => { - if (!this._input.hasFocus()) { - this._onBlur.fire(); + this._selectList = new List('EditableDropdown', this._selectListContainer, this, [new DropdownListRenderer()], { + useShadows: false, + verticalScrollMode: ScrollbarVisibility.Visible, + keyboardSupport: true, + mouseSupport: true, + accessibilityProvider: { + getAriaLabel: (element) => element.text, + getWidgetAriaLabel: () => nls.localize('selectBox', "Select Box"), + getRole: () => 'option', + getWidgetRole: () => 'listbox' } }); this.values = this._options.values; - - this._controller.onSelectionChange(e => { - this.value = e.value; - this._onValueChange.fire(e.value); - this._input.focus(); + this._register(this._selectList.onDidBlur(() => { this._hideList(); - }); + })); - this._controller.onDropdownEscape(() => { - this._hideList(); - // have to put this in the setTimeout to make sure the focus can be set properly when the context menu is opened by pressing the DownArrow key - setTimeout(() => { - this._input.focus(); - }, 0); - }); + this._register(this._selectList.onKeyDown((e) => { + const event = new StandardKeyboardEvent(e); + let handled: boolean = false; + switch (event.keyCode) { + case KeyCode.Escape: + this._hideList(); + setTimeout(() => { + this._input.focus(); + }, 0); + handled = true; + break; + case KeyCode.Enter: + case KeyCode.Space: + const focusedElements = this._selectList.getFocusedElements(); + if (focusedElements.length !== 0) { + this._updateSelection(focusedElements[0].text); + handled = true; + } + break; + default: + return; + } + if (handled) { + e.preventDefault(); + e.stopPropagation(); + } + })); + this._register(this._selectList.onMouseClick((e) => { + if (e.element) { + this._updateSelection(e.element.text); + } + })); this._input.onDidChange(e => { - if (this._dataSource.options) { - this._filter.filterString = e; - this._layoutTree(); + if (this._dataSource.values?.length > 0) { + this._dataSource.filter = e; + if (this._isDropDownVisible) { + this._updateDropDownList(); + } } if (this.fireOnTextChange) { this.value = e; @@ -225,25 +238,52 @@ export class Dropdown extends Disposable { this._input.validate(); }); - this._register(this._tree); + this._register(this._selectList); this._register(this._input); } + getHeight(): number { + return 22; + } + + getTemplateId(): string { + return SELECT_OPTION_ENTRY_TEMPLATE_ID; + } + + private get _isDropDownVisible(): boolean { + return this._selectListContainer.classList.contains('visible'); + } + + private _setDropdownVisibility(visible: boolean): void { + if (visible) { + this._selectListContainer.classList.add('visible'); + } else { + this._selectListContainer.classList.remove('visible'); + } + this._selectListContainer.setAttribute('aria-hidden', `${!visible}`); + } + + private _updateSelection(newValue: string): void { + this.value = newValue; + this._onValueChange.fire(newValue); + this._input.focus(); + this._hideList(); + } + private _showList(): void { if (this._input.isEnabled()) { this._inputContainer.setAttribute('aria-expanded', 'true'); this._onFocus.fire(); - this._filter.filterString = ''; + this._dataSource.filter = undefined; this.contextViewService.showContextView({ getAnchor: () => this._inputContainer, render: container => { - DOM.append(container, this._treeContainer); - this._layoutTree(); + this._setDropdownVisibility(true); + DOM.append(container, this._selectListContainer); + this._updateDropDownList(); return { dispose: () => { - // when we dispose we want to remove treecontainer so that it doesn't have a parent - // we often use the presense of a parent to detect if the tree is being shown - this._treeContainer.remove(); + this._setDropdownVisibility(false); } }; } @@ -252,55 +292,43 @@ export class Dropdown extends Disposable { } private _hideList(): void { - this.contextViewService.hideContextView(); + //this.contextViewService.hideContextView(); this._inputContainer.setAttribute('aria-expanded', 'false'); } - private _layoutTree(): void { - if (this._dataSource && this._dataSource.options && this._dataSource.options.length > 0) { - let filteredLength = this._dataSource.options.reduce((p, i) => { - if (this._filter.isVisible(undefined, i)) { - return p + 1; - } else { - return p; - } - }, 0); - let height = filteredLength * this._renderer.getHeight() > this._options.maxHeight! ? this._options.maxHeight! : filteredLength * this._renderer.getHeight(); - this._treeContainer.style.height = height + 'px'; - this.updateTreeWidth(); - this._tree.layout(parseInt(this._treeContainer.style.height)); - this._tree.refresh().catch(e => onUnexpectedError(e)); + private _updateDropDownList(): void { + try { + this._selectList.splice(0, this._selectList.length, this._dataSource.filteredValues.map(v => { return { text: v }; })); + } catch (e) { + onUnexpectedError(e); } - } - /** - * Update the width of the context tree to better fit the contents. - */ - private updateTreeWidth(): void { - if (this._dataSource && this._dataSource.options) { - const longestOption = this._dataSource.options.reduce((previous, current) => { - return previous.value.length > current.value.length ? previous : current; - }, { value: '' }); - this._widthControlElement.innerText = longestOption.value; + let width = this._inputContainer.clientWidth; + if (this._dataSource && this._dataSource.filteredValues) { + const longestOption = this._dataSource.filteredValues.reduce((previous, current) => { + return previous.length > current.length ? previous : current; + }, ''); + this._widthControlElement.innerText = longestOption; const inputContainerWidth = DOM.getContentWidth(this._inputContainer); const longestOptionWidth = DOM.getTotalWidth(this._widthControlElement); - this._treeContainer.style.width = `${clamp(longestOptionWidth, inputContainerWidth, 500)}px`; + width = clamp(longestOptionWidth, inputContainerWidth, 500); } + const height = Math.min((this._dataSource.filteredValues?.length ?? 0) * this.getHeight(), this._options.maxHeight ?? 500); + this._selectListContainer.style.width = `${width}px`; + this._selectListContainer.style.height = `${height}px`; + this._selectList.layout(height, width); } public set values(vals: string[] | undefined) { if (vals) { - this._filter.filterString = ''; - this._dataSource.options = vals.map(i => { return { value: i }; }); - this.updateTreeWidth(); - let height = this._dataSource.options.length * 22 > this._options.maxHeight! ? this._options.maxHeight! : this._dataSource.options.length * 22; - this._treeContainer.style.height = height + 'px'; - this._tree.layout(parseInt(this._treeContainer.style.height)); - this._tree.setInput(new DropdownModel()).catch(e => onUnexpectedError(e)); + this._dataSource.filter = undefined; + this._dataSource.values = vals; + if (this._isDropDownVisible) { + this._updateDropDownList(); + } this._input.validate(); - } } @@ -326,14 +354,14 @@ export class Dropdown extends Disposable { } style(style: IListStyles & IInputBoxStyles & IDropdownStyles) { - this._tree.style(style); + this._selectList.style(style); this._input.style(style); - this._treeContainer.style.backgroundColor = style.contextBackground ? style.contextBackground.toString() : ''; - this._treeContainer.style.outline = `1px solid ${style.contextBorder || this._options.contextBorder}`; + this._selectListContainer.style.backgroundColor = style.contextBackground ? style.contextBackground.toString() : ''; + this._selectListContainer.style.outline = `1px solid ${style.contextBorder}`; } private _inputValidator(value: string): IMessage | null { - if (!this._input.hasFocus() && !this._tree.isDOMFocused() && this._dataSource.options && !this._dataSource.options.some(i => i.value === value)) { + if (!this._input.hasFocus() && !this._selectList.isDOMFocused() && this._dataSource.values && !this._dataSource.values.some(i => i === value)) { if (this._options.strictSelection && this._options.errorMessage) { return { content: this._options.errorMessage, diff --git a/src/sql/base/parts/editableDropdown/browser/dropdownList.ts b/src/sql/base/parts/editableDropdown/browser/dropdownList.ts new file mode 100644 index 0000000000..5d6d231aac --- /dev/null +++ b/src/sql/base/parts/editableDropdown/browser/dropdownList.ts @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/dropdownList'; +import * as DOM from 'vs/base/browser/dom'; +import { IListRenderer } from 'vs/base/browser/ui/list/list'; +const $ = DOM.$; + +export const SELECT_OPTION_ENTRY_TEMPLATE_ID = 'editableDropDownOption.entry.template'; + +export interface IDropdownListTemplateData { + root: HTMLElement; + text: HTMLElement; +} + +export interface IDropdownListItem { + text: string; +} + +export class DropdownListRenderer implements IListRenderer { + + get templateId(): string { return SELECT_OPTION_ENTRY_TEMPLATE_ID; } + + renderTemplate(container: HTMLElement): IDropdownListTemplateData { + const data: IDropdownListTemplateData = Object.create(null); + data.root = container; + data.text = DOM.append(container, $('span.editable-drop-option-text')); + return data; + } + + renderElement(element: IDropdownListItem, index: number, templateData: IDropdownListTemplateData): void { + const data: IDropdownListTemplateData = templateData; + const text = element.text; + data.text.textContent = text; + data.text.title = text; + } + + disposeTemplate(templateData: IDropdownListTemplateData): void { + } +} + +export class DropdownDataSource { + values: string[]; + + filter: string | undefined; + + public get filteredValues(): string[] { + if (this.filter) { + return this.values.filter(v => { + return v.toLocaleLowerCase().indexOf(this.filter.toLocaleLowerCase()) !== -1; + }); + } + return this.values; + } +} diff --git a/src/sql/base/parts/editableDropdown/browser/dropdownTree.ts b/src/sql/base/parts/editableDropdown/browser/dropdownTree.ts deleted file mode 100644 index 066ffff0a1..0000000000 --- a/src/sql/base/parts/editableDropdown/browser/dropdownTree.ts +++ /dev/null @@ -1,153 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as tree from 'vs/base/parts/tree/browser/tree'; -import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults'; -import { generateUuid } from 'vs/base/common/uuid'; -import * as DOM from 'vs/base/browser/dom'; -import { Event, Emitter } from 'vs/base/common/event'; -import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; - -export interface Template { - label: HTMLElement; - row: HTMLElement; -} - -export interface Resource { - value: string; -} - -export class DropdownModel { - public static ID = generateUuid(); -} - -export class DropdownRenderer implements tree.IRenderer { - public getHeight(): number { - return 22; - } - - public getTemplateId(): string { - return ''; - } - - public renderTemplate(tree: tree.ITree, templateId: string, container: HTMLElement): Template { - const row = DOM.$('div.list-row'); - row.style.height = '22px'; - row.style.paddingLeft = '5px'; - DOM.append(container, row); - const label = DOM.$('span.label'); - label.style.margin = 'auto'; - label.style.verticalAlign = 'middle'; - DOM.append(row, label); - - return { label, row }; - } - - public renderElement(tree: tree.ITree, element: Resource, templateId: string, templateData: Template): void { - templateData.label.innerText = element.value; - templateData.row.title = element.value; - } - - public disposeTemplate(tree: tree.ITree, templateId: string, templateData: Template): void { - // no op - } -} - -export class DropdownDataSource implements tree.IDataSource { - public options?: Array; - - public getId(tree: tree.ITree, element: Resource | DropdownModel): string { - if (element instanceof DropdownModel) { - return DropdownModel.ID; - } else { - return (element as Resource).value; - } - } - - public hasChildren(tree: tree.ITree, element: Resource | DropdownModel): boolean { - if (element instanceof DropdownModel) { - return true; - } else { - return false; - } - } - - public getChildren(tree: tree.ITree, element: Resource | DropdownModel): Promise { - if (element instanceof DropdownModel) { - return Promise.resolve(this.options); - } else { - return Promise.resolve(undefined); - } - } - - public getParent(tree: tree.ITree, element: Resource | DropdownModel): Promise { - if (element instanceof DropdownModel) { - return Promise.resolve(undefined); - } else { - return Promise.resolve(new DropdownModel()); - } - } -} - -export class DropdownFilter extends TreeDefaults.DefaultFilter { - public filterString?: string; - - public isVisible(tree: tree.ITree | undefined, element: Resource): boolean { - if (this.filterString) { - return element.value.toLowerCase().indexOf(this.filterString.toLowerCase()) !== -1; - } else { - return true; - } - } -} - -export class DropdownController extends TreeDefaults.DefaultController { - private _onSelectionChange = new Emitter(); - public readonly onSelectionChange: Event = this._onSelectionChange.event; - - private _onDropdownEscape = new Emitter(); - public readonly onDropdownEscape: Event = this._onDropdownEscape.event; - - constructor() { - super(); - } - - protected onEscape(tree: tree.ITree, event: IKeyboardEvent): boolean { - let response = super.onEscape(tree, event); - this._onDropdownEscape.fire(); - return response; - } - - protected onLeftClick(tree: tree.ITree, element: any, eventish: TreeDefaults.ICancelableEvent, origin: string): boolean { - let response = super.onLeftClick(tree, element, eventish, origin); - if (response) { - this._onSelectionChange.fire(tree.getSelection()[0]); - } - return response; - } - - public onKeyDown(tree: tree.ITree, event: IKeyboardEvent): boolean { - // The enter key press is handled on key up by our base class (DefaultController) but - // we want to stop it here because we know we're going to handle it (by selecting the item) - // and letting it propagate up means that other controls may incorrectly handle it first - // if they're listening to onKeyDown - const response = super.onKeyDown(tree, event); - if (event.keyCode === KeyCode.Enter) { - DOM.EventHelper.stop(event, true); - return true; - } - return response; - } - - protected onEnter(tree: tree.ITree, event: IKeyboardEvent): boolean { - let response = super.onEnter(tree, event); - if (response) { - this._onSelectionChange.fire(tree.getSelection()[0]); - DOM.EventHelper.stop(event, true); - } - return response; - } -} diff --git a/src/sql/base/parts/editableDropdown/browser/media/dropdownList.css b/src/sql/base/parts/editableDropdown/browser/media/dropdownList.css index f3b419a017..ae2b359586 100644 --- a/src/sql/base/parts/editableDropdown/browser/media/dropdownList.css +++ b/src/sql/base/parts/editableDropdown/browser/media/dropdownList.css @@ -3,43 +3,17 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.vs .dropdown-arrow.codicon { - background-image: url("dropdownarrow.svg"); -} - -.vs-dark .dropdown-arrow.codicon, -.hc-black .dropdown-arrow.codicon { - background-image: url("dropdownarrow_inverse.svg"); -} - .monaco-dropdown-width-control-element { position: absolute; left: -10000px; visibility: hidden; } -.monaco-dropdown .monaco-action-bar .action-label.codicon.dropdown-arrow { - padding: 0; - background-size: 10px; - background-position: 50%; -} - -.monaco-dropdown .monaco-action-bar .action-item { - margin: 0; -} - -.dropdown-tree .list-row { - width: 100%; - box-sizing: border-box; -} - -.dropdown-tree .content { - width: 100%; -} - -.dropdown-tree .list-row .label { - width: 100%; - display: inline-block; +.editable-drop-option-text { + padding-left: 6px; + padding-right: 4px; text-overflow: ellipsis; + display: inline-block; + width: 100%; overflow: hidden; } diff --git a/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow.svg b/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow.svg deleted file mode 100644 index 17e7e8abe3..0000000000 --- a/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow.svg +++ /dev/null @@ -1 +0,0 @@ -dropdownarrow \ No newline at end of file diff --git a/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow_inverse.svg b/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow_inverse.svg deleted file mode 100644 index be66e61fe7..0000000000 --- a/src/sql/base/parts/editableDropdown/browser/media/dropdownarrow_inverse.svg +++ /dev/null @@ -1 +0,0 @@ -dropdownarrow_inverse \ No newline at end of file diff --git a/src/sql/platform/browser/editableDropdown/editableDropdown.component.ts b/src/sql/platform/browser/editableDropdown/editableDropdown.component.ts index af5321bee7..9f43fa441c 100644 --- a/src/sql/platform/browser/editableDropdown/editableDropdown.component.ts +++ b/src/sql/platform/browser/editableDropdown/editableDropdown.component.ts @@ -44,8 +44,7 @@ export class EditableDropDown extends AngularDisposable implements OnInit, OnCha strictSelection: false, placeholder: '', maxHeight: 125, - ariaLabel: '', - actionLabel: '' + ariaLabel: '' }; this._selectbox = new Dropdown(this._el.nativeElement, this.contextViewService, dropdownOptions); this._selectbox.values = this.options; diff --git a/src/sql/workbench/browser/modelComponents/dropdown.component.ts b/src/sql/workbench/browser/modelComponents/dropdown.component.ts index 74256c9e2c..040c58304c 100644 --- a/src/sql/workbench/browser/modelComponents/dropdown.component.ts +++ b/src/sql/workbench/browser/modelComponents/dropdown.component.ts @@ -70,8 +70,7 @@ export default class DropDownComponent extends ComponentBase this.databaseSelected(s))); this._register(this._dropdown.onFocus(() => this.onDropdownFocus())); diff --git a/src/sql/workbench/services/connection/browser/connectionWidget.ts b/src/sql/workbench/services/connection/browser/connectionWidget.ts index 00baccdc33..fad6bad70a 100644 --- a/src/sql/workbench/services/connection/browser/connectionWidget.ts +++ b/src/sql/workbench/services/connection/browser/connectionWidget.ts @@ -161,6 +161,7 @@ export class ConnectionWidget extends lifecycle.Disposable { this._previousGroupOption = this._serverGroupSelectBox.value; this._container = DOM.append(container, DOM.$('div.connection-table')); this._tableContainer = DOM.append(this._container, DOM.$('table.connection-table-content')); + this._tableContainer.setAttribute('role', 'presentation'); this.fillInConnectionForm(authTypeChanged); this.registerListeners(); if (this._authTypeSelectBox) { @@ -284,8 +285,7 @@ export class ConnectionWidget extends lifecycle.Disposable { strictSelection: false, placeholder: this._defaultDatabaseName, maxHeight: 125, - ariaLabel: databaseOption.displayName, - actionLabel: localize('connectionWidget.toggleDatabaseNameDropdown', "Select Database Toggle Dropdown") + ariaLabel: databaseOption.displayName }); } } diff --git a/src/sql/workbench/services/restore/browser/restoreDialog.ts b/src/sql/workbench/services/restore/browser/restoreDialog.ts index 30fd4c6e34..7cc7aa1162 100644 --- a/src/sql/workbench/services/restore/browser/restoreDialog.ts +++ b/src/sql/workbench/services/restore/browser/restoreDialog.ts @@ -213,8 +213,7 @@ export class RestoreDialog extends Modal { this._databaseDropdown = new Dropdown(dropdownContainer, this._contextViewService, { strictSelection: false, - ariaLabel: LocalizedStrings.TARGETDATABASE, - actionLabel: localize('restoreDialog.toggleDatabaseNameDropdown', "Select Database Toggle Dropdown") + ariaLabel: LocalizedStrings.TARGETDATABASE } ); this._databaseDropdown.onValueChange(s => {