提交 4cffff9f 编写于 作者: B Benjamin Pasero

fix #51013

上级 931c2203
......@@ -35,7 +35,7 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe
import { OS } from 'vs/base/common/platform';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import { INotificationService, INotification, INotificationHandle, NoOpNotification, IPromptChoice } from 'vs/platform/notification/common/notification';
import { INotificationService, INotification, INotificationHandle, NoOpNotification, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions } from 'vs/platform/dialogs/common/dialogs';
import { IPosition, Position as Pos } from 'vs/editor/common/core/position';
import { isEditorConfigurationKey, isDiffEditorConfigurationKey } from 'vs/editor/common/config/commonEditorConfig';
......@@ -212,7 +212,7 @@ export class SimpleNotificationService implements INotificationService {
return SimpleNotificationService.NO_OP;
}
public prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle {
public prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
return SimpleNotificationService.NO_OP;
}
}
......
......@@ -96,7 +96,8 @@ export class IntegrityServiceImpl implements IIntegrityService {
isSecondary: true,
run: () => this._storage.set({ dontShowPrompt: true, commit: product.commit })
}
]
],
{ sticky: true }
);
}
......
......@@ -16,7 +16,7 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe
import { OS } from 'vs/base/common/platform';
import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { INotificationService, NoOpNotification, INotification, IPromptChoice } from 'vs/platform/notification/common/notification';
import { INotificationService, NoOpNotification, INotification, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
function createContext(ctx: any) {
return {
......@@ -140,7 +140,7 @@ suite('AbstractKeybindingService', () => {
showMessageCalls.push({ sev: Severity.Error, message });
return new NoOpNotification();
},
prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void) {
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions) {
throw new Error('not implemented');
}
};
......
......@@ -45,6 +45,12 @@ export interface INotification {
* this usecase and much easier to use!
*/
actions?: INotificationActions;
/**
* Sticky notifications are not automatically removed after a certain timeout. By
* default, notifications with primary actions and severity error are always sticky.
*/
sticky?: boolean;
}
export interface INotificationActions {
......@@ -147,6 +153,22 @@ export interface IPromptChoice {
run: () => void;
}
export interface IPromptOptions {
/**
* Sticky prompts are not automatically removed after a certain timeout.
*
* Note: Prompts of severity ERROR are always sticky.
*/
sticky?: boolean;
/**
* Will be called if the user closed the notification without picking
* any of the provided choices.
*/
onCancel?: () => void;
}
/**
* A service to bring up notifications and non-modal prompts.
*
......@@ -195,7 +217,7 @@ export interface INotificationService {
*
* @returns a handle on the notification to e.g. hide it or update message, buttons, etc.
*/
prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle;
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle;
}
export class NoOpNotification implements INotificationHandle {
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { INotificationService, INotificationHandle, NoOpNotification, Severity, INotification, IPromptChoice } from 'vs/platform/notification/common/notification';
import { INotificationService, INotificationHandle, NoOpNotification, Severity, INotification, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
export class TestNotificationService implements INotificationService {
......@@ -27,7 +27,7 @@ export class TestNotificationService implements INotificationService {
return TestNotificationService.NO_OP;
}
public prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle {
public prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
return TestNotificationService.NO_OP;
}
}
\ No newline at end of file
......@@ -512,7 +512,8 @@ export class EditorStatus implements IStatusbarItem {
run: () => {
this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER);
}
}]
}],
{ sticky: true }
);
once(this.screenReaderNotification.onDidClose)(() => {
......
......@@ -21,6 +21,7 @@ import { localize } from 'vs/nls';
import { Severity } from 'vs/platform/notification/common/notification';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IWindowService } from 'vs/platform/windows/common/windows';
interface INotificationToast {
item: INotificationViewItem;
......@@ -52,6 +53,7 @@ export class NotificationsToasts extends Themable {
private notificationsToastsContainer: HTMLElement;
private workbenchDimensions: Dimension;
private windowHasFocus: boolean;
private isNotificationsCenterVisible: boolean;
private mapNotificationToToast: Map<INotificationViewItem, INotificationToast>;
private notificationsToastsVisibleContextKey: IContextKey<boolean>;
......@@ -64,13 +66,16 @@ export class NotificationsToasts extends Themable {
@IThemeService themeService: IThemeService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IContextKeyService contextKeyService: IContextKeyService,
@ILifecycleService private lifecycleService: ILifecycleService
@ILifecycleService private lifecycleService: ILifecycleService,
@IWindowService private windowService: IWindowService
) {
super(themeService);
this.mapNotificationToToast = new Map<INotificationViewItem, INotificationToast>();
this.notificationsToastsVisibleContextKey = NotificationsToastsVisibleContext.bindTo(contextKeyService);
this.windowService.isFocused().then(isFocused => this.windowHasFocus = isFocused);
this.registerListeners();
}
......@@ -85,6 +90,9 @@ export class NotificationsToasts extends Themable {
// Update toasts on notification changes
this._register(this.model.onDidNotificationChange(e => this.onDidNotificationChange(e)));
});
// Track window focus
this.windowService.onDidChangeFocus(hasFocus => this.windowHasFocus = hasFocus);
}
private onDidNotificationChange(e: INotificationChangeEvent): void {
......@@ -177,31 +185,8 @@ export class NotificationsToasts extends Themable {
this.removeToast(item);
});
// Automatically hide collapsed notifications
if (!item.expanded) {
// Track mouse over item
let isMouseOverToast = false;
itemDisposeables.push(addDisposableListener(notificationToastContainer, EventType.MOUSE_OVER, () => isMouseOverToast = true));
itemDisposeables.push(addDisposableListener(notificationToastContainer, EventType.MOUSE_OUT, () => isMouseOverToast = false));
// Install Timers
let timeoutHandle: any;
const hideAfterTimeout = () => {
timeoutHandle = setTimeout(() => {
const showsProgress = item.hasProgress() && !item.progress.state.done;
if (!notificationList.hasFocus() && !item.expanded && !isMouseOverToast && !showsProgress) {
this.removeToast(item);
} else {
hideAfterTimeout(); // push out disposal if item has focus or is expanded
}
}, NotificationsToasts.PURGE_TIMEOUT[item.severity]);
};
hideAfterTimeout();
itemDisposeables.push(toDisposable(() => clearTimeout(timeoutHandle)));
}
// Automatically purge non-sticky notifications
this.purgeNotification(item, notificationToastContainer, notificationList, itemDisposeables);
// Theming
this.updateStyles();
......@@ -217,6 +202,35 @@ export class NotificationsToasts extends Themable {
}));
}
private purgeNotification(item: INotificationViewItem, notificationToastContainer: HTMLElement, notificationList: NotificationsList, disposables: IDisposable[]): void {
// Track mouse over item
let isMouseOverToast = false;
disposables.push(addDisposableListener(notificationToastContainer, EventType.MOUSE_OVER, () => isMouseOverToast = true));
disposables.push(addDisposableListener(notificationToastContainer, EventType.MOUSE_OUT, () => isMouseOverToast = false));
// Install Timers
let timeoutHandle: any;
const hideAfterTimeout = () => {
timeoutHandle = setTimeout(() => {
if (
item.sticky || // never hide sticky notifications
notificationList.hasFocus() || // never hide notifications with focus
isMouseOverToast || // never hide notifications under mouse
!this.windowHasFocus // never hide when window has no focus
) {
hideAfterTimeout();
} else {
this.removeToast(item);
}
}, NotificationsToasts.PURGE_TIMEOUT[item.severity]);
};
hideAfterTimeout();
disposables.push(toDisposable(() => clearTimeout(timeoutHandle)));
}
private removeToast(item: INotificationViewItem): void {
const notificationToast = this.mapNotificationToToast.get(item);
let focusGroup = false;
......
......@@ -177,6 +177,7 @@ export class NotificationsModel extends Disposable implements INotificationsMode
export interface INotificationViewItem {
readonly severity: Severity;
readonly sticky: boolean;
readonly message: INotificationMessage;
readonly source: string;
readonly actions: INotificationActions;
......@@ -363,7 +364,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
actions = { primary: notification.message.actions };
}
return new NotificationViewItem(severity, message, notification.source, actions);
return new NotificationViewItem(severity, notification.sticky, message, notification.source, actions);
}
private static parseNotificationMessage(input: NotificationMessage): INotificationMessage {
......@@ -397,11 +398,10 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return matchString;
});
return { raw, value: message, links, original: input };
}
private constructor(private _severity: Severity, private _message: INotificationMessage, private _source: string, actions?: INotificationActions) {
private constructor(private _severity: Severity, private _sticky: boolean, private _message: INotificationMessage, private _source: string, actions?: INotificationActions) {
super();
this.setActions(actions);
......@@ -436,6 +436,23 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return this._severity;
}
get sticky(): boolean {
if (this._sticky) {
return true; // explicitly sticky
}
const hasPrimaryActions = Array.isArray(this._actions.primary) && this._actions.primary.length > 0;
if (
(hasPrimaryActions && this._severity === Severity.Error) || // notification errors with actions are sticky
(!hasPrimaryActions && this._expanded) || // notifications that got expanded are sticky
(this._progress && !this._progress.state.done) // notifications with running progress are sticky
) {
return true;
}
return false; // not sticky
}
hasProgress(): boolean {
return !!this._progress;
}
......
......@@ -80,9 +80,11 @@ export class ExperimentalPrompts extends Disposable implements IWorkbenchContrib
};
});
this.notificationService.prompt(Severity.Info, actionProperties.promptText, choices, () => {
logTelemetry();
this.experimentService.markAsCompleted(experiment.id);
this.notificationService.prompt(Severity.Info, actionProperties.promptText, choices, {
onCancel: () => {
logTelemetry();
this.experimentService.markAsCompleted(experiment.id);
}
});
}
......
......@@ -94,7 +94,7 @@ suite('Experimental Prompts', () => {
};
instantiationService.stub(INotificationService, {
prompt: (a: Severity, b: string, c: IPromptChoice[], d) => {
prompt: (a: Severity, b: string, c: IPromptChoice[], options) => {
assert.equal(b, promptText);
assert.equal(c.length, 2);
c[0].run();
......@@ -118,7 +118,7 @@ suite('Experimental Prompts', () => {
};
instantiationService.stub(INotificationService, {
prompt: (a: Severity, b: string, c: IPromptChoice[], d) => {
prompt: (a: Severity, b: string, c: IPromptChoice[], options) => {
assert.equal(b, promptText);
assert.equal(c.length, 2);
c[1].run();
......@@ -142,10 +142,10 @@ suite('Experimental Prompts', () => {
};
instantiationService.stub(INotificationService, {
prompt: (a: Severity, b: string, c: IPromptChoice[], d) => {
prompt: (a: Severity, b: string, c: IPromptChoice[], options) => {
assert.equal(b, promptText);
assert.equal(c.length, 2);
d();
options.onCancel();
}
});
......
......@@ -611,14 +611,17 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
this.promptIgnoreExtensionRecommendations();
}
}],
() => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name });
{
sticky: true,
onCancel: () => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name });
}
}
);
});
......@@ -687,14 +690,17 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension: fileExtension });
}
}],
() => {
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension: fileExtension });
{
sticky: true,
onCancel: () => {
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension: fileExtension });
}
}
);
});
......@@ -772,15 +778,18 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
c(void 0);
}
}],
() => {
/* __GDPR__
"extensionWorkspaceRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'cancelled' });
{
sticky: true,
onCancel: () => {
/* __GDPR__
"extensionWorkspaceRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'cancelled' });
c(void 0);
c(void 0);
}
}
);
});
......
......@@ -7,7 +7,6 @@ import 'vs/css!./media/extensionActions';
import { localize } from 'vs/nls';
import { IAction, Action } from 'vs/base/common/actions';
import { Throttler } from 'vs/base/common/async';
import severity from 'vs/base/common/severity';
import * as DOM from 'vs/base/browser/dom';
import * as paths from 'vs/base/common/paths';
import { Event } from 'vs/base/common/event';
......@@ -823,7 +822,7 @@ export class CheckForUpdatesAction extends Action {
extensions => {
const outdatedExtensions = extensions.filter(ext => ext.outdated === true);
if (!outdatedExtensions.length) {
this.notificationService.notify({ severity: severity.Info, message: localize('noUpdatesAvailable', "All Extensions are up to date.") });
this.notificationService.info(localize('noUpdatesAvailable', "All Extensions are up to date."));
return;
}
......@@ -846,7 +845,7 @@ export class CheckForUpdatesAction extends Action {
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => viewlet.search(''));
this.notificationService.notify({ severity: severity.Info, message: msgAvailableExtensions });
this.notificationService.info(msgAvailableExtensions);
}
);
}
......@@ -2351,7 +2350,8 @@ export class InstallVSIXAction extends Action {
[{
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()
}]
}],
{ sticky: true }
);
});
});
......@@ -2408,7 +2408,8 @@ export class ReinstallAction extends Action {
[{
label: localize('ReinstallAction.reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()
}]
}],
{ sticky: true }
);
}, error => this.notificationService.error(error));
}
......
......@@ -635,7 +635,8 @@ export class MaliciousExtensionChecker implements IWorkbenchContribution {
[{
label: localize('reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()
}]
}],
{ sticky: true }
);
})));
} else {
......
......@@ -1033,7 +1033,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
[{
label: nls.localize('install', "Install"),
run: () => this.install(extension).then(undefined, error => this.onError(error))
}]
}],
{ sticky: true }
);
});
});
......
......@@ -43,7 +43,7 @@ import product from 'vs/platform/node/product';
import { ITextModel } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification';
import { INotificationService, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
import { URLService } from 'vs/platform/url/common/urlService';
import { IExperimentService } from 'vs/workbench/parts/experiments/node/experimentService';
import { TestExperimentService } from 'vs/workbench/parts/experiments/test/node/experimentService.test';
......@@ -233,7 +233,7 @@ suite('ExtensionsTipsService Test', () => {
prompted = false;
class TestNotificationService2 extends TestNotificationService {
public prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void) {
public prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions) {
prompted = true;
return null;
}
......
......@@ -93,7 +93,8 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
label: localize('neverAgain', "Don't Show Again"),
isSecondary: true,
run: () => this.storageService.store(donotAskUpdateKey, true)
}]
}],
{ sticky: true }
);
}
}
......@@ -200,8 +201,10 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
logUserReaction('neverShowAgain');
}
}],
() => {
logUserReaction('cancelled');
{
onCancel: () => {
logUserReaction('cancelled');
}
}
);
......
......@@ -112,7 +112,8 @@ class LanguageSurvey {
storageService.store(IS_CANDIDATE_KEY, false, StorageScope.GLOBAL);
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
}
}]
}],
{ sticky: true }
);
}
}
......
......@@ -82,7 +82,8 @@ class NPSContribution implements IWorkbenchContribution {
storageService.store(IS_CANDIDATE_KEY, false, StorageScope.GLOBAL);
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
}
}]
}],
{ sticky: true }
);
}
}
......
......@@ -509,7 +509,8 @@ class TaskService implements ITaskService {
[{
label: nls.localize('reloadWindow', "Reload Window"),
run: () => this._windowService.reloadWindow()
}]
}],
{ sticky: true }
);
return;
} else {
......@@ -1236,7 +1237,8 @@ class TaskService implements ITaskService {
{
label: nls.localize('restartTask', "Restart Task"),
run: () => this.restart(task)
}]
}],
{ sticky: true }
);
} else {
throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is already a task running. Terminate it first before executing another task.'), TaskErrors.RunningTask);
......
......@@ -134,7 +134,8 @@ export class ProductContribution implements IWorkbenchContribution {
const uri = URI.parse(product.releaseNotesUrl);
openerService.open(uri);
}
}]
}],
{ sticky: true }
);
});
}
......@@ -204,7 +205,8 @@ export class Win3264BitContribution implements IWorkbenchContribution {
neverShowAgain.action.run(handle);
neverShowAgain.action.dispose();
}
}]
}],
{ sticky: true }
);
}
}
......@@ -357,7 +359,8 @@ export class UpdateContribution implements IGlobalActivity {
action.run();
action.dispose();
}
}]
}],
{ sticky: true }
);
}
......@@ -383,7 +386,8 @@ export class UpdateContribution implements IGlobalActivity {
action.run();
action.dispose();
}
}]
}],
{ sticky: true }
);
}
......@@ -437,7 +441,8 @@ export class UpdateContribution implements IGlobalActivity {
action.run();
action.dispose();
}
}]
}],
{ sticky: true }
);
}
......
......@@ -67,7 +67,8 @@ export class TelemetryOptOut implements IWorkbenchContribution {
[{
label: localize('telemetryOptOut.readMore', "Read More"),
run: () => openerService.open(URI.parse(this.optOutUrl))
}]
}],
{ sticky: true }
);
})
.then(null, onUnexpectedError);
......@@ -136,7 +137,10 @@ export class TelemetryOptOut implements IWorkbenchContribution {
}
}
],
logTelemetry
{
sticky: true,
onCancel: logTelemetry
}
);
this.experimentService.markAsCompleted(experimentId);
});
......
......@@ -273,7 +273,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
[{
label: nls.localize('reloadWindow', "Reload Window"),
run: () => this._windowService.reloadWindow()
}]
}],
{ sticky: true }
);
}, 10000);
}
......
......@@ -194,7 +194,7 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
}
}
// Extnesion is not installed
// Extension is not installed
else {
const galleryExtension = await this.galleryService.getExtension(extensionIdentifier);
if (galleryExtension) {
......@@ -224,7 +224,8 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
[{
label: reloadActionLabel,
run: () => this.reloadAndHandle(uri)
}]
}],
{ sticky: true }
);
}
} catch (e) {
......
......@@ -144,7 +144,8 @@ export class FileService extends Disposable implements IFileService {
label: nls.localize('neverShowAgain', "Don't Show Again"),
isSecondary: true,
run: () => this.storageService.store(FileService.NET_VERSION_ERROR_IGNORE_KEY, true, StorageScope.WORKSPACE)
}]
}],
{ sticky: true }
);
}
......@@ -161,7 +162,8 @@ export class FileService extends Disposable implements IFileService {
label: nls.localize('neverShowAgain', "Don't Show Again"),
isSecondary: true,
run: () => this.storageService.store(FileService.ENOSPC_ERROR_IGNORE_KEY, true, StorageScope.WORKSPACE)
}]
}],
{ sticky: true }
);
}
}
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice } from 'vs/platform/notification/common/notification';
import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
import { INotificationsModel, NotificationsModel, ChoiceAction } from 'vs/workbench/common/notifications';
import { dispose, Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { once } from 'vs/base/common/event';
......@@ -52,7 +52,7 @@ export class NotificationService extends Disposable implements INotificationServ
return this.model.notify(notification);
}
prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle {
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
const toDispose: IDisposable[] = [];
let choiceClicked = false;
......@@ -82,7 +82,7 @@ export class NotificationService extends Disposable implements INotificationServ
});
// Show notification with actions
handle = this.notify({ severity, message, actions });
handle = this.notify({ severity, message, actions, sticky: options && options.sticky });
once(handle.onDidClose)(() => {
......@@ -90,8 +90,8 @@ export class NotificationService extends Disposable implements INotificationServ
dispose(toDispose);
// Indicate cancellation to the outside if no action was executed
if (typeof onCancel === 'function' && !choiceClicked) {
onCancel();
if (options && typeof options.onCancel === 'function' && !choiceClicked) {
options.onCancel();
}
});
......
......@@ -7,7 +7,7 @@ import * as assert from 'assert';
import { MainThreadMessageService } from 'vs/workbench/api/electron-browser/mainThreadMessageService';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice } from 'vs/platform/notification/common/notification';
import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
import { ICommandService } from 'vs/platform/commands/common/commands';
const emptyDialogService = new class implements IDialogService {
......@@ -43,7 +43,7 @@ const emptyNotificationService = new class implements INotificationService {
error(...args: any[]): never {
throw new Error('not implemented');
}
prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle {
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
throw new Error('not implemented');
}
};
......@@ -69,7 +69,7 @@ class EmptyNotificationService implements INotificationService {
error(message: any): void {
throw new Error('Method not implemented.');
}
prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle {
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
throw new Error('not implemented');
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册