diff --git a/src/sql/workbench/contrib/dataExplorer/browser/media/connectionViewletPanel.css b/src/sql/workbench/contrib/dataExplorer/browser/media/connectionViewletPanel.css index 278207a83c..83a4ba5cc9 100644 --- a/src/sql/workbench/contrib/dataExplorer/browser/media/connectionViewletPanel.css +++ b/src/sql/workbench/contrib/dataExplorer/browser/media/connectionViewletPanel.css @@ -217,8 +217,14 @@ border-radius: 5px; } +.monaco-list-row .async-server-group .async-server-group .async-server-group-container .icon { + width: 7px; + height: 20px; + border-radius: 3px; +} + .monaco-list-row .async-server-group .async-server-group .async-server-group-container .name { - padding-left: 10px; + padding-left: 5px; flex: 1; overflow: hidden; text-overflow: ellipsis; @@ -255,7 +261,6 @@ position: relative; } - .monaco-list-row .connection-profile .connection-profile-container .icon .connection-status-badge { position: absolute; bottom: 0; diff --git a/src/sql/workbench/services/objectExplorer/browser/asyncServerTreeRenderer.ts b/src/sql/workbench/services/objectExplorer/browser/asyncServerTreeRenderer.ts index d886e6d100..d155461ebe 100644 --- a/src/sql/workbench/services/objectExplorer/browser/asyncServerTreeRenderer.ts +++ b/src/sql/workbench/services/objectExplorer/browser/asyncServerTreeRenderer.ts @@ -13,7 +13,7 @@ import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode' import { iconRenderer } from 'sql/workbench/services/objectExplorer/browser/iconRenderer'; import { URI } from 'vs/base/common/uri'; import { ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree'; -import { FuzzyScore } from 'vs/base/common/filters'; +import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list'; @@ -21,9 +21,9 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { ServerTreeRenderer, getLabelWithFilteredSuffix } from 'sql/workbench/services/objectExplorer/browser/serverTreeRenderer'; import { ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree'; import { DefaultServerGroupColor } from 'sql/workbench/services/serverGroup/common/serverGroupViewModel'; -import { withNullAsUndefined } from 'vs/base/common/types'; import { instanceOfSqlThemeIcon } from 'sql/workbench/services/objectExplorer/common/nodeType'; import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService'; +import { ResourceLabel } from 'vs/workbench/browser/labels'; const DefaultConnectionIconClass = 'server-page'; export interface ConnectionProfileGroupDisplayOptions { @@ -32,35 +32,37 @@ export interface ConnectionProfileGroupDisplayOptions { class ConnectionProfileGroupTemplate extends Disposable { private _root: HTMLElement; - private _nameContainer: HTMLElement; + private _icon: HTMLElement; + private _labelContainer: HTMLElement; + private _label: ResourceLabel; constructor( container: HTMLElement, - private _option: ConnectionProfileGroupDisplayOptions + private _option: ConnectionProfileGroupDisplayOptions, + @IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); container.parentElement!.classList.add('async-server-group'); container.classList.add('async-server-group'); this._root = dom.append(container, dom.$('.async-server-group-container')); - this._nameContainer = dom.append(this._root, dom.$('span.name')); + this._icon = dom.append(this._root, dom.$('div.icon')); + this._labelContainer = dom.append(this._root, dom.$('span.name')); + this._label = this._instantiationService.createInstance(ResourceLabel, this._labelContainer, { supportHighlights: true }); } - set(element: ConnectionProfileGroup) { - let rowElement = findParentElement(this._root, 'monaco-list-row'); - if (this._option.showColor && rowElement) { - rowElement.style.color = element.textColor; - if (element.color) { - this._nameContainer.style.background = element.color; - } else { - // If the group doesn't contain specific color, assign the default color - this._nameContainer.style.background = DefaultServerGroupColor; - } + set(element: ConnectionProfileGroup, filterData: FuzzyScore) { + if (this._option.showColor) { + // If the color is not defined, use the default color + const backgroundColor = element.color ?? DefaultServerGroupColor; + this._icon.style.background = backgroundColor; } if (element.description && (element.description !== '')) { this._root.title = element.description; } - this._nameContainer.hidden = false; - this._nameContainer.textContent = element.name; + this._labelContainer.hidden = false; + this._label.element.setLabel(element.name, '', { + matches: createMatches(filterData) + }); } } @@ -75,7 +77,7 @@ export class ConnectionProfileGroupRenderer implements ITreeRenderer, index: number, template: ConnectionProfileGroupTemplate): void { - template.set(node.element); + template.set(node.element, node.filterData); } disposeTemplate(templateData: ConnectionProfileGroupTemplate): void { templateData.dispose(); @@ -87,7 +89,8 @@ class ConnectionProfileTemplate extends Disposable { private _root: HTMLElement; private _icon: HTMLElement; private _connectionStatusBadge: HTMLElement; - private _label: HTMLElement; + private _labelContainer: HTMLElement; + private _label: ResourceLabel; /** * _isCompact is used to render connections tiles with and without the action buttons. * When set to true, like in the connection dialog recent connections tree, the connection @@ -97,17 +100,19 @@ class ConnectionProfileTemplate extends Disposable { container: HTMLElement, private _isCompact: boolean, @IConnectionManagementService private _connectionManagementService: IConnectionManagementService, - @IObjectExplorerService private _objectExplorerService: IObjectExplorerService + @IObjectExplorerService private _objectExplorerService: IObjectExplorerService, + @IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); container.parentElement!.classList.add('connection-profile'); this._root = dom.append(container, dom.$('.connection-profile-container')); this._icon = dom.append(this._root, dom.$('div.icon')); this._connectionStatusBadge = dom.append(this._icon, dom.$('div.connection-status-badge')); - this._label = dom.append(this._root, dom.$('div.label')); + this._labelContainer = dom.append(this._root, dom.$('div.label')); + this._label = this._instantiationService.createInstance(ResourceLabel, this._labelContainer, { supportHighlights: true }); } - set(element: ConnectionProfile) { + set(element: ConnectionProfile, filterData: FuzzyScore) { if (!this._isCompact) { if (this._connectionManagementService.isConnected(undefined, element)) { this._connectionStatusBadge.classList.remove('disconnected'); @@ -120,14 +125,13 @@ class ConnectionProfileTemplate extends Disposable { const iconPath: IconPath | undefined = getIconPath(element, this._connectionManagementService); renderServerIcon(this._icon, iconPath); - let label = element.title; - this._label.textContent = label; - this._root.title = element.serverInfo; const treeNode = this._objectExplorerService.getObjectExplorerNode(element); - if (treeNode?.filters?.length > 0) { - this._label.textContent = getLabelWithFilteredSuffix(this._label.textContent); - } + let labelText = treeNode?.filters?.length > 0 ? getLabelWithFilteredSuffix(element.title) : element.title; + this._label.element.setLabel(labelText, '', { + matches: createMatches(filterData) + }); + this._root.title = labelText; } } @@ -143,7 +147,7 @@ export class ConnectionProfileRenderer implements ITreeRenderer, index: number, template: ConnectionProfileTemplate): void { - template.set(node.element); + template.set(node.element, node.filterData); } disposeTemplate(templateData: ConnectionProfileTemplate): void { templateData.dispose(); @@ -153,18 +157,21 @@ export class ConnectionProfileRenderer implements ITreeRenderer 0 ? getLabelWithFilteredSuffix(element.label) : + const labelText = element.filters.length > 0 ? getLabelWithFilteredSuffix(element.label) : element.label; - this._root.title = element.label; + this._label.element.setLabel(labelText, '', { + matches: createMatches(filterData) + }); + this._root.title = labelText; } } @@ -215,7 +225,7 @@ export class TreeNodeRenderer implements ITreeRenderer, index: number, template: TreeNodeTemplate): void { - template.set(node.element); + template.set(node.element, node.filterData); } disposeTemplate(templateData: TreeNodeTemplate): void { @@ -256,20 +266,6 @@ export class ServerTreeAccessibilityProvider implements IListAccessibilityProvid } } -/** - * Returns the first parent which contains the className - */ -function findParentElement(container: HTMLElement, className: string): HTMLElement | undefined { - let currentElement: HTMLElement | null = container; - while (currentElement) { - if (currentElement.className.indexOf(className) > -1) { - break; - } - currentElement = currentElement.parentElement; - } - return withNullAsUndefined(currentElement); -} - function getIconPath(connection: ConnectionProfile, connectionManagementService: IConnectionManagementService): IconPath | undefined { if (!connection) { return undefined; }