src/vs/workbench/common/notifications.ts

818 LOC · 688 covered · 130 uncovered · 125 ranges · 6 concepts · 6 introducers · 3 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/base/common/actions.ts · 294 LOCcommon/actions.tssrc/vs/base/common/errorMessage.ts · 113 LOCcommon/errorMessage.tssrc/vs/base/common/linkedText.ts · 55 LOCcommon/linkedText.tssrc/vs/platform/notification/common/notification.ts · 491 LOCcommon/notification.tsnotifications.ts ×23 · 137 introduced LOCnotifications.ts ×23notifications.ts ×17 · 59 introduced LOCnotifications.ts ×17notifications.ts ×25 · 82 introduced LOCnotifications.ts ×25notifications.ts ×1 · 2 introduced LOCnotifications.ts ×1notifications.ts ×1 · 2 introduced LOCnotifications.ts ×1notifications.ts ×58 · 436 introduced LOCnotifications.ts ×58notifications.test|title=Notifications Items - does not fire changed when message did not change (content, severity)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/test/common/notifications.test|title=Notifications Items - does not fire changed when message did not change (content, severity)|occurrence=1notifications.test|title…notifications.test|title=Notifications Items|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/test/common/notifications.test|title=Notifications Items|occurrence=1notifications.test|title…notifications.test|title=Notifications Model|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/test/common/notifications.test|title=Notifications Model|occurrence=1notifications.test|title…Focused file · src/vs/workbench/common/notifications.ts · 818 LOCcommon/notifications.ts

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- notifications.ts ×58
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice, IStatusMessageOptions, NotificationsFilter, INotificationProgressProperties, IPromptChoiceWithMenu, NotificationPriority, INotificationSource, isNotificationSource, IStatusHandle } from '../../platform/notification/common/notification.js';
7 > import { toErrorMessage, isErrorWithActions } from '../../base/common/errorMessage.js';
8 > import { Event, Emitter } from '../../base/common/event.js';
9 > import { Disposable } from '../../base/common/lifecycle.js';
10 > import { isCancellationError } from '../../base/common/errors.js';
11 > import { Action } from '../../base/common/actions.js';
12 > import { equals } from '../../base/common/arrays.js';
13 > import { parseLinkedText, LinkedText } from '../../base/common/linkedText.js';
14 > import { mapsStrictEqualIgnoreOrder } from '../../base/common/map.js';
15 > import { IConfigurationService } from '../../platform/configuration/common/configuration.js';
16 >
17 > export interface INotificationsModel {
18 >
19 > //#region Notifications as Toasts/Center
20 >
21 > readonly notifications: INotificationViewItem[];
22 >
23 > readonly onDidChangeNotification: Event<INotificationChangeEvent>;
24 > readonly onDidChangeFilter: Event<Partial<INotificationsFilter>>;
25 >
26 > addNotification(notification: INotification): INotificationHandle;
27 >
28 > setFilter(filter: Partial<INotificationsFilter>): void;
29 >
30 > //#endregion
31 >
32 >
33 > //#region Notifications as Status
34 >
35 > readonly statusMessage: IStatusMessageViewItem | undefined;
36 >
37 > readonly onDidChangeStatusMessage: Event<IStatusMessageChangeEvent>;
38 >
39 > showStatusMessage(message: NotificationMessage, options?: IStatusMessageOptions): IStatusHandle;
40 >
41 > //#endregion
42 > }
43 >
44 > export const enum NotificationChangeType {
45 >
46 > /**
47 > * A notification was added.
48 > */
49 > ADD,
50 >
51 > /**
52 > * A notification changed. Check `detail` property
53 > * on the event for additional information.
54 > */
55 > CHANGE,
56 >
57 > /**
58 > * A notification expanded or collapsed.
59 > */
60 > EXPAND_COLLAPSE,
61 >
62 > /**
63 > * A notification was removed.
64 > */
65 > REMOVE
66 > }
67 >
68 > export interface INotificationChangeEvent {
69 >
70 > /**
71 > * The index this notification has in the list of notifications.
72 > */
73 > index: number;
74 >
75 > /**
76 > * The notification this change is about.
77 > */
78 > item: INotificationViewItem;
79 >
80 > /**
81 > * The kind of notification change.
82 > */
83 > kind: NotificationChangeType;
84 >
85 > /**
86 > * Additional detail about the item change. Only applies to
87 > * `NotificationChangeType.CHANGE`.
88 > */
89 > detail?: NotificationViewItemContentChangeKind;
90 > }
91 >
92 > export const enum StatusMessageChangeType {
93 > ADD,
94 > REMOVE
95 > }
96 >
97 > export interface IStatusMessageViewItem {
98 > message: string;
99 > options?: IStatusMessageOptions;
100 > }
101 >
102 > export interface IStatusMessageChangeEvent {
103 >
104 > /**
105 > * The status message item this change is about.
106 > */
107 > item: IStatusMessageViewItem;
108 >
109 > /**
110 > * The kind of status message change.
111 > */
112 > kind: StatusMessageChangeType;
113 > }
114 >
115 > export class NotificationHandle extends Disposable implements INotificationHandle {
116 >
117 > private readonly _onDidClose = this._register(new Emitter<void>());
118 > readonly onDidClose = this._onDidClose.event;
119 >
120 > private readonly _onDidChangeVisibility = this._register(new Emitter<boolean>());
121 > readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
122 >
123 > constructor(private readonly item: INotificationViewItem, private readonly onClose: (item: INotificationViewItem) => void) {
124 > super(); notifications.ts ×23
125 >
126 > this.registerListeners();
127 > }
129 > private registerListeners(): void {
131 > // Visibility
132 > this._register(this.item.onDidChangeVisibility(visible => this._onDidChangeVisibility.fire(visible)));
133 >
134 > // Closing
135 > Event.once(this.item.onDidClose)(() => {
136 > this._onDidClose.fire();
137 >
138 > this.dispose();
139 > });
140 > }
142 > get progress(): INotificationProgress {
143 > return this.item.progress; notifications.ts ×23
144 > }
146 > updateSeverity(severity: Severity): void {
147 > this.item.updateSeverity(severity); notifications.ts ×23
148 > }
150 > updateMessage(message: NotificationMessage): void {
151 > this.item.updateMessage(message); notifications.ts ×23
152 > }
154 > updateActions(actions?: INotificationActions): void {
155 > this.item.updateActions(actions); notifications.ts ×23
156 > }
158 > close(): void {
159 > this.onClose(this.item); notifications.ts ×23
160 >
161 > this.dispose();
162 > }
164 >
165 > export interface INotificationsFilter {
166 > readonly global: NotificationsFilter;
167 > readonly sources: Map<string, NotificationsFilter>;
168 > }
169 >
170 > export class NotificationsModel extends Disposable implements INotificationsModel {
172 > private static readonly NO_OP_NOTIFICATION = new NoOpNotification();
173 >
174 > private readonly _onDidChangeNotification = this._register(new Emitter<INotificationChangeEvent>());
175 > readonly onDidChangeNotification = this._onDidChangeNotification.event;
176 >
177 > private readonly _onDidChangeStatusMessage = this._register(new Emitter<IStatusMessageChangeEvent>());
178 > readonly onDidChangeStatusMessage = this._onDidChangeStatusMessage.event;
179 >
180 > private readonly _onDidChangeFilter = this._register(new Emitter<Partial<INotificationsFilter>>());
181 > readonly onDidChangeFilter = this._onDidChangeFilter.event;
182 >
183 > private readonly _notifications: INotificationViewItem[] = [];
184 > get notifications(): INotificationViewItem[] { return this._notifications; }
185 >
186 > private _statusMessage: IStatusMessageViewItem | undefined;
187 > get statusMessage(): IStatusMessageViewItem | undefined { return this._statusMessage; }
188 >
189 > private readonly filter = {
190 > global: NotificationsFilter.OFF,
191 > sources: new Map<string, NotificationsFilter>()
192 > };
194 > setFilter(filter: Partial<INotificationsFilter>): void {
195 let globalChanged = false;
196 if (typeof filter.global === 'number') {
197 globalChanged = this.filter.global !== filter.global;
198 this.filter.global = filter.global;
199 }
200
201 let sourcesChanged = false;
202 if (filter.sources) {
203 sourcesChanged = !mapsStrictEqualIgnoreOrder(this.filter.sources, filter.sources);
204 this.filter.sources = filter.sources;
205 }
206
207 if (globalChanged || sourcesChanged) {
208 this._onDidChangeFilter.fire({
209 global: globalChanged ? filter.global : undefined,
210 sources: sourcesChanged ? filter.sources : undefined
211 });
212 }
213 }
215 > addNotification(notification: INotification): INotificationHandle {
216 > const item = this.createViewItem(notification); notifications.ts ×23
217 > if (!item) {
218 return NotificationsModel.NO_OP_NOTIFICATION; // return early if this is a no-op
219 }
221 > // Deduplicate
222 > const duplicate = this.findNotification(item);
223 > duplicate?.close();
224 >
225 > // Add to list as first entry
226 > this._notifications.splice(0, 0, item);
227 >
228 > // Events
229 > this._onDidChangeNotification.fire({ item, index: 0, kind: NotificationChangeType.ADD });
230 >
231 > // Wrap into handle
232 > return new NotificationHandle(item, item => this.onClose(item));
233 > }
235 > private onClose(item: INotificationViewItem): void {
236 > const liveItem = this.findNotification(item); notifications.ts ×23
237 > if (liveItem && liveItem !== item) {
238 > liveItem.close(); // item could have been replaced with another one, make sure to close the live item
239 > } else {
240 > item.close(); // otherwise just close the item that was passed in
241 > }
242 > }
244 > private findNotification(item: INotificationViewItem): INotificationViewItem | undefined {
245 > return this._notifications.find(notification => notification.equals(item)); notifications.ts ×23
246 > }
248 > private createViewItem(notification: INotification): INotificationViewItem | undefined {
249 > const item = NotificationViewItem.create(notification, this.filter); notifications.ts ×23
250 > if (!item) {
251 return undefined;
252 }
254 > // Item Events
255 > const fireNotificationChangeEvent = (kind: NotificationChangeType, detail?: NotificationViewItemContentChangeKind) => {
256 > const index = this._notifications.indexOf(item);
257 > if (index >= 0) {
258 > this._onDidChangeNotification.fire({ item, index, kind, detail });
259 > }
260 > };
261 >
262 > const itemExpansionChangeListener = item.onDidChangeExpansion(() => fireNotificationChangeEvent(NotificationChangeType.EXPAND_COLLAPSE));
263 > const itemContentChangeListener = item.onDidChangeContent(e => fireNotificationChangeEvent(NotificationChangeType.CHANGE, e.kind));
264 >
265 > Event.once(item.onDidClose)(() => {
266 > itemExpansionChangeListener.dispose();
267 > itemContentChangeListener.dispose();
268 >
269 > const index = this._notifications.indexOf(item);
270 > if (index >= 0) {
271 > this._notifications.splice(index, 1);
272 > this._onDidChangeNotification.fire({ item, index, kind: NotificationChangeType.REMOVE });
273 > }
274 > });
275 >
276 > return item;
277 > }
279 > showStatusMessage(message: NotificationMessage, options?: IStatusMessageOptions): IStatusHandle {
280 > const item = StatusMessageViewItem.create(message, options); notifications.ts ×23
281 > if (!item) {
282 return { close: () => { } };
283 }
285 > this._statusMessage = item;
286 > this._onDidChangeStatusMessage.fire({ kind: StatusMessageChangeType.ADD, item });
287 >
288 > return {
289 > close: () => {
290 > if (this._statusMessage === item) {
291 > this._statusMessage = undefined;
292 > this._onDidChangeStatusMessage.fire({ kind: StatusMessageChangeType.REMOVE, item });
293 > }
294 > }
295 > };
296 > }
298 >
299 > export interface INotificationViewItem {
300 > readonly id: string | undefined;
301 > readonly severity: Severity;
302 > readonly sticky: boolean;
303 > readonly priority: NotificationPriority;
304 > readonly message: INotificationMessage;
305 > readonly source: string | undefined;
306 > readonly sourceId: string | undefined;
307 > readonly actions: INotificationActions | undefined;
308 > readonly progress: INotificationViewItemProgress;
309 >
310 > readonly expanded: boolean;
311 > readonly visible: boolean;
312 > readonly canCollapse: boolean;
313 > readonly hasProgress: boolean;
314 >
315 > readonly onDidChangeExpansion: Event<void>;
316 > readonly onDidChangeVisibility: Event<boolean>;
317 > readonly onDidChangeContent: Event<INotificationViewItemContentChangeEvent>;
318 > readonly onDidClose: Event<void>;
319 >
320 > expand(): void;
321 > collapse(skipEvents?: boolean): void;
322 > toggle(): void;
323 >
324 > updateSeverity(severity: Severity): void;
325 > updateMessage(message: NotificationMessage): void;
326 > updateActions(actions?: INotificationActions): void;
327 >
328 > updateVisibility(visible: boolean): void;
329 >
330 > close(): void;
331 >
332 > equals(item: INotificationViewItem): boolean;
333 > }
334 >
335 > export function isNotificationViewItem(obj: unknown): obj is INotificationViewItem {
336 return obj instanceof NotificationViewItem;
337 }
339 > export const enum NotificationViewItemContentChangeKind {
340 > SEVERITY,
341 > MESSAGE,
342 > ACTIONS,
343 > PROGRESS
344 > }
345 >
346 > export interface INotificationViewItemContentChangeEvent {
347 > kind: NotificationViewItemContentChangeKind;
348 > }
349 >
350 > export interface INotificationViewItemProgressState {
351 > infinite?: boolean;
352 > total?: number;
353 > worked?: number;
354 > done?: boolean;
355 > }
356 >
357 > export interface INotificationViewItemProgress extends INotificationProgress {
358 > readonly state: INotificationViewItemProgressState;
359 >
360 > dispose(): void;
361 > }
362 >
363 > export class NotificationViewItemProgress extends Disposable implements INotificationViewItemProgress {
364 > private readonly _state: INotificationViewItemProgressState;
365 >
366 > private readonly _onDidChange = this._register(new Emitter<void>());
367 > readonly onDidChange = this._onDidChange.event;
368 >
369 > constructor() {
370 > super(); notifications.ts ×25
371 >
372 > this._state = Object.create(null);
373 > }
375 > get state(): INotificationViewItemProgressState {
376 return this._state;
377 }
379 > infinite(): void {
380 > if (this._state.infinite) { notifications.ts ×25
381 return;
382 }
384 > this._state.infinite = true;
385 >
386 > this._state.total = undefined;
387 > this._state.worked = undefined;
388 > this._state.done = undefined;
389 >
390 > this._onDidChange.fire();
391 > }
393 > done(): void {
394 > if (this._state.done) { notifications.ts ×17
395 return;
396 }
398 > this._state.done = true;
399 >
400 > this._state.infinite = undefined;
401 > this._state.total = undefined;
402 > this._state.worked = undefined;
403 >
404 > this._onDidChange.fire();
405 > }
407 > total(value: number): void {
408 if (this._state.total === value) {
409 return;
410 }
411
412 this._state.total = value;
413
414 this._state.infinite = undefined;
415 this._state.done = undefined;
416
417 this._onDidChange.fire();
418 }
420 > worked(value: number): void {
421 if (typeof this._state.worked === 'number') {
422 this._state.worked += value;
423 } else {
424 this._state.worked = value;
425 }
426
427 this._state.infinite = undefined;
428 this._state.done = undefined;
429
430 this._onDidChange.fire();
431 }
433 >
434 > export interface IMessageLink {
435 > href: string;
436 > name: string;
437 > title: string;
438 > offset: number;
439 > length: number;
440 > }
441 >
442 > export interface INotificationMessage {
443 > raw: string;
444 > original: NotificationMessage;
445 > linkedText: LinkedText;
446 > }
447 >
448 > export class NotificationViewItem extends Disposable implements INotificationViewItem {
449 >
450 > private static readonly MAX_MESSAGE_LENGTH = 1000;
451 >
452 > private _expanded: boolean | undefined;
453 > private _visible: boolean = false;
454 >
455 > private _actions: INotificationActions | undefined;
456 > private _progress: NotificationViewItemProgress | undefined;
457 >
458 > private readonly _onDidChangeExpansion = this._register(new Emitter<void>());
459 > readonly onDidChangeExpansion = this._onDidChangeExpansion.event;
460 >
461 > private readonly _onDidClose = this._register(new Emitter<void>());
462 > readonly onDidClose = this._onDidClose.event;
463 >
464 > private readonly _onDidChangeContent = this._register(new Emitter<INotificationViewItemContentChangeEvent>());
465 > readonly onDidChangeContent = this._onDidChangeContent.event;
466 >
467 > private readonly _onDidChangeVisibility = this._register(new Emitter<boolean>());
468 > readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
469 >
470 > static create(notification: INotification, filter: INotificationsFilter): INotificationViewItem | undefined {
471 > if (!notification?.message || isCancellationError(notification.message)) {
472 > return undefined; // we need a message to show notifications.ts ×17
473 > }
475 > let severity: Severity;
476 > if (typeof notification.severity === 'number') {
477 > severity = notification.severity;
478 > } else {
479 severity = Severity.Info;
480 }
482 > const message = NotificationViewItem.parseNotificationMessage(notification.message);
483 > if (!message) {
484 return undefined; // we need a message to show
485 }
487 > let actions: INotificationActions | undefined;
488 > if (notification.actions) {
489 > actions = notification.actions; notifications.ts ×25
490 > } else if (isErrorWithActions(notification.message)) { notifications.ts ×58
491 > actions = { primary: notification.message.actions }; notifications.ts ×17
492 > }
494 > let priority = notification.priority ?? NotificationPriority.DEFAULT;
495 > if ((priority === NotificationPriority.DEFAULT || priority === NotificationPriority.OPTIONAL) && severity !== Severity.Error) {
496 > if (filter.global === NotificationsFilter.ERROR) { notifications.ts ×25
497 > priority = NotificationPriority.SILENT; // filtered globally notifications.ts ×17
498 > } else if (isNotificationSource(notification.source) && filter.sources.get(notification.source.id) === NotificationsFilter.ERROR) { notifications.ts ×25
499 > priority = NotificationPriority.SILENT; // filtered by source notifications.ts ×17
500 > }
503 > return new NotificationViewItem(notification.id, severity, notification.sticky, priority, message, notification.source, notification.progress, actions);
504 > }
505 >
506 > private static parseNotificationMessage(input: NotificationMessage): INotificationMessage | undefined {
507 > let message: string | undefined;
508 > if (input instanceof Error) {
509 > message = toErrorMessage(input, false); notifications.ts ×17
510 > } else if (typeof input === 'string') { notifications.ts ×58
511 > message = input;
512 > }
513 >
514 > if (!message) {
515 return undefined; // we need a message to show
516 }
518 > const raw = message;
519 >
520 > // Make sure message is in the limits
521 > if (message.length > NotificationViewItem.MAX_MESSAGE_LENGTH) {
522 message = `${message.substr(0, NotificationViewItem.MAX_MESSAGE_LENGTH)}...`;
523 }
525 > // Remove newlines from messages as we do not support that and it makes link parsing hard
526 > message = message.replace(/(\r\n|\n|\r)/gm, ' ').trim();
527 >
528 > // Parse Links
529 > const linkedText = parseLinkedText(message);
530 >
531 > return { raw, linkedText, original: input };
532 > }
533 >
534 > private constructor(
535 > readonly id: string | undefined,
536 > private _severity: Severity,
537 > private _sticky: boolean | undefined,
538 > private _priority: NotificationPriority,
539 > private _message: INotificationMessage,
540 > private _source: string | INotificationSource | undefined,
541 > progress: INotificationProgressProperties | undefined,
542 > actions?: INotificationActions
543 > ) {
544 > super();
545 >
546 > if (progress) {
547 > this.setProgress(progress); notifications.ts ×17
548 > }
550 > this.setActions(actions);
551 > }
552 >
553 > private setProgress(progress: INotificationProgressProperties): void {
554 > if (progress.infinite) { notifications.ts ×17
555 > this.progress.infinite();
556 > } else if (progress.total) {
557 this.progress.total(progress.total);
558
559 if (progress.worked) {
560 this.progress.worked(progress.worked);
561 }
562 }
565 > private setActions(actions: INotificationActions = { primary: [], secondary: [] }): void {
566 > this._actions = {
567 > primary: Array.isArray(actions.primary) ? actions.primary : [],
568 > secondary: Array.isArray(actions.secondary) ? actions.secondary : []
569 > };
570 >
571 > this._expanded = actions.primary && actions.primary.length > 0;
572 > }
573 >
574 > get canCollapse(): boolean {
575 > return !this.hasActions; notifications.ts ×25
576 > }
578 > get expanded(): boolean {
579 > return !!this._expanded; notifications.ts ×17
580 > }
582 > get severity(): Severity {
583 > return this._severity; notifications.ts ×23
584 > }
586 > get sticky(): boolean {
587 if (this._sticky) {
588 return true; // explicitly sticky
589 }
590
591 const hasActions = this.hasActions;
592 if (
593 (hasActions && this._severity === Severity.Error) || // notification errors with actions are sticky
594 (!hasActions && this._expanded) || // notifications that got expanded are sticky
595 (this._progress && !this._progress.state.done) // notifications with running progress are sticky
596 ) {
597 return true;
598 }
599
600 return false; // not sticky
601 }
603 > get priority(): NotificationPriority {
604 > return this._priority; notifications.ts ×17
605 > }
607 > private get hasActions(): boolean {
608 > if (!this._actions) { notifications.ts ×25
609 return false;
610 }
612 > if (!this._actions.primary) {
613 return false;
614 }
616 > return this._actions.primary.length > 0;
617 > }
619 > get hasProgress(): boolean {
620 > return !!this._progress; notifications.ts ×25
621 > }
623 > get progress(): INotificationViewItemProgress {
624 > if (!this._progress) { notifications.ts ×25
625 > this._progress = this._register(new NotificationViewItemProgress());
626 > this._register(this._progress.onDidChange(() => this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.PROGRESS })));
627 > }
628 >
629 > return this._progress;
630 > }
632 > get message(): INotificationMessage {
633 > return this._message; notifications.ts ×25
634 > }
636 > get source(): string | undefined {
637 > return typeof this._source === 'string' ? this._source : (this._source ? this._source.label : undefined); notifications.ts ×25
638 > }
640 > get sourceId(): string | undefined {
641 return (this._source && typeof this._source !== 'string' && 'id' in this._source) ? this._source.id : undefined;
642 }
644 > get actions(): INotificationActions | undefined {
645 > return this._actions; notifications.ts ×25
646 > }
648 > get visible(): boolean {
649 return this._visible;
650 }
652 > updateSeverity(severity: Severity): void {
653 > if (severity === this._severity) {
654 > return; notifications.ts ×1
655 > }
657 > this._severity = severity;
658 > this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.SEVERITY });
660 >
661 > updateMessage(input: NotificationMessage): void {
662 > const message = NotificationViewItem.parseNotificationMessage(input);
663 > if (!message || message.raw === this._message.raw) {
664 > return; notifications.ts ×1
665 > }
667 > this._message = message;
668 > this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.MESSAGE });
670 >
671 > updateActions(actions?: INotificationActions): void {
672 > this.setActions(actions); notifications.ts ×25
673 > this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.ACTIONS });
674 > }
676 > updateVisibility(visible: boolean): void {
677 > if (this._visible !== visible) { notifications.ts ×17
678 > this._visible = visible;
679 >
680 > this._onDidChangeVisibility.fire(visible);
681 > }
682 > }
684 > expand(): void {
685 > if (this._expanded || !this.canCollapse) { notifications.ts ×25
686 > return; notifications.ts ×17
687 > }
689 > this._expanded = true;
690 > this._onDidChangeExpansion.fire();
691 > }
693 > collapse(skipEvents?: boolean): void {
694 > if (!this._expanded || !this.canCollapse) { notifications.ts ×17
695 > return;
696 > }
697 >
698 > this._expanded = false;
699 >
700 > if (!skipEvents) {
701 > this._onDidChangeExpansion.fire();
702 > }
703 > }
705 > toggle(): void {
706 if (this._expanded) {
707 this.collapse();
708 } else {
709 this.expand();
710 }
711 }
713 > close(): void {
714 > this._onDidClose.fire();
715 >
716 > this.dispose();
717 > }
718 >
719 > equals(other: INotificationViewItem): boolean {
720 > if (this.hasProgress || other.hasProgress) { notifications.ts ×25
721 > return false; notifications.ts ×23
722 > }
724 > if (typeof this.id === 'string' || typeof other.id === 'string') {
725 > return this.id === other.id; notifications.ts ×17
726 > }
728 > if (typeof this._source === 'object') {
729 if (this._source.label !== other.source || this._source.id !== other.sourceId) {
730 return false;
731 }
732 > } else if (this._source !== other.source) { notifications.ts ×25
733 > return false;
734 > }
735 >
736 > if (this._message.raw !== other.message.raw) {
737 > return false; notifications.ts ×17
738 > }
740 > const primaryActions = this._actions?.primary || [];
741 > const otherPrimaryActions = other.actions?.primary || [];
742 > return equals(primaryActions, otherPrimaryActions, (action, otherAction) => (action.id + action.label) === (otherAction.id + otherAction.label));
743 > }
745 >
746 > export class ChoiceAction extends Action {
747 >
748 > private readonly _onDidRun = this._register(new Emitter<void>());
749 > readonly onDidRun = this._onDidRun.event;
750 >
751 > private readonly _keepOpen: boolean;
752 > private readonly _menu: ChoiceAction[] | undefined;
753 >
754 > constructor(id: string, choice: IPromptChoice) {
755 super(id, choice.label, undefined, true, async () => {
756
757 // Pass to runner
758 choice.run();
759
760 // Emit Event
761 this._onDidRun.fire();
762 });
763
764 this._keepOpen = !!choice.keepOpen;
765 this._menu = !choice.isSecondary && (<IPromptChoiceWithMenu>choice).menu ? (<IPromptChoiceWithMenu>choice).menu.map((c, index) => new ChoiceAction(`${id}.${index}`, c)) : undefined;
766 }
768 > get menu(): ChoiceAction[] | undefined {
769 return this._menu;
770 }
772 > get keepOpen(): boolean {
773 return this._keepOpen;
774 }
776 >
777 > class StatusMessageViewItem {
778 >
779 > static create(notification: NotificationMessage, options?: IStatusMessageOptions): IStatusMessageViewItem | undefined {
780 > if (!notification || isCancellationError(notification)) { notifications.ts ×23
781 return undefined; // we need a message to show
782 }
784 > let message: string | undefined;
785 > if (notification instanceof Error) {
786 message = toErrorMessage(notification, false);
787 > } else if (typeof notification === 'string') { notifications.ts ×23
788 > message = notification;
789 > }
790 >
791 > if (!message) {
792 return undefined; // we need a message to show
793 }
795 > return { message, options };
796 > }
798 >
799 > export const enum NotificationsSettings {
800 > NOTIFICATIONS_POSITION = 'workbench.notifications.position',
801 > NOTIFICATIONS_BUTTON = 'workbench.notifications.showInTitleBar'
802 > }
803 >
804 > export const enum NotificationsPosition {
805 > BOTTOM_RIGHT = 'bottom-right',
806 > BOTTOM_LEFT = 'bottom-left',
807 > TOP_RIGHT = 'top-right'
808 > }
809 >
810 > export function getNotificationsPosition(configurationService: IConfigurationService): NotificationsPosition {
811 const position = configurationService.getValue<NotificationsPosition>(NotificationsSettings.NOTIFICATIONS_POSITION);
812
813 if (position === NotificationsPosition.BOTTOM_LEFT || position === NotificationsPosition.TOP_RIGHT) {
814 return position;
815 }
816
817 return NotificationsPosition.BOTTOM_RIGHT;
818 }