Reuse never show again logic - work in progress (#73968)

* Support never show again option in notification service

* in notify put never show again as secondary

* Allow customization of whether never show again is shown as secondary or primary

* put never show again inside notification object

* feedback

* feedback
This commit is contained in:
Yisrael Veller
2019-08-08 16:47:15 +03:00
committed by Benjamin Pasero
parent 1cb73a38a7
commit f084f2c793
4 changed files with 85 additions and 19 deletions

View File

@@ -269,6 +269,10 @@
{
"name": "vs/workbench/services/preferences",
"project": "vscode-preferences"
},
{
"name": "vs/workbench/services/notification",
"project": "vscode-workbench"
}
]
}

View File

@@ -29,6 +29,11 @@ export interface INotificationProperties {
* catch some attention.
*/
silent?: boolean;
/**
* Add a "never show again" action. If user selects the action, the notification will not appear again.
*/
neverShowAgainOptions?: INeverShowAgainOptions;
}
export interface INotification extends INotificationProperties {
@@ -173,6 +178,23 @@ export interface IPromptOptions extends INotificationProperties {
onCancel?: () => void;
}
export interface INeverShowAgainOptions {
/**
* Sending prompt id automatically adds a "never show again" action to the prompt.
* If user picks this option, future calls to 'prompt' with the same prompt id will be ignored.
* The id is used to persist the selection to storage
*/
id: string;
/**
*
* Primary: The never show again action will show up as a button on the notificaion.
* Secondary The never show again action will show up under the gear icon.
*/
isSecondary?: boolean;
}
export interface IStatusMessageOptions {
/**

View File

@@ -11,7 +11,6 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
/**
* Shows a message when opening a large file which has been memory optimized (and features disabled).
@@ -20,26 +19,19 @@ export class LargeFileOptimizationsWarner extends Disposable implements IEditorC
private static readonly ID = 'editor.contrib.largeFileOptimizationsWarner';
private _isDisabled: boolean;
constructor(
private readonly _editor: ICodeEditor,
@INotificationService private readonly _notificationService: INotificationService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IStorageService private readonly _storageService: IStorageService,
) {
super();
this._isDisabled = Boolean(this._storageService.getBoolean('editor.neverPromptForLargeFiles', StorageScope.GLOBAL, false));
this._register(this._editor.onDidChangeModel((e) => {
const model = this._editor.getModel();
if (!model) {
return;
}
if (this._isDisabled) {
return;
}
if (model.isTooLargeForTokenization()) {
const message = nls.localize(
@@ -54,13 +46,6 @@ export class LargeFileOptimizationsWarner extends Disposable implements IEditorC
);
this._notificationService.prompt(Severity.Info, message, [
{
label: nls.localize('dontShowAgain', "Don't Show Again"),
run: () => {
this._isDisabled = true;
this._storageService.store('editor.neverPromptForLargeFiles', true, StorageScope.GLOBAL);
}
},
{
label: nls.localize('removeOptimizations', "Forcefully enable features"),
run: () => {
@@ -71,7 +56,7 @@ export class LargeFileOptimizationsWarner extends Disposable implements IEditorC
});
}
}
]);
], { neverShowAgainOptions: { id: 'editor.contrib.largeFileOptimizationsWarner' } });
}
}));
}

View File

@@ -3,13 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification';
import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions, IStatusMessageOptions, NoOpNotification } from 'vs/platform/notification/common/notification';
import { INotificationsModel, NotificationsModel, ChoiceAction } from 'vs/workbench/common/notifications';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IAction } from 'vs/base/common/actions';
import { IAction, Action } from 'vs/base/common/actions';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import * as nls from 'vs/nls';
export class NotificationService extends Disposable implements INotificationService {
@@ -21,6 +23,10 @@ export class NotificationService extends Disposable implements INotificationServ
return this._model;
}
constructor(@IStorageService private readonly storageService: IStorageService) {
super();
}
info(message: NotificationMessage | NotificationMessage[]): void {
if (Array.isArray(message)) {
message.forEach(m => this.info(m));
@@ -52,12 +58,61 @@ export class NotificationService extends Disposable implements INotificationServ
}
notify(notification: INotification): INotificationHandle {
return this.model.addNotification(notification);
let handle: INotificationHandle;
if (notification.neverShowAgainOptions) {
const id = notification.neverShowAgainOptions.id;
if (!!this.storageService.get(id, StorageScope.GLOBAL)) {
return new NoOpNotification();
}
const neverShowAction = new Action(
'workbench.dialog.choice.neverShowAgain',
nls.localize('neverShowAgain', "Don't Show Again"),
undefined, true, () => {
handle.close();
this.storageService.store(id, true, StorageScope.GLOBAL);
return Promise.resolve();
});
notification.actions = notification.actions || {};
if (notification.neverShowAgainOptions.isSecondary) {
notification.actions.secondary = notification.actions.secondary || [];
notification.actions.secondary = [...notification.actions.secondary, neverShowAction];
}
else {
notification.actions.primary = notification.actions.primary || [];
notification.actions.primary = [neverShowAction, ...notification.actions.primary];
}
}
handle = this.model.addNotification(notification);
return handle;
}
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
const toDispose = new DisposableStore();
if (options && options.neverShowAgainOptions) {
const id = options.neverShowAgainOptions.id;
if (!!this.storageService.get(id, StorageScope.GLOBAL)) {
return new NoOpNotification();
}
const neverShowAgainChoice = {
label: nls.localize('neverShowAgain', "Don't Show Again"),
run: () => this.storageService.store(id, true, StorageScope.GLOBAL),
isSecondary: options.neverShowAgainOptions.isSecondary
};
if (options.neverShowAgainOptions.isSecondary) {
choices = [...choices, neverShowAgainChoice];
}
else {
choices = [neverShowAgainChoice, ...choices];
}
}
let choiceClicked = false;
let handle: INotificationHandle;