diff --git a/src/sql/parts/dashboard/widgets/tasks/tasksWidget.component.ts b/src/sql/parts/dashboard/widgets/tasks/tasksWidget.component.ts index c77b6ba701..5bb88a043b 100644 --- a/src/sql/parts/dashboard/widgets/tasks/tasksWidget.component.ts +++ b/src/sql/parts/dashboard/widgets/tasks/tasksWidget.component.ts @@ -52,6 +52,7 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On private _profile: IConnectionProfile; private _scrollableElement: ScrollableElement; private $container: Builder; + static readonly ICON_PATH_TO_CSS_RULES: Map = new Map(); private _inited = false; @@ -131,9 +132,9 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On let tile = $('div.task-tile').style('height', this._size + 'px').style('width', this._size + 'px'); let innerTile = $('div'); - // @SQLTODO - iconPath shouldn't be used as a CSS class - if (action.iconPath && action.iconPath.dark) { - let icon = $('span.icon').addClass(action.iconPath.dark); + let iconClassName = TaskRegistry.getOrCreateTaskIconClassName(action); + if (iconClassName) { + let icon = $('span.icon').addClass(iconClassName); innerTile.append(icon); } innerTile.append(label); diff --git a/src/sql/parts/profiler/contrib/profilerActions.ts b/src/sql/parts/profiler/contrib/profilerActions.ts index 1a208e32fa..31f6b52dcc 100644 --- a/src/sql/parts/profiler/contrib/profilerActions.ts +++ b/src/sql/parts/profiler/contrib/profilerActions.ts @@ -238,7 +238,8 @@ export class NewProfilerAction extends Task { super({ id: NewProfilerAction.ID, title: NewProfilerAction.LABEL, - iconPath: { dark: NewProfilerAction.ICON, light: NewProfilerAction.ICON } + iconPath: { dark: NewProfilerAction.ICON, light: NewProfilerAction.ICON }, + iconClass: NewProfilerAction.ICON }); } diff --git a/src/sql/platform/tasks/common/tasks.ts b/src/sql/platform/tasks/common/tasks.ts index 49aab3cc57..0ac784f7fe 100644 --- a/src/sql/platform/tasks/common/tasks.ts +++ b/src/sql/platform/tasks/common/tasks.ts @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; import * as types from 'vs/base/common/types'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -14,9 +15,10 @@ import { ILocalizedString, IMenuItem, MenuRegistry, ICommandAction } from 'vs/pl import Event, { Emitter } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; import { LinkedList } from 'vs/base/common/linkedList'; - +import { IdGenerator } from 'vs/base/common/idGenerator'; +import { createCSSRule } from 'vs/base/browser/dom'; +import URI from 'vs/base/common/uri'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; export interface ITaskOptions { @@ -24,6 +26,7 @@ export interface ITaskOptions { title: string; iconPath: { dark: string; light: string; }; description?: ITaskHandlerDescription; + iconClass?: string; } export abstract class Task { @@ -31,12 +34,14 @@ export abstract class Task { public readonly title: string; public readonly iconPathDark: string; public readonly iconPath: { dark: string; light: string; }; + private readonly _iconClass: string; private readonly _description: ITaskHandlerDescription; constructor(opts: ITaskOptions) { this.id = opts.id; this.title = opts.title; this.iconPath = opts.iconPath; + this._iconClass = opts.iconClass; this._description = opts.description; } @@ -44,7 +49,8 @@ export abstract class Task { return { id: this.id, handler: (accessor, profile, args) => this.runTask(accessor, profile, args), - description: this._description + description: this._description, + iconClass: this._iconClass }; } @@ -91,20 +97,25 @@ export interface ITask { handler: ITaskHandler; precondition?: ContextKeyExpr; description?: ITaskHandlerDescription; + iconClass?: string; } export interface ITaskRegistry { registerTask(id: string, command: ITaskHandler): IDisposable; registerTask(command: ITask): IDisposable; getTasks(): string[]; + getOrCreateTaskIconClassName(item: ICommandAction): string; onTaskRegistered: Event; } +const ids = new IdGenerator('task-icon-'); + export const TaskRegistry: ITaskRegistry = new class implements ITaskRegistry { private _tasks = new Array(); private _onTaskRegistered = new Emitter(); public readonly onTaskRegistered: Event = this._onTaskRegistered.event; + private taskIdToIconClassNameMap: Map = new Map(); registerTask(idOrTask: string | ITask, handler?: ITaskHandler): IDisposable { let disposable: IDisposable; @@ -113,6 +124,9 @@ export const TaskRegistry: ITaskRegistry = new class implements ITaskRegistry { disposable = CommandsRegistry.registerCommand(idOrTask, handler); id = idOrTask; } else { + if (idOrTask.iconClass) { + this.taskIdToIconClassNameMap.set(idOrTask.id, idOrTask.iconClass); + } disposable = CommandsRegistry.registerCommand(idOrTask); id = idOrTask.id; } @@ -131,6 +145,19 @@ export const TaskRegistry: ITaskRegistry = new class implements ITaskRegistry { }; } + getOrCreateTaskIconClassName(item: ICommandAction): string { + let iconClass = null; + if (this.taskIdToIconClassNameMap.has(item.id)) { + iconClass = this.taskIdToIconClassNameMap.get(item.id); + } else if (item.iconPath) { + iconClass = ids.nextId(); + createCSSRule(`.icon.${iconClass}`, `background-image: url("${URI.file(item.iconPath.light || item.iconPath.dark).toString()}")`); + createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${URI.file(item.iconPath.dark).toString()}")`); + this.taskIdToIconClassNameMap.set(item.id, iconClass); + } + return iconClass; + } + getTasks(): string[] { return this._tasks.slice(0); } diff --git a/src/sql/workbench/common/actions.ts b/src/sql/workbench/common/actions.ts index b98a2f905c..f65cff0ef6 100644 --- a/src/sql/workbench/common/actions.ts +++ b/src/sql/workbench/common/actions.ts @@ -51,7 +51,8 @@ export class NewQueryAction extends Task { super({ id: NewQueryAction.ID, title: NewQueryAction.LABEL, - iconPath: { dark: NewQueryAction.ICON, light: NewQueryAction.ICON } + iconPath: { dark: NewQueryAction.ICON, light: NewQueryAction.ICON }, + iconClass: NewQueryAction.ICON }); } @@ -292,7 +293,8 @@ export class BackupAction extends Task { super({ id: BackupAction.ID, title: BackupAction.LABEL, - iconPath: { dark: BackupAction.ICON, light: BackupAction.ICON } + iconPath: { dark: BackupAction.ICON, light: BackupAction.ICON }, + iconClass: BackupAction.ICON }); } @@ -322,7 +324,8 @@ export class RestoreAction extends Task { super({ id: RestoreAction.ID, title: RestoreAction.LABEL, - iconPath: { dark: RestoreAction.ICON, light: RestoreAction.ICON } + iconPath: { dark: RestoreAction.ICON, light: RestoreAction.ICON }, + iconClass: RestoreAction.ICON }); } @@ -421,7 +424,8 @@ export class ConfigureDashboardAction extends Task { super({ id: ConfigureDashboardAction.ID, title: ConfigureDashboardAction.LABEL, - iconPath: { dark: ConfigureDashboardAction.ICON, light: ConfigureDashboardAction.ICON } + iconPath: { dark: ConfigureDashboardAction.ICON, light: ConfigureDashboardAction.ICON }, + iconClass: ConfigureDashboardAction.ICON }); }