提交 56064364 编写于 作者: B Benjamin Pasero

notifications - add progress bar and API

上级 5bd22ef4
...@@ -97,9 +97,9 @@ export class Button { ...@@ -97,9 +97,9 @@ export class Button {
}); });
// Also set hover background when button is focused for feedback // Also set hover background when button is focused for feedback
const tracker = DOM.trackFocus(this.$el.getHTMLElement()); this.focusTracker = DOM.trackFocus(this.$el.getHTMLElement());
tracker.onDidFocus(() => this.setHoverBackground()); this.focusTracker.onDidFocus(() => this.setHoverBackground());
tracker.onDidBlur(() => this.applyStyles()); // restore standard styles this.focusTracker.onDidBlur(() => this.applyStyles()); // restore standard styles
this.applyStyles(); this.applyStyles();
} }
......
...@@ -45,7 +45,9 @@ export class ProgressBar { ...@@ -45,7 +45,9 @@ export class ProgressBar {
private animationStopToken: ValueCallback; private animationStopToken: ValueCallback;
private progressBarBackground: Color; private progressBarBackground: Color;
constructor(builder: Builder, options?: IProgressBarOptions) { constructor(container: Builder, options?: IProgressBarOptions);
constructor(container: HTMLElement, options?: IProgressBarOptions);
constructor(container: any, options?: IProgressBarOptions) {
this.options = options || Object.create(null); this.options = options || Object.create(null);
mixin(this.options, defaultOpts, false); mixin(this.options, defaultOpts, false);
...@@ -54,11 +56,13 @@ export class ProgressBar { ...@@ -54,11 +56,13 @@ export class ProgressBar {
this.progressBarBackground = this.options.progressBarBackground; this.progressBarBackground = this.options.progressBarBackground;
this.create(builder); this.create(container);
} }
private create(parent: Builder): void { private create(container: Builder): void;
parent.div({ 'class': css_progress_container }, (builder) => { private create(container: HTMLElement): void;
private create(container: any): void {
$(container).div({ 'class': css_progress_container }, (builder) => {
this.element = builder.clone(); this.element = builder.clone();
builder.div({ 'class': css_progress_bit }).on([DOM.EventType.ANIMATION_START, DOM.EventType.ANIMATION_END, DOM.EventType.ANIMATION_ITERATION], (e: Event) => { builder.div({ 'class': css_progress_bit }).on([DOM.EventType.ANIMATION_START, DOM.EventType.ANIMATION_END, DOM.EventType.ANIMATION_ITERATION], (e: Event) => {
......
...@@ -285,7 +285,7 @@ export class SimpleNotificationService implements INotificationService { ...@@ -285,7 +285,7 @@ export class SimpleNotificationService implements INotificationService {
public _serviceBrand: any; public _serviceBrand: any;
private static readonly Empty: INotificationHandle = { dispose: () => undefined }; private static readonly Empty: INotificationHandle = { dispose: () => undefined, progress: undefined };
public info(message: string): INotificationHandle { public info(message: string): INotificationHandle {
return this.notify({ severity: Severity.Info, message }); return this.notify({ severity: Severity.Info, message });
......
...@@ -25,7 +25,15 @@ export interface INotificationActions { ...@@ -25,7 +25,15 @@ export interface INotificationActions {
secondary?: IAction[]; secondary?: IAction[];
} }
export interface INotificationProgress {
infinite(): void;
total(value: number): void;
worked(value: number): void;
done(): void;
}
export interface INotificationHandle extends IDisposable { export interface INotificationHandle extends IDisposable {
readonly progress: INotificationProgress;
} }
export interface INotificationService { export interface INotificationService {
......
...@@ -112,4 +112,11 @@ ...@@ -112,4 +112,11 @@
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-actions-container .monaco-button:not(:first-of-type) { .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-actions-container .monaco-button:not(:first-of-type) {
margin-left: 10px; margin-left: 10px;
}
/** Notification: Progress */
.monaco-workbench .notifications-list-container .progress-bit {
height: 2px;
bottom: 0;
} }
\ No newline at end of file
...@@ -66,7 +66,6 @@ export class NotificationsList extends Themable { ...@@ -66,7 +66,6 @@ export class NotificationsList extends Themable {
// Notification Renderer // Notification Renderer
const renderer = this.instantiationService.createInstance(NotificationRenderer, this.instantiationService.createInstance(NotificationActionRunner)); const renderer = this.instantiationService.createInstance(NotificationRenderer, this.instantiationService.createInstance(NotificationActionRunner));
this.toUnbind.push(renderer);
// List // List
this.list = this.instantiationService.createInstance( this.list = this.instantiationService.createInstance(
......
...@@ -14,7 +14,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; ...@@ -14,7 +14,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { Severity } from 'vs/platform/message/common/message'; import { Severity } from 'vs/platform/message/common/message';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { Button } from 'vs/base/browser/ui/button/button'; import { Button } from 'vs/base/browser/ui/button/button';
import { attachButtonStyler } from 'vs/platform/theme/common/styler'; import { attachButtonStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IMarkdownString } from 'vs/base/common/htmlContent';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
...@@ -27,6 +27,7 @@ import { INotificationViewItem, NotificationViewItem } from 'vs/workbench/common ...@@ -27,6 +27,7 @@ import { INotificationViewItem, NotificationViewItem } from 'vs/workbench/common
import { ClearNotificationAction, ExpandNotificationAction, CollapseNotificationAction, ConfigureNotificationAction } from 'vs/workbench/browser/parts/notifications/notificationsActions'; import { ClearNotificationAction, ExpandNotificationAction, CollapseNotificationAction, ConfigureNotificationAction } from 'vs/workbench/browser/parts/notifications/notificationsActions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { MarkedOptions } from 'vs/base/common/marked/marked'; import { MarkedOptions } from 'vs/base/common/marked/marked';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
export class NotificationsListDelegate implements IDelegate<INotificationViewItem> { export class NotificationsListDelegate implements IDelegate<INotificationViewItem> {
...@@ -117,6 +118,9 @@ export interface INotificationTemplateData { ...@@ -117,6 +118,9 @@ export interface INotificationTemplateData {
detailsRow: HTMLElement; detailsRow: HTMLElement;
source: HTMLElement; source: HTMLElement;
actionsContainer: HTMLElement; actionsContainer: HTMLElement;
progress: ProgressBar;
renderer: NotificationTemplateRenderer;
} }
class NotificationMessageMarkdownRenderer { class NotificationMessageMarkdownRenderer {
...@@ -150,29 +154,12 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN ...@@ -150,29 +154,12 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN
public static readonly TEMPLATE_ID = 'notification'; public static readonly TEMPLATE_ID = 'notification';
private static readonly SEVERITIES: ('info' | 'warning' | 'error')[] = ['info', 'warning', 'error'];
private toDispose: IDisposable[];
private closeNotificationAction: ClearNotificationAction;
private expandNotificationAction: ExpandNotificationAction;
private collapseNotificationAction: CollapseNotificationAction;
constructor( constructor(
private actionRunner: IActionRunner, private actionRunner: IActionRunner,
@IOpenerService private openerService: IOpenerService,
@IThemeService private themeService: IThemeService, @IThemeService private themeService: IThemeService,
@IInstantiationService private instantiationService: IInstantiationService,
@IContextMenuService private contextMenuService: IContextMenuService, @IContextMenuService private contextMenuService: IContextMenuService,
@IKeybindingService private keybindingService: IKeybindingService @IInstantiationService private instantiationService: IInstantiationService
) { ) {
this.toDispose = [];
this.closeNotificationAction = instantiationService.createInstance(ClearNotificationAction, ClearNotificationAction.ID, ClearNotificationAction.LABEL);
this.expandNotificationAction = instantiationService.createInstance(ExpandNotificationAction, ExpandNotificationAction.ID, ExpandNotificationAction.LABEL);
this.collapseNotificationAction = instantiationService.createInstance(CollapseNotificationAction, CollapseNotificationAction.ID, CollapseNotificationAction.LABEL);
this.toDispose.push(this.closeNotificationAction, this.expandNotificationAction, this.collapseNotificationAction);
} }
public get templateId() { public get templateId() {
...@@ -218,6 +205,7 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN ...@@ -218,6 +205,7 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN
} }
} }
); );
data.toDispose.push(data.toolbar);
// Details Row // Details Row
data.detailsRow = document.createElement('div'); data.detailsRow = document.createElement('div');
...@@ -244,43 +232,83 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN ...@@ -244,43 +232,83 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN
data.mainRow.appendChild(data.message); data.mainRow.appendChild(data.message);
data.mainRow.appendChild(toolbarContainer); data.mainRow.appendChild(toolbarContainer);
// Progress: below the rows to span the entire width of the item
data.progress = new ProgressBar(container);
data.toDispose.push(attachProgressBarStyler(data.progress, this.themeService));
data.toDispose.push(data.progress);
// Renderer
data.renderer = this.instantiationService.createInstance(NotificationTemplateRenderer, data, this.actionRunner);
data.toDispose.push(data.renderer);
return data; return data;
} }
private toSeverity(severity: 'info' | 'warning' | 'error'): Severity { public renderElement(notification: INotificationViewItem, index: number, data: INotificationTemplateData): void {
switch (severity) { data.renderer.setInput(notification);
case 'info': }
return Severity.Info;
case 'warning': public disposeTemplate(templateData: INotificationTemplateData): void {
return Severity.Warning; templateData.toDispose = dispose(templateData.toDispose);
case 'error': }
return Severity.Error; }
export class NotificationTemplateRenderer {
private static closeNotificationAction: ClearNotificationAction;
private static expandNotificationAction: ExpandNotificationAction;
private static collapseNotificationAction: CollapseNotificationAction;
private static readonly SEVERITIES: ('info' | 'warning' | 'error')[] = ['info', 'warning', 'error'];
private inputDisposeables: IDisposable[];
constructor(
private template: INotificationTemplateData,
private actionRunner: IActionRunner,
@IOpenerService private openerService: IOpenerService,
@IInstantiationService private instantiationService: IInstantiationService,
@IThemeService private themeService: IThemeService,
@IKeybindingService private keybindingService: IKeybindingService
) {
this.inputDisposeables = [];
if (!NotificationTemplateRenderer.closeNotificationAction) {
NotificationTemplateRenderer.closeNotificationAction = instantiationService.createInstance(ClearNotificationAction, ClearNotificationAction.ID, ClearNotificationAction.LABEL);
NotificationTemplateRenderer.expandNotificationAction = instantiationService.createInstance(ExpandNotificationAction, ExpandNotificationAction.ID, ExpandNotificationAction.LABEL);
NotificationTemplateRenderer.collapseNotificationAction = instantiationService.createInstance(CollapseNotificationAction, CollapseNotificationAction.ID, CollapseNotificationAction.LABEL);
} }
} }
public renderElement(notification: INotificationViewItem, index: number, data: INotificationTemplateData): void { public setInput(notification: INotificationViewItem): void {
this.inputDisposeables = dispose(this.inputDisposeables);
this.render(notification);
}
private render(notification: INotificationViewItem): void {
// Container // Container
toggleClass(data.container, 'expanded', notification.expanded); toggleClass(this.template.container, 'expanded', notification.expanded);
// Icon // Icon
NotificationRenderer.SEVERITIES.forEach(severity => { NotificationTemplateRenderer.SEVERITIES.forEach(severity => {
const domAction = notification.severity === this.toSeverity(severity) ? addClass : removeClass; const domAction = notification.severity === this.toSeverity(severity) ? addClass : removeClass;
domAction(data.icon, `icon-${severity}`); domAction(this.template.icon, `icon-${severity}`);
}); });
// Message (simple markdown with links support) // Message (simple markdown with links support)
clearNode(data.message); clearNode(this.template.message);
data.message.appendChild(NotificationMessageMarkdownRenderer.render(notification.message, (content: string) => this.openerService.open(URI.parse(content)).then(void 0, onUnexpectedError))); this.template.message.appendChild(NotificationMessageMarkdownRenderer.render(notification.message, (content: string) => this.openerService.open(URI.parse(content)).then(void 0, onUnexpectedError)));
const messageOverflows = notification.canCollapse && !notification.expanded && data.message.scrollWidth > data.message.clientWidth; const messageOverflows = notification.canCollapse && !notification.expanded && this.template.message.scrollWidth > this.template.message.clientWidth;
if (messageOverflows) { if (messageOverflows) {
data.message.title = data.message.textContent; this.template.message.title = this.template.message.textContent;
} else { } else {
data.message.removeAttribute('title'); this.template.message.removeAttribute('title');
} }
const links = data.message.querySelectorAll('a'); const links = this.template.message.querySelectorAll('a');
for (let i = 0; i < links.length; i++) { for (let i = 0; i < links.length; i++) {
links.item(i).tabIndex = -1; // prevent keyboard navigation to links to allow for better keyboard support within a message links.item(i).tabIndex = -1; // prevent keyboard navigation to links to allow for better keyboard support within a message
} }
...@@ -291,7 +319,7 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN ...@@ -291,7 +319,7 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN
if (notification.actions.secondary.length > 0) { if (notification.actions.secondary.length > 0) {
const configureNotificationAction = this.instantiationService.createInstance(ConfigureNotificationAction, ConfigureNotificationAction.ID, ConfigureNotificationAction.LABEL, notification.actions.secondary); const configureNotificationAction = this.instantiationService.createInstance(ConfigureNotificationAction, ConfigureNotificationAction.ID, ConfigureNotificationAction.LABEL, notification.actions.secondary);
actions.push(configureNotificationAction); actions.push(configureNotificationAction);
data.toDispose.push(configureNotificationAction); this.inputDisposeables.push(configureNotificationAction);
} }
let showExpandCollapseAction = false; let showExpandCollapseAction = false;
...@@ -306,27 +334,74 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN ...@@ -306,27 +334,74 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN
} }
if (showExpandCollapseAction) { if (showExpandCollapseAction) {
actions.push(notification.expanded ? this.collapseNotificationAction : this.expandNotificationAction); actions.push(notification.expanded ? NotificationTemplateRenderer.collapseNotificationAction : NotificationTemplateRenderer.expandNotificationAction);
} }
actions.push(this.closeNotificationAction); actions.push(NotificationTemplateRenderer.closeNotificationAction);
// Toolbar // Toolbar
data.toolbar.clear(); this.template.toolbar.clear();
data.toolbar.context = notification; this.template.toolbar.context = notification;
actions.forEach(action => data.toolbar.push(action, { icon: true, label: false, keybinding: this.getKeybindingLabel(action) })); actions.forEach(action => this.template.toolbar.push(action, { icon: true, label: false, keybinding: this.getKeybindingLabel(action) }));
// Source // Source
if (notification.expanded && notification.source) { if (notification.expanded && notification.source) {
data.source.innerText = localize('notificationSource', "Source: {0}", notification.source); this.template.source.innerText = localize('notificationSource', "Source: {0}", notification.source);
} else { } else {
data.source.innerText = ''; this.template.source.innerText = '';
} }
// Actions // Actions
clearNode(data.actionsContainer); clearNode(this.template.actionsContainer);
if (notification.expanded) { if (notification.expanded) {
notification.actions.primary.forEach(action => this.createButton(notification, action, data)); notification.actions.primary.forEach(action => this.createButton(notification, action));
}
// Progress
this.renderProgress(notification);
this.inputDisposeables.push(notification.progress.onDidChange(() => this.renderProgress(notification)));
}
private renderProgress(notification: INotificationViewItem): void {
// Return early if the item has no progress
if (!notification.hasProgress()) {
this.template.progress.done().getContainer().hide();
return;
}
// Infinite
const state = notification.progress.state;
if (state.infinite) {
this.template.progress.infinite().getContainer().show();
}
// Total / Worked
else if (state.total || state.worked) {
if (state.total) {
this.template.progress.total(state.total);
}
if (state.worked) {
this.template.progress.worked(state.worked).getContainer().show();
}
}
// Done
else {
this.template.progress.done().getContainer().hide();
}
}
private toSeverity(severity: 'info' | 'warning' | 'error'): Severity {
switch (severity) {
case 'info':
return Severity.Info;
case 'warning':
return Severity.Warning;
case 'error':
return Severity.Error;
} }
} }
...@@ -336,29 +411,25 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN ...@@ -336,29 +411,25 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN
return keybinding ? keybinding.getLabel() : void 0; return keybinding ? keybinding.getLabel() : void 0;
} }
private createButton(notification: INotificationViewItem, action: IAction, data: INotificationTemplateData): Button { private createButton(notification: INotificationViewItem, action: IAction): Button {
const button = new Button(data.actionsContainer); const button = new Button(this.template.actionsContainer);
data.toDispose.push(attachButtonStyler(button, this.themeService));
button.label = action.label; button.label = action.label;
button.onDidClick(() => { this.inputDisposeables.push(button.onDidClick(() => {
// Run action // Run action
this.actionRunner.run(action); this.actionRunner.run(action);
// Hide notification // Hide notification
notification.dispose(); notification.dispose();
}); }));
return button; this.inputDisposeables.push(attachButtonStyler(button, this.themeService));
} this.inputDisposeables.push(button);
public disposeTemplate(templateData: INotificationTemplateData): void { return button;
templateData.toolbar.dispose();
templateData.toDispose = dispose(templateData.toDispose);
} }
public dispose(): void { public dispose(): void {
this.toDispose = dispose(this.toDispose); this.inputDisposeables = dispose(this.inputDisposeables);
} }
} }
\ No newline at end of file
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import { Severity } from 'vs/platform/message/common/message'; import { Severity } from 'vs/platform/message/common/message';
import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IMarkdownString } from 'vs/base/common/htmlContent';
import { INotification, INotificationHandle, INotificationActions } from 'vs/platform/notification/common/notification'; import { INotification, INotificationHandle, INotificationActions, INotificationProgress } from 'vs/platform/notification/common/notification';
import { toErrorMessage } from 'vs/base/common/errorMessage'; import { toErrorMessage } from 'vs/base/common/errorMessage';
import Event, { Emitter, once } from 'vs/base/common/event'; import Event, { Emitter, once } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle';
...@@ -34,9 +34,21 @@ export interface INotificationChangeEvent { ...@@ -34,9 +34,21 @@ export interface INotificationChangeEvent {
} }
class NoOpNotification implements INotificationHandle { class NoOpNotification implements INotificationHandle {
public readonly progress = new NoOpProgress();
public dispose(): void { } public dispose(): void { }
} }
class NoOpProgress implements INotificationProgress {
public infinite(): void { }
public done(): void { }
public total(value: number): void { }
public worked(value: number): void { }
}
export class NotificationsModel implements INotificationsModel { export class NotificationsModel implements INotificationsModel {
private static NO_OP_NOTIFICATION = new NoOpNotification(); private static NO_OP_NOTIFICATION = new NoOpNotification();
...@@ -64,8 +76,8 @@ export class NotificationsModel implements INotificationsModel { ...@@ -64,8 +76,8 @@ export class NotificationsModel implements INotificationsModel {
public notify(notification: INotification): INotificationHandle { public notify(notification: INotification): INotificationHandle {
const item = this.createViewItem(notification); const item = this.createViewItem(notification);
if (item instanceof NoOpNotification) { if (!item) {
return item; // return early if this is a no-op return NotificationsModel.NO_OP_NOTIFICATION; // return early if this is a no-op
} }
// Deduplicate // Deduplicate
...@@ -80,9 +92,15 @@ export class NotificationsModel implements INotificationsModel { ...@@ -80,9 +92,15 @@ export class NotificationsModel implements INotificationsModel {
// Events // Events
this._onDidNotificationChange.fire({ item, index: 0, kind: NotificationChangeType.ADD }); this._onDidNotificationChange.fire({ item, index: 0, kind: NotificationChangeType.ADD });
// Wrap into handles // Wrap into handle
return { return {
dispose: () => this.disposeItem(item) dispose: () => this.disposeItem(item),
progress: {
infinite: () => item.progress.infinite(),
total: value => item.progress.total(value),
worked: value => item.progress.worked(value),
done: () => item.progress.done()
}
}; };
} }
...@@ -106,10 +124,10 @@ export class NotificationsModel implements INotificationsModel { ...@@ -106,10 +124,10 @@ export class NotificationsModel implements INotificationsModel {
return void 0; return void 0;
} }
private createViewItem(notification: INotification): INotificationViewItem | NoOpNotification { private createViewItem(notification: INotification): INotificationViewItem {
const item = NotificationViewItem.create(notification); const item = NotificationViewItem.create(notification);
if (!item) { if (!item) {
return NotificationsModel.NO_OP_NOTIFICATION; return null;
} }
// Item Events // Item Events
...@@ -143,6 +161,7 @@ export interface INotificationViewItem { ...@@ -143,6 +161,7 @@ export interface INotificationViewItem {
readonly message: IMarkdownString; readonly message: IMarkdownString;
readonly source: string; readonly source: string;
readonly actions: INotificationActions; readonly actions: INotificationActions;
readonly progress: INotificationViewItemProgress;
readonly expanded: boolean; readonly expanded: boolean;
readonly canCollapse: boolean; readonly canCollapse: boolean;
...@@ -154,6 +173,8 @@ export interface INotificationViewItem { ...@@ -154,6 +173,8 @@ export interface INotificationViewItem {
collapse(): void; collapse(): void;
toggle(): void; toggle(): void;
hasProgress(): boolean;
dispose(): void; dispose(): void;
equals(item: INotificationViewItem); equals(item: INotificationViewItem);
...@@ -163,6 +184,101 @@ export function isNotificationViewItem(obj: any): obj is INotificationViewItem { ...@@ -163,6 +184,101 @@ export function isNotificationViewItem(obj: any): obj is INotificationViewItem {
return obj instanceof NotificationViewItem; return obj instanceof NotificationViewItem;
} }
export interface INotificationViewItemProgressState {
infinite?: boolean;
total?: number;
worked?: number;
done?: boolean;
}
export interface INotificationViewItemProgress extends INotificationProgress {
readonly state: INotificationViewItemProgressState;
readonly onDidChange: Event<void>;
dispose(): void;
}
export class NotificationViewItemProgress implements INotificationViewItemProgress {
private _state: INotificationViewItemProgressState;
private _onDidChange: Emitter<void>;
private toDispose: IDisposable[];
constructor() {
this.toDispose = [];
this._state = Object.create(null);
this._onDidChange = new Emitter<void>();
this.toDispose.push(this._onDidChange);
}
public get state(): INotificationViewItemProgressState {
return this._state;
}
public get onDidChange(): Event<void> {
return this._onDidChange.event;
}
public infinite(): void {
if (this._state.infinite) {
return;
}
this._state.infinite = true;
this._state.total = void 0;
this._state.worked = void 0;
this._state.done = void 0;
this._onDidChange.fire();
}
public done(): void {
if (this._state.done) {
return;
}
this._state.done = true;
this._state.infinite = void 0;
this._state.total = void 0;
this._state.worked = void 0;
this._onDidChange.fire();
}
public total(value: number): void {
if (this._state.total === value) {
return;
}
this._state.total = value;
this._state.infinite = void 0;
this._state.done = void 0;
this._onDidChange.fire();
}
public worked(value: number): void {
if (this._state.worked === value) {
return;
}
this._state.worked = value;
this._state.infinite = void 0;
this._state.done = void 0;
this._onDidChange.fire();
}
public dispose(): void {
this.toDispose = dispose(this.toDispose);
}
}
export class NotificationViewItem implements INotificationViewItem { export class NotificationViewItem implements INotificationViewItem {
private static MAX_MESSAGE_LENGTH = 1000; private static MAX_MESSAGE_LENGTH = 1000;
...@@ -173,6 +289,8 @@ export class NotificationViewItem implements INotificationViewItem { ...@@ -173,6 +289,8 @@ export class NotificationViewItem implements INotificationViewItem {
private _onDidChange: Emitter<void>; private _onDidChange: Emitter<void>;
private _onDidDispose: Emitter<void>; private _onDidDispose: Emitter<void>;
private _progress: INotificationViewItemProgress;
public static create(notification: INotification): INotificationViewItem { public static create(notification: INotification): INotificationViewItem {
if (!notification || !notification.message || isPromiseCanceledError(notification.message)) { if (!notification || !notification.message || isPromiseCanceledError(notification.message)) {
return null; // we need a message to show return null; // we need a message to show
...@@ -247,6 +365,19 @@ export class NotificationViewItem implements INotificationViewItem { ...@@ -247,6 +365,19 @@ export class NotificationViewItem implements INotificationViewItem {
return this._severity; return this._severity;
} }
public hasProgress(): boolean {
return !!this._progress;
}
public get progress(): INotificationViewItemProgress {
if (!this._progress) {
this._progress = new NotificationViewItemProgress();
this.toDispose.push(this._progress);
}
return this._progress;
}
public get message(): IMarkdownString { public get message(): IMarkdownString {
return this._message; return this._message;
} }
......
...@@ -42,7 +42,7 @@ export class NotificationService implements INotificationService { ...@@ -42,7 +42,7 @@ export class NotificationService implements INotificationService {
message: 'This is a info message with a [link](https://code.visualstudio.com). This is a info message with a [link](https://code.visualstudio.com). This is a info message with a [link](https://code.visualstudio.com). This is a info message with a [link](https://code.visualstudio.com).', message: 'This is a info message with a [link](https://code.visualstudio.com). This is a info message with a [link](https://code.visualstudio.com). This is a info message with a [link](https://code.visualstudio.com). This is a info message with a [link](https://code.visualstudio.com).',
source: 'GitLens Extension' source: 'GitLens Extension'
}); });
this.notify({ let handle = this.notify({
severity: Severity.Warning, severity: Severity.Warning,
message: 'This is a warning message with a [link](https://code.visualstudio.com).', message: 'This is a warning message with a [link](https://code.visualstudio.com).',
actions: { actions: {
...@@ -56,10 +56,36 @@ export class NotificationService implements INotificationService { ...@@ -56,10 +56,36 @@ export class NotificationService implements INotificationService {
] ]
} }
}); });
this.notify({ handle.progress.total(100);
setTimeout(() => {
handle.progress.worked(20);
setTimeout(() => {
handle.progress.worked(40);
setTimeout(() => {
handle.progress.worked(60);
setTimeout(() => {
handle.progress.worked(80);
setTimeout(() => {
handle.progress.worked(100);
setTimeout(() => {
handle.progress.done();
}, 3000);
}, 3000);
}, 3000);
}, 3000);
}, 3000);
}, 1000);
let handle2 = this.notify({
severity: Severity.Error, severity: Severity.Error,
message: 'This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com).This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com).' message: 'This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com).This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com). This is a error message with a [link](https://code.visualstudio.com).'
}); });
setTimeout(() => {
handle2.progress.infinite();
setTimeout(() => {
handle2.progress.done();
}, 1500);
}, 500);
}, 500); }, 500);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册