mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Differentiated server icons by server type: box, big data cluster, cloud... (#5241)
This commit is contained in:
137
src/sql/workbench/parts/objectExplorer/browser/iconRenderer.ts
Normal file
137
src/sql/workbench/parts/objectExplorer/browser/iconRenderer.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createCSSRule } from 'vs/base/browser/dom';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
class IconRenderer {
|
||||
private iconRegistered: Set<string> = new Set<string>();
|
||||
|
||||
public registerIcon(path: URI | IconPath): string {
|
||||
if (!path) { return undefined; }
|
||||
let iconPath: IconPath = this.toIconPath(path);
|
||||
let iconUid: string = this.getIconUid(iconPath);
|
||||
if (!this.iconRegistered.has(iconUid)) {
|
||||
createCSSRule(`.icon#${iconUid}`, `background: url("${iconPath.light.toString()}") center center no-repeat`);
|
||||
createCSSRule(`.vs-dark .icon#${iconUid}, .hc-black .icon#${iconUid}`, `background: url("${iconPath.dark.toString()}") center center no-repeat`);
|
||||
this.iconRegistered.add(iconUid);
|
||||
}
|
||||
return iconUid;
|
||||
}
|
||||
|
||||
public getIconUid(path: URI | IconPath): string {
|
||||
if (!path) { return undefined; }
|
||||
let iconPath: IconPath = this.toIconPath(path);
|
||||
return `icon${hash(iconPath.light.toString() + iconPath.dark.toString())}`;
|
||||
}
|
||||
|
||||
private toIconPath(path: URI | IconPath): IconPath {
|
||||
if (path['light']) {
|
||||
return path as IconPath;
|
||||
} else {
|
||||
let singlePath = path as URI;
|
||||
return { light: singlePath, dark: singlePath };
|
||||
}
|
||||
}
|
||||
|
||||
public putIcon(element: HTMLElement, path: URI | IconPath): void {
|
||||
if (!element || !path) { return undefined; }
|
||||
let iconUid: string = this.registerIcon(path);
|
||||
element.id = iconUid;
|
||||
}
|
||||
|
||||
public removeIcon(element: HTMLElement): void {
|
||||
if (!element) { return undefined; }
|
||||
element.id = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export const iconRenderer: IconRenderer = new IconRenderer();
|
||||
|
||||
class BadgeRenderer {
|
||||
public readonly serverConnected: string = 'serverConnected';
|
||||
public readonly serverDisconnected: string = 'serverDisconnected';
|
||||
public readonly newTag: string = 'newTag';
|
||||
|
||||
private badgeCreated: Set<string> = new Set<string>();
|
||||
|
||||
constructor() {
|
||||
this.createBadge(this.serverConnected, this.getConnectionStatusBadge(true));
|
||||
this.createBadge(this.serverDisconnected, this.getConnectionStatusBadge(false));
|
||||
this.createBadge(this.newTag, this.getNewTagBadge());
|
||||
}
|
||||
|
||||
private getConnectionStatusBadge(isConnected: boolean) {
|
||||
let circleColor: string = isConnected ? 'rgba(59, 180, 74, 100%)' : 'rgba(208, 46, 0, 100%)';
|
||||
let bgColor: string = isConnected ? 'rgba(59, 180, 74, 100%)' : 'rgba(255, 255, 255, 80%)';
|
||||
return `position: absolute;
|
||||
height: 0.25rem;
|
||||
width: 0.25rem;
|
||||
top: 14px;
|
||||
left: 19px;
|
||||
border: 0.12rem solid ${circleColor};
|
||||
border-radius: 100%;
|
||||
background: ${bgColor};
|
||||
content:"";
|
||||
font-size: 100%;
|
||||
line-height: 100%;
|
||||
color:white;
|
||||
text-align:center;
|
||||
vertical-align:middle;`
|
||||
.replace(/\t/g, ' ').replace(/\r?\n/g, ' ').replace(/ +/g, ' ');
|
||||
}
|
||||
|
||||
private getNewTagBadge(): string {
|
||||
return `position: absolute;
|
||||
height: 0.4rem;
|
||||
width: 0.4rem;
|
||||
top: 3px;
|
||||
left: 5px;
|
||||
border: 1px solid green;
|
||||
border-radius: 15%;
|
||||
background: green;
|
||||
content:"N";
|
||||
font-size: 0.3rem;
|
||||
font-weight: bold;
|
||||
line-height: 0.4rem;
|
||||
color: white;
|
||||
text-align:center;
|
||||
vertical-align:middle;`
|
||||
.replace(/\t/g, ' ').replace(/\r?\n/g, ' ').replace(/ +/g, ' ');
|
||||
}
|
||||
|
||||
private createBadge(badgeClass: string, badge: string): void {
|
||||
if (!this.badgeCreated.has(badgeClass)) {
|
||||
createCSSRule(`.${badgeClass}:after`, badge);
|
||||
this.badgeCreated.add(badgeClass);
|
||||
}
|
||||
}
|
||||
|
||||
public addBadge(element: HTMLElement, badgeClass: string): void {
|
||||
element.innerHTML = (element.innerHTML || '') +
|
||||
`<div class="${badgeClass}" style="width: 0px; height: 0px;"><div>`;
|
||||
}
|
||||
|
||||
public removeBadge(element: HTMLElement, badgeClass: string): void {
|
||||
let children: HTMLCollection = element.children;
|
||||
let current = children[0];
|
||||
while (current) {
|
||||
let next = current.nextElementSibling;
|
||||
if (current.classList.contains(badgeClass)) {
|
||||
current.remove();
|
||||
break;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const badgeRenderer: BadgeRenderer = new BadgeRenderer();
|
||||
|
||||
interface IconPath {
|
||||
light: URI;
|
||||
dark: URI;
|
||||
}
|
||||
@@ -14,6 +14,9 @@ import { ITree, IRenderer } from 'vs/base/parts/tree/browser/tree';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { TreeNode } from 'sql/workbench/parts/objectExplorer/common/treeNode';
|
||||
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { badgeRenderer, iconRenderer } from 'sql/workbench/parts/objectExplorer/browser/iconRenderer';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export interface IConnectionTemplateData {
|
||||
root: HTMLElement;
|
||||
@@ -56,7 +59,8 @@ export class ServerTreeRenderer implements IRenderer {
|
||||
|
||||
constructor(
|
||||
isCompact: boolean,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService
|
||||
) {
|
||||
// isCompact defaults to false unless explicitly set by instantiation call.
|
||||
if (isCompact) {
|
||||
@@ -152,19 +156,70 @@ export class ServerTreeRenderer implements IRenderer {
|
||||
let iconLowerCaseName = iconName.toLocaleLowerCase();
|
||||
templateData.icon.classList.add(iconLowerCaseName);
|
||||
|
||||
if (treeNode.iconPath) {
|
||||
iconRenderer.putIcon(templateData.icon, treeNode.iconPath);
|
||||
}
|
||||
|
||||
templateData.label.textContent = treeNode.label;
|
||||
templateData.root.title = treeNode.label;
|
||||
}
|
||||
|
||||
private getIconPath(connection: ConnectionProfile): IconPath {
|
||||
if (!connection) { return undefined; }
|
||||
|
||||
if (connection['iconPath']) {
|
||||
return connection['iconPath'];
|
||||
}
|
||||
|
||||
let iconId = this._connectionManagementService.getConnectionIconId(connection.id);
|
||||
if (!iconId) { return undefined; }
|
||||
|
||||
let providerProperties = this._connectionManagementService.getProviderProperties(connection.providerName);
|
||||
if (!providerProperties) { return undefined; }
|
||||
|
||||
let iconPath: IconPath = undefined;
|
||||
let pathConfig: URI | IconPath | { id: string, path: IconPath }[] = providerProperties['iconPath'];
|
||||
if (Array.isArray(pathConfig)) {
|
||||
for (const e of pathConfig) {
|
||||
if (!e.id || e.id === iconId) {
|
||||
iconPath = e.path;
|
||||
connection['iconPath'] = iconPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (pathConfig['light']) {
|
||||
iconPath = pathConfig as IconPath;
|
||||
connection['iconPath'] = iconPath;
|
||||
} else {
|
||||
let singlePath = pathConfig as URI;
|
||||
iconPath = { light: singlePath, dark: singlePath };
|
||||
connection['iconPath'] = iconPath;
|
||||
}
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
private renderServerIcon(element: HTMLElement, iconPath: IconPath, isConnected: boolean): void {
|
||||
if (!element) { return; }
|
||||
if (iconPath) {
|
||||
iconRenderer.putIcon(element, iconPath);
|
||||
}
|
||||
let badgeToRemove: string = isConnected ? badgeRenderer.serverDisconnected : badgeRenderer.serverConnected;
|
||||
let badgeToAdd: string = isConnected ? badgeRenderer.serverConnected : badgeRenderer.serverDisconnected;
|
||||
badgeRenderer.removeBadge(element, badgeToRemove);
|
||||
badgeRenderer.addBadge(element, badgeToAdd);
|
||||
}
|
||||
|
||||
private renderConnection(connection: ConnectionProfile, templateData: IConnectionTemplateData): void {
|
||||
if (!this._isCompact) {
|
||||
let iconPath: IconPath = this.getIconPath(connection);
|
||||
if (this._connectionManagementService.isConnected(undefined, connection)) {
|
||||
templateData.icon.classList.remove('disconnected');
|
||||
templateData.icon.classList.add('connected');
|
||||
this.renderServerIcon(templateData.icon, iconPath, true);
|
||||
} else {
|
||||
templateData.icon.classList.remove('connected');
|
||||
templateData.icon.classList.add('disconnected');
|
||||
this.renderServerIcon(templateData.icon, iconPath, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,3 +272,7 @@ export class ServerTreeRenderer implements IRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
interface IconPath {
|
||||
light: URI;
|
||||
dark: URI;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { NodeType, SqlThemeIcon } from 'sql/workbench/parts/objectExplorer/commo
|
||||
import * as azdata from 'sqlops';
|
||||
|
||||
import * as UUID from 'vs/base/common/uuid';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export enum TreeItemCollapsibleState {
|
||||
None = 0,
|
||||
@@ -91,6 +92,8 @@ export class TreeNode {
|
||||
|
||||
public iconType: string | SqlThemeIcon;
|
||||
|
||||
public iconPath: URI | { light: URI, dark: URI };
|
||||
|
||||
constructor(nodeTypeId: string, label: string, isAlwaysLeaf: boolean, nodePath: string,
|
||||
nodeSubType: string, nodeStatus: string, parent: TreeNode, metadata: azdata.ObjectMetadata,
|
||||
iconType: string | SqlThemeIcon,
|
||||
|
||||
Reference in New Issue
Block a user