From f67097d45e8d6c9383390e7fc6c316d594e26b54 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 16 Feb 2018 14:14:15 +0100 Subject: [PATCH] notifications - extract a reusable notifications list --- ...ationsCenter.css => notificationsList.css} | 0 .../notifications/notificationCommands.ts | 66 +++--- .../notifications/notificationsAlerts.ts | 1 - .../notifications/notificationsCenter.ts | 223 +++--------------- .../parts/notifications/notificationsList.ts | 208 ++++++++++++++++ .../notifications/notificationsStatus.ts | 12 +- src/vs/workbench/common/notifications.ts | 2 +- 7 files changed, 278 insertions(+), 234 deletions(-) rename src/vs/workbench/browser/parts/notifications/media/{notificationsCenter.css => notificationsList.css} (100%) create mode 100644 src/vs/workbench/browser/parts/notifications/notificationsList.ts diff --git a/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css b/src/vs/workbench/browser/parts/notifications/media/notificationsList.css similarity index 100% rename from src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css rename to src/vs/workbench/browser/parts/notifications/media/notificationsList.css diff --git a/src/vs/workbench/browser/parts/notifications/notificationCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationCommands.ts index 4754b2fe50f..181fb87a3b5 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationCommands.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationCommands.ts @@ -7,7 +7,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { INotificationViewItem, isNotificationViewItem } from 'vs/workbench/common/notifications'; @@ -15,6 +15,7 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { localize } from 'vs/nls'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IListService, WorkbenchList } from 'vs/platform/list/browser/listService'; export const SHOW_NOTFICATIONS_CENTER_COMMAND_ID = 'notifications.show'; export const HIDE_NOTFICATIONS_CENTER_COMMAND_ID = 'notifications.hide'; @@ -25,17 +26,14 @@ export const TOGGLE_NOTIFICATION = 'notification.toggle'; export const CLEAR_NOTFICATION = 'notification.clear'; export const CLEAR_ALL_NOTFICATIONS = 'notifications.clearAll'; -const notificationsCenterFocusedId = 'notificationsCenterFocus'; -export const NotificationsCenterFocusedContext = new RawContextKey(notificationsCenterFocusedId, true); +const notificationFocusedId = 'notificationFocus'; +export const NotificationFocusedContext = new RawContextKey(notificationFocusedId, true); const notificationsCenterVisibleId = 'notificationsCenterVisible'; export const NotificationsCenterVisibleContext = new RawContextKey(notificationsCenterVisibleId, false); -export const InNotificationsCenterContext = ContextKeyExpr.and(ContextKeyExpr.has(notificationsCenterFocusedId), ContextKeyExpr.has(notificationsCenterVisibleId)); - export interface INotificationsCenterController { readonly isVisible: boolean; - readonly selected: INotificationViewItem; show(): void; hide(): void; @@ -61,14 +59,30 @@ export function registerNotificationCommands(center: INotificationsCenterControl } } + function getNotificationFromContext(listService: IListService, context?: any): INotificationViewItem { + if (isNotificationViewItem(context)) { + return context; + } + + const list = listService.lastFocusedList; + if (list instanceof WorkbenchList) { + const focusedElement = list.getFocusedElements()[0]; + if (isNotificationViewItem(focusedElement)) { + return focusedElement; + } + } + + return void 0; + } + // Show Notifications Cneter CommandsRegistry.registerCommand(SHOW_NOTFICATIONS_CENTER_COMMAND_ID, () => showCenter()); // Hide Notifications Center KeybindingsRegistry.registerCommandAndKeybindingRule({ id: HIDE_NOTFICATIONS_CENTER_COMMAND_ID, - weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), - when: InNotificationsCenterContext, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50), + when: NotificationsCenterVisibleContext, primary: KeyCode.Escape, handler: accessor => hideCenter(accessor) }); @@ -80,19 +94,13 @@ export function registerNotificationCommands(center: INotificationsCenterControl KeybindingsRegistry.registerCommandAndKeybindingRule({ id: CLEAR_NOTFICATION, weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), - when: InNotificationsCenterContext, + when: NotificationFocusedContext, primary: KeyCode.Delete, mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace }, handler: (accessor, args?: any) => { - let notification: INotificationViewItem; - if (isNotificationViewItem(args)) { - notification = args; - } else { - notification = center.selected; - } - + const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification) { notification.dispose(); } @@ -103,16 +111,10 @@ export function registerNotificationCommands(center: INotificationsCenterControl KeybindingsRegistry.registerCommandAndKeybindingRule({ id: EXPAND_NOTIFICATION, weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), - when: InNotificationsCenterContext, + when: NotificationFocusedContext, primary: KeyCode.RightArrow, handler: (accessor, args?: any) => { - let notification: INotificationViewItem; - if (isNotificationViewItem(args)) { - notification = args; - } else { - notification = center.selected; - } - + const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification) { notification.expand(); } @@ -123,16 +125,10 @@ export function registerNotificationCommands(center: INotificationsCenterControl KeybindingsRegistry.registerCommandAndKeybindingRule({ id: COLLAPSE_NOTIFICATION, weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), - when: InNotificationsCenterContext, + when: NotificationFocusedContext, primary: KeyCode.LeftArrow, handler: (accessor, args?: any) => { - let notification: INotificationViewItem; - if (isNotificationViewItem(args)) { - notification = args; - } else { - notification = center.selected; - } - + const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification) { notification.collapse(); } @@ -143,10 +139,10 @@ export function registerNotificationCommands(center: INotificationsCenterControl KeybindingsRegistry.registerCommandAndKeybindingRule({ id: TOGGLE_NOTIFICATION, weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), - when: InNotificationsCenterContext, + when: NotificationFocusedContext, primary: KeyCode.Space, handler: accessor => { - const notification = center.selected; + const notification = getNotificationFromContext(accessor.get(IListService)); if (notification) { notification.toggle(); } @@ -165,7 +161,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl - // TODO@Notification remove me + // TODO@notifications remove me CommandsRegistry.registerCommand('notifications.showInfo', accessor => { accessor.get(INotificationService).info('This is an information message!'); }); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts b/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts index 84c98c310eb..9909020457e 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts @@ -13,7 +13,6 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { toErrorMessage } from 'vs/base/common/errorMessage'; export class NotificationsAlerts { - private toDispose: IDisposable[]; constructor(private model: INotificationsModel) { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index 67e719c6d86..727b4c21405 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -5,31 +5,22 @@ 'use strict'; -import 'vs/css!./media/notificationsCenter'; -import { addClass, removeClass, isAncestor } from 'vs/base/browser/dom'; -import { WorkbenchList } from 'vs/platform/list/browser/listService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IListOptions } from 'vs/base/browser/ui/list/listWidget'; -import { localize } from 'vs/nls'; -import { Themable, NOTIFICATIONS_BORDER, NOTIFICATIONS_LINKS, NOTIFICATIONS_BACKGROUND, NOTIFICATIONS_FOREGROUND } from 'vs/workbench/common/theme'; -import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; -import { INotificationViewItem, INotificationsModel, INotificationChangeEvent, NotificationChangeType } from 'vs/workbench/common/notifications'; -import { NotificationsListDelegate, NotificationRenderer } from 'vs/workbench/browser/parts/notifications/notificationsViewer'; -import { NotificationActionRunner } from 'vs/workbench/browser/parts/notifications/notificationsActions'; +import { Themable } from 'vs/workbench/common/theme'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { INotificationsModel, INotificationChangeEvent, NotificationChangeType } from 'vs/workbench/common/notifications'; import { Dimension } from 'vs/base/browser/builder'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import Event, { Emitter } from 'vs/base/common/event'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { NotificationsCenterFocusedContext, NotificationsCenterVisibleContext } from 'vs/workbench/browser/parts/notifications/notificationCommands'; +import { NotificationsCenterVisibleContext } from 'vs/workbench/browser/parts/notifications/notificationCommands'; +import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; export class NotificationsCenter extends Themable { private static MAX_DIMENSIONS = new Dimension(600, 600); - private listContainer: HTMLElement; - private list: WorkbenchList; - private viewModel: INotificationViewItem[]; + private notificationsList: NotificationsList; private _isVisible: boolean; private workbenchDimensions: Dimension; private _onDidChangeVisibility: Emitter; @@ -38,8 +29,8 @@ export class NotificationsCenter extends Themable { constructor( private container: HTMLElement, private model: INotificationsModel, - @IInstantiationService private instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, + @IInstantiationService private instantiationService: IInstantiationService, @IPartService private partService: IPartService, @IContextKeyService contextKeyService: IContextKeyService ) { @@ -50,10 +41,13 @@ export class NotificationsCenter extends Themable { this.notificationsCenterVisibleContextKey = NotificationsCenterVisibleContext.bindTo(contextKeyService); - this.viewModel = []; this.registerListeners(); } + private registerListeners(): void { + this.toUnbind.push(this.model.onDidNotificationChange(e => this.onDidNotificationChange(e))); + } + public get onDidChangeVisibility(): Event { return this._onDidChangeVisibility.event; } @@ -62,41 +56,22 @@ export class NotificationsCenter extends Themable { return this._isVisible; } - public get selected(): INotificationViewItem { - if (!this._isVisible || !this.list) { - return null; - } - - const focusedIndex = this.list.getFocus()[0]; - - return this.viewModel[focusedIndex]; - } - - private registerListeners(): void { - this.toUnbind.push(this.model.onDidNotificationChange(e => this.onDidNotificationChange(e))); - } - public show(): void { - if (this._isVisible) { - this.focusNotificationsList(); - - return; // already visible - } // Lazily create if showing for the first time - if (!this.list) { - this.createNotificationsList(); + if (!this.notificationsList) { + this.notificationsList = this.instantiationService.createInstance(NotificationsList, this.container); } // Make visible this._isVisible = true; - addClass(this.listContainer, 'visible'); + this.notificationsList.show(); - // Show all notifications that are present now - this.onNotificationsAdded(0, this.model.notifications); + // Layout + this.layoutList(); - // Focus - this.focusNotificationsList(); + // Show all notifications that are present now + this.notificationsList.updateNotificationsList(0, 0, this.model.notifications); // Context Key this.notificationsCenterVisibleContextKey.set(true); @@ -105,142 +80,38 @@ export class NotificationsCenter extends Themable { this._onDidChangeVisibility.fire(); } - private focusNotificationsList(): void { - if (!this._isVisible) { - return; - } - - this.list.domFocus(); - } - - private createNotificationsList(): void { - - // List Container - this.listContainer = document.createElement('div'); - addClass(this.listContainer, 'notifications-list-container'); - - // Notification Renderer - const renderer = this.instantiationService.createInstance(NotificationRenderer, this.instantiationService.createInstance(NotificationActionRunner)); - this.toUnbind.push(renderer); - - // List - this.list = this.instantiationService.createInstance( - WorkbenchList, - this.listContainer, - new NotificationsListDelegate(this.listContainer), - [renderer], - { - ariaLabel: localize('notificationsList', "Notifications List") - } as IListOptions - ); - this.toUnbind.push(this.list); - - this.toUnbind.push(this.list.onMouseDblClick(event => { - const item = event.element; - item.toggle(); - })); - - // Context key - NotificationsCenterFocusedContext.bindTo(this.list.contextKeyService); - - // Only allow for focus in notifications, as the - // selection is too strong over the contents of - // the notification - this.toUnbind.push(this.list.onSelectionChange(e => { - if (e.indexes.length > 0) { - this.list.setSelection([]); - } - })); - - this.container.appendChild(this.listContainer); - - this.updateStyles(); - this.layoutList(); - } - private onDidNotificationChange(e: INotificationChangeEvent): void { if (!this._isVisible) { return; // only if visible } + // Update notifications list based on event switch (e.kind) { case NotificationChangeType.ADD: - return this.onNotificationsAdded(e.index, [e.item]); + this.notificationsList.updateNotificationsList(e.index, 0, [e.item]); + break; case NotificationChangeType.CHANGE: - return this.onNotificationChanged(e.index, e.item); + this.notificationsList.updateNotificationsList(e.index, 1, [e.item]); + break; case NotificationChangeType.REMOVE: - return this.onNotificationRemoved(e.index, e.item); + this.notificationsList.updateNotificationsList(e.index, 1); + break; } - } - - private onNotificationsAdded(index: number, items: INotificationViewItem[]): void { - this.updateNotificationsList(index, 0, items); - } - - private onNotificationChanged(index: number, item: INotificationViewItem): void { - this.updateNotificationsList(index, 1, [item]); - } - - private onNotificationRemoved(index: number, item: INotificationViewItem): void { - this.updateNotificationsList(index, 1); - } - - private updateNotificationsList(start: number, deleteCount: number, items: INotificationViewItem[] = []) { - const listHasDOMFocus = isAncestor(document.activeElement, this.listContainer); - - // Remember focus - const focusedIndex = this.list.getFocus()[0]; - const focusedItem = this.viewModel[focusedIndex]; - - // Update view model - this.viewModel.splice(start, deleteCount, ...items); - - // Update list - this.list.splice(start, deleteCount, items); - this.list.layout(); // Hide if no more notifications to show - if (this.viewModel.length === 0) { + if (this.model.notifications.length === 0) { this.hide(); } - - // Otherwise restore focus if we had - else if (typeof focusedIndex === 'number') { - let indexToFocus = 0; - if (focusedItem) { - let indexToFocusCandidate = this.viewModel.indexOf(focusedItem); - if (indexToFocusCandidate === -1) { - indexToFocusCandidate = focusedIndex - 1; // item could have been removed - } - - if (indexToFocusCandidate < this.viewModel.length && indexToFocusCandidate >= 0) { - indexToFocus = indexToFocusCandidate; - } - } - - this.list.setFocus([indexToFocus]); - } - - // Restore DOM focus if we had focus before - if (listHasDOMFocus) { - this.list.domFocus(); - } } public hide(): void { - if (!this._isVisible || !this.list) { + if (!this._isVisible || !this.notificationsList) { return; // already hidden } // Hide this._isVisible = false; - removeClass(this.listContainer, 'visible'); - - // Clear list - this.list.splice(0, this.viewModel.length); - - // Clear view model - this.viewModel = []; + this.notificationsList.hide(); // Context Key this.notificationsCenterVisibleContextKey.set(false); @@ -249,26 +120,10 @@ export class NotificationsCenter extends Themable { this._onDidChangeVisibility.fire(); } - protected updateStyles(): void { - if (this.listContainer) { - const foreground = this.getColor(NOTIFICATIONS_FOREGROUND); - this.listContainer.style.color = foreground ? foreground.toString() : null; - - const background = this.getColor(NOTIFICATIONS_BACKGROUND); - this.listContainer.style.background = background ? background.toString() : null; - - const outlineColor = this.getColor(contrastBorder); - this.listContainer.style.outlineColor = outlineColor ? outlineColor.toString() : null; - - const widgetShadowColor = this.getColor(widgetShadow); - this.listContainer.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : null; - } - } - public layout(dimension: Dimension): void { this.workbenchDimensions = dimension; - if (this._isVisible && this.listContainer) { + if (this._isVisible && this.notificationsList) { this.layoutList(); } } @@ -304,9 +159,7 @@ export class NotificationsCenter extends Themable { } } - this.listContainer.style.width = `${width}px`; - this.list.getHTMLElement().style.maxHeight = `${maxHeight}px`; - this.list.layout(); + this.notificationsList.layout(new Dimension(width, maxHeight)); } public clearAll(): void { @@ -319,16 +172,4 @@ export class NotificationsCenter extends Themable { this.model.notifications[0].dispose(); } } -} - -registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { - const linkColor = theme.getColor(NOTIFICATIONS_LINKS); - if (linkColor) { - collector.addRule(`.monaco-workbench > .notifications-list-container .notification-list-item .notification-list-item-message a { color: ${linkColor}; }`); - } - - const notificationBorderColor = theme.getColor(NOTIFICATIONS_BORDER); - if (notificationBorderColor) { - collector.addRule(`.monaco-workbench > .notifications-list-container .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`); - } -}); +} \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts new file mode 100644 index 00000000000..d92d6c96e12 --- /dev/null +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -0,0 +1,208 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import 'vs/css!./media/notificationsList'; +import { addClass, removeClass, isAncestor } from 'vs/base/browser/dom'; +import { WorkbenchList } from 'vs/platform/list/browser/listService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IListOptions } from 'vs/base/browser/ui/list/listWidget'; +import { localize } from 'vs/nls'; +import { Themable, NOTIFICATIONS_BORDER, NOTIFICATIONS_LINKS, NOTIFICATIONS_BACKGROUND, NOTIFICATIONS_FOREGROUND } from 'vs/workbench/common/theme'; +import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import { contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { INotificationViewItem } from 'vs/workbench/common/notifications'; +import { NotificationsListDelegate, NotificationRenderer } from 'vs/workbench/browser/parts/notifications/notificationsViewer'; +import { NotificationActionRunner } from 'vs/workbench/browser/parts/notifications/notificationsActions'; +import { Dimension } from 'vs/base/browser/builder'; +import { NotificationFocusedContext } from 'vs/workbench/browser/parts/notifications/notificationCommands'; + +export class NotificationsList extends Themable { + private listContainer: HTMLElement; + private list: WorkbenchList; + private viewModel: INotificationViewItem[]; + private dimensions: Dimension; + private isVisible: boolean; + + constructor( + private container: HTMLElement, + @IInstantiationService private instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService + ) { + super(themeService); + + this.viewModel = []; + } + + public show(): void { + if (this.isVisible) { + this.list.domFocus(); + + return; // already visible + } + + // Lazily create if showing for the first time + if (!this.list) { + this.createNotificationsList(); + } + + // Make visible + this.isVisible = true; + addClass(this.listContainer, 'visible'); + + // Focus + this.list.domFocus(); + } + + private createNotificationsList(): void { + + // List Container + this.listContainer = document.createElement('div'); + addClass(this.listContainer, 'notifications-list-container'); + + // Notification Renderer + const renderer = this.instantiationService.createInstance(NotificationRenderer, this.instantiationService.createInstance(NotificationActionRunner)); + this.toUnbind.push(renderer); + + // List + this.list = this.instantiationService.createInstance( + WorkbenchList, + this.listContainer, + new NotificationsListDelegate(this.listContainer), + [renderer], + { + ariaLabel: localize('notificationsList', "Notifications List") + } as IListOptions + ); + this.toUnbind.push(this.list); + + // Toggle on double click + this.toUnbind.push(this.list.onMouseDblClick(event => (event.element as INotificationViewItem).toggle())); + + // Context key + NotificationFocusedContext.bindTo(this.list.contextKeyService); + + // Only allow for focus in notifications, as the + // selection is too strong over the contents of + // the notification + this.toUnbind.push(this.list.onSelectionChange(e => { + if (e.indexes.length > 0) { + this.list.setSelection([]); + } + })); + + this.container.appendChild(this.listContainer); + + this.updateStyles(); + } + + public updateNotificationsList(start: number, deleteCount: number, items: INotificationViewItem[] = []) { + const listHasDOMFocus = isAncestor(document.activeElement, this.listContainer); + + // Remember focus + const focusedIndex = this.list.getFocus()[0]; + const focusedItem = this.viewModel[focusedIndex]; + + // Update view model + this.viewModel.splice(start, deleteCount, ...items); + + // Update list + this.list.splice(start, deleteCount, items); + this.list.layout(); + + // Hide if no more notifications to show + if (this.viewModel.length === 0) { + this.hide(); + } + + // Otherwise restore focus if we had + else if (typeof focusedIndex === 'number') { + let indexToFocus = 0; + if (focusedItem) { + let indexToFocusCandidate = this.viewModel.indexOf(focusedItem); + if (indexToFocusCandidate === -1) { + indexToFocusCandidate = focusedIndex - 1; // item could have been removed + } + + if (indexToFocusCandidate < this.viewModel.length && indexToFocusCandidate >= 0) { + indexToFocus = indexToFocusCandidate; + } + } + + this.list.setFocus([indexToFocus]); + } + + // Restore DOM focus if we had focus before + if (listHasDOMFocus) { + this.list.domFocus(); + } + } + + public hide(): void { + if (!this.isVisible || !this.list) { + return; // already hidden + } + + // Hide + this.isVisible = false; + removeClass(this.listContainer, 'visible'); + + // Clear list + this.list.splice(0, this.viewModel.length); + + // Clear view model + this.viewModel = []; + } + + protected updateStyles(): void { + if (this.listContainer) { + const foreground = this.getColor(NOTIFICATIONS_FOREGROUND); + this.listContainer.style.color = foreground ? foreground.toString() : null; + + const background = this.getColor(NOTIFICATIONS_BACKGROUND); + this.listContainer.style.background = background ? background.toString() : null; + + const outlineColor = this.getColor(contrastBorder); + this.listContainer.style.outlineColor = outlineColor ? outlineColor.toString() : null; + + const widgetShadowColor = this.getColor(widgetShadow); + this.listContainer.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : null; + } + } + + public layout(dimension: Dimension): void { + this.dimensions = dimension; + + this.layoutList(); + } + + private layoutList(): void { + if (this.list) { + this.listContainer.style.width = `${this.dimensions.width}px`; + + this.list.getHTMLElement().style.maxHeight = `${this.dimensions.height}px`; + this.list.layout(); + } + } + + public dispose(): void { + this.hide(); + + super.dispose(); + } +} + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + const linkColor = theme.getColor(NOTIFICATIONS_LINKS); + if (linkColor) { + collector.addRule(`.monaco-workbench > .notifications-list-container .notification-list-item .notification-list-item-message a { color: ${linkColor}; }`); + } + + const notificationBorderColor = theme.getColor(NOTIFICATIONS_BORDER); + if (notificationBorderColor) { + collector.addRule(`.monaco-workbench > .notifications-list-container .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`); + } +}); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index 1d0dc86bd26..783fce1d46c 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -14,7 +14,7 @@ import { localize } from 'vs/nls'; export class NotificationsStatus { private statusItem: IDisposable; private toDispose: IDisposable[]; - private isCenterVisible: boolean; + private isNotificationsCenterVisible: boolean; constructor( private model: INotificationsModel, @@ -26,8 +26,8 @@ export class NotificationsStatus { } public update(isCenterVisible: boolean): void { - if (this.isCenterVisible !== isCenterVisible) { - this.isCenterVisible = isCenterVisible; + if (this.isNotificationsCenterVisible !== isCenterVisible) { + this.isNotificationsCenterVisible = isCenterVisible; this.updateNotificationsStatusItem(); } } @@ -55,9 +55,9 @@ export class NotificationsStatus { const notificationsCount = this.model.notifications.length; if (notificationsCount > 0) { this.statusItem = this.statusbarService.addEntry({ - text: this.isCenterVisible ? '$(megaphone) ' + localize('hideNotifications', "Hide Notifications") : `$(megaphone) ${notificationsCount}`, - command: this.isCenterVisible ? HIDE_NOTFICATIONS_CENTER_COMMAND_ID : SHOW_NOTFICATIONS_CENTER_COMMAND_ID, - tooltip: this.isCenterVisible ? localize('hideNotifications', "Hide Notifications") : localize('notifications', "{0} notifications", notificationsCount) + text: this.isNotificationsCenterVisible ? '$(megaphone) ' + localize('hideNotifications', "Hide Notifications") : `$(megaphone) ${notificationsCount}`, + command: this.isNotificationsCenterVisible ? HIDE_NOTFICATIONS_CENTER_COMMAND_ID : SHOW_NOTFICATIONS_CENTER_COMMAND_ID, + tooltip: this.isNotificationsCenterVisible ? localize('hideNotifications', "Hide Notifications") : localize('notifications', "{0} notifications", notificationsCount) }, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */); } } diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 0d9492eef09..78509de5e76 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -260,7 +260,7 @@ export class NotificationViewItem implements INotificationViewItem { } public expand(): void { - if (this._expanded) { + if (this._expanded || !this.canCollapse) { return; } -- GitLab