提交 5fc7be85 编写于 作者: B Benjamin Pasero

notifications - clean up choice service

上级 b55506b4
......@@ -34,7 +34,7 @@ export class ChoiceChannelClient implements IChoiceService {
constructor(private channel: IChoiceChannel) { }
choose(severity: Severity, message: string, options: string[], cancelId: number, modal?: boolean): TPromise<number> {
choose(severity: Severity, message: string, options: string[], cancelId?: number, modal?: boolean): TPromise<number> {
return this.channel.call('choose', [severity, message, options, cancelId, modal]);
}
}
\ No newline at end of file
......@@ -45,12 +45,14 @@ export interface IConfirmationService {
export const IChoiceService = createDecorator<IChoiceService>('choiceService');
export type Choice = string | { label: string; isSecondary?: boolean; };
export interface IChoiceService {
_serviceBrand: any;
/**
* Prompt the user for a choice between multiple options.
* Prompt the user for a choice between multiple choices.
*
* @param when `modal` is true, this will block the user until chooses.
*
......@@ -62,5 +64,5 @@ export interface IChoiceService {
* `Cancel` option is returned. If there is no such option then promise with
* `0` index is returned.
*/
choose(severity: Severity, message: string, options: string[], cancelId: number, modal?: boolean): TPromise<number>;
choose(severity: Severity, message: string, choices: Choice[], cancelId?: number, modal?: boolean): TPromise<number>;
}
\ No newline at end of file
......@@ -12,7 +12,7 @@ export class ChoiceCliService implements IChoiceService {
_serviceBrand: any;
choose(severity: Severity, message: string, options: string[], cancelId: number): TPromise<number> {
choose(severity: Severity, message: string, options: string[]): TPromise<number> {
const promise = new TPromise<number>((c, e) => {
const rl = readline.createInterface({
input: process.stdin,
......
......@@ -36,7 +36,7 @@ import { getHashedRemotesFromUri } from 'vs/workbench/parts/stats/node/workspace
import { IRequestService } from 'vs/platform/request/node/request';
import { asJson } from 'vs/base/node/request';
import { isNumber } from 'vs/base/common/types';
import { IChoiceService } from 'vs/platform/dialogs/common/dialogs';
import { IChoiceService, Choice } from 'vs/platform/dialogs/common/dialogs';
interface IExtensionsContent {
recommendations: string[];
......@@ -45,7 +45,6 @@ interface IExtensionsContent {
const empty: { [key: string]: any; } = Object.create(null);
const milliSecondsInADay = 1000 * 60 * 60 * 24;
const choiceNever = localize('neverShowAgain', "Don't Show Again");
const choiceClose = localize('close', "Close");
interface IDynamicWorkspaceRecommendations {
remoteSet: string[];
......@@ -401,14 +400,13 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations"));
const installAction = this.instantiationService.createInstance(InstallRecommendedExtensionAction, id);
const options = [
const options: Choice[] = [
localize('install', 'Install'),
recommendationsAction.label,
choiceNever,
choiceClose
{ label: choiceNever, isSecondary: true }
];
this.choiceService.choose(Severity.Info, message, options, 3).done(choice => {
this.choiceService.choose(Severity.Info, message, options).done(choice => {
switch (choice) {
case 0:
/* __GDPR__
......@@ -442,14 +440,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name });
return this.ignoreExtensionRecommendations();
case 3:
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'close', extensionId: name });
}
}, () => {
/* __GDPR__
......@@ -492,13 +482,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
const searchMarketplaceAction = this.instantiationService.createInstance(ShowLanguageExtensionsAction, fileExtension);
const options = [
const options: Choice[] = [
localize('searchMarketplace', "Search Marketplace"),
choiceNever,
choiceClose
{ label: choiceNever, isSecondary: true }
];
this.choiceService.choose(Severity.Info, message, options, 2).done(choice => {
this.choiceService.choose(Severity.Info, message, options).done(choice => {
switch (choice) {
case 0:
/* __GDPR__
......@@ -524,15 +513,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension: fileExtension });
case 2:
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'close', fileExtension: fileExtension });
break;
}
}, () => {
/* __GDPR__
......@@ -569,14 +549,13 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
const showAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations"));
const installAllAction = this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, localize('installAll', "Install All"));
const options = [
const options: Choice[] = [
installAllAction.label,
showAction.label,
choiceNever,
choiceClose
{ label: choiceNever, isSecondary: true }
];
return this.choiceService.choose(Severity.Info, message, options, 3).done(choice => {
return this.choiceService.choose(Severity.Info, message, options).done(choice => {
switch (choice) {
case 0:
/* __GDPR__
......@@ -602,13 +581,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
*/
this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'neverShowAgain' });
return this.storageService.store(storageKey, true, StorageScope.WORKSPACE);
case 3:
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'close' });
}
}, () => {
/* __GDPR__
......@@ -630,7 +602,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
localize('cancel', "Cancel")
];
this.choiceService.choose(Severity.Info, message, options, 2).done(choice => {
this.choiceService.choose(Severity.Info, message, options).done(choice => {
switch (choice) {
case 0: // If the user ignores the current message and selects different file type
// we should hide all the stacked up messages as he has selected Yes, Ignore All
......
......@@ -66,8 +66,6 @@ export class KeymapExtensions implements IWorkbenchContribution {
}
private promptForDisablingOtherKeymaps(newKeymap: IExtensionStatus, oldKeymaps: IExtensionStatus[]): TPromise<void> {
const message = localize('disableOtherKeymapsConfirmation', "Disable other keymaps ({0}) to avoid conflicts between keybindings?", oldKeymaps.map(k => `'${k.local.manifest.displayName}'`).join(', '));
const options = [
localize('yes', "Yes"),
......
......@@ -961,7 +961,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
nls.localize('install', "Install"),
nls.localize('cancel', "Cancel")
];
return this.choiceService.choose(Severity.Info, message, options, 2, false).then(value => {
return this.choiceService.choose(Severity.Info, message, options).then(value => {
if (value !== 0) {
return TPromise.as(null);
}
......
......@@ -46,6 +46,8 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { IProgressService2, IProgressOptions, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IConfirmationService } from 'vs/platform/dialogs/common/dialogs';
import { IModelService } from 'vs/editor/common/services/modelService';
......@@ -454,20 +456,6 @@ class TaskService implements ITaskService {
public static OutputChannelId: string = 'tasks';
public static OutputChannelLabel: string = nls.localize('tasks', "Tasks");
private configurationService: IConfigurationService;
private markerService: IMarkerService;
private outputService: IOutputService;
private messageService: IMessageService;
private choiceService: IChoiceService;
private fileService: IFileService;
private telemetryService: ITelemetryService;
private editorService: IWorkbenchEditorService;
private contextService: IWorkspaceContextService;
private textFileService: ITextFileService;
private modelService: IModelService;
private extensionService: IExtensionService;
private quickOpenService: IQuickOpenService;
private _configHasErrors: boolean;
private __schemaVersion: JsonSchemaVersion;
private __executionEngine: ExecutionEngine;
......@@ -486,37 +474,28 @@ class TaskService implements ITaskService {
private _onDidStateChange: Emitter<TaskEvent>;
constructor(
@IConfigurationService configurationService: IConfigurationService,
@IMarkerService markerService: IMarkerService, @IOutputService outputService: IOutputService,
@IMessageService messageService: IMessageService, @IChoiceService choiceService: IChoiceService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IFileService fileService: IFileService, @IWorkspaceContextService contextService: IWorkspaceContextService,
@ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService,
@IConfigurationService private configurationService: IConfigurationService,
@IMarkerService private markerService: IMarkerService,
@IOutputService private outputService: IOutputService,
@IMessageService private messageService: IMessageService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IFileService private fileService: IFileService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@ITelemetryService private telemetryService: ITelemetryService,
@ITextFileService private textFileService: ITextFileService,
@ILifecycleService lifecycleService: ILifecycleService,
@IModelService modelService: IModelService, @IExtensionService extensionService: IExtensionService,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IModelService private modelService: IModelService,
@IExtensionService private extensionService: IExtensionService,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IConfigurationResolverService private configurationResolverService: IConfigurationResolverService,
@ITerminalService private terminalService: ITerminalService,
@IStorageService private storageService: IStorageService,
@IProgressService2 private progressService: IProgressService2,
@IOpenerService private openerService: IOpenerService,
@IWindowService private readonly _windowServive: IWindowService,
@IConfirmationService private confirmationService: IConfirmationService
@IConfirmationService private confirmationService: IConfirmationService,
@INotificationService private notificationService: INotificationService
) {
this.configurationService = configurationService;
this.markerService = markerService;
this.outputService = outputService;
this.messageService = messageService;
this.choiceService = choiceService;
this.editorService = editorService;
this.fileService = fileService;
this.contextService = contextService;
this.telemetryService = telemetryService;
this.textFileService = textFileService;
this.modelService = modelService;
this.extensionService = extensionService;
this.quickOpenService = quickOpenService;
this._configHasErrors = false;
this._workspaceTasksPromise = undefined;
this._taskSystem = undefined;
......@@ -1876,23 +1855,21 @@ class TaskService implements ITaskService {
if (this.ignoredWorkspaceFolders.length === 0 || !this.showIgnoreMessage) {
return TPromise.as(undefined);
}
let message: string = nls.localize('TaskService.ignoredFolder', 'The following workspace folders are ignored since they use task version 0.1.0: ');
for (let i = 0; i < this.ignoredWorkspaceFolders.length; i++) {
message = message + this.ignoredWorkspaceFolders[i].name;
if (i < this.ignoredWorkspaceFolders.length - 1) {
message = message + ', ';
}
}
let notAgain = nls.localize('TaskService.notAgain', 'Don\'t Show Again');
let ok = nls.localize('TaskService.ok', 'OK');
return this.choiceService.choose(Severity.Info, message, [notAgain, ok], 0).then((choice) => {
if (choice === 0) {
this.notificationService.notify({
severity: Severity.Info,
message: nls.localize('TaskService.ignoredFolder', 'The following workspace folders are ignored since they use task version 0.1.0: {0}', this.ignoredWorkspaceFolders.map(f => f.name).join(', ')),
actions: {
secondary: [new Action('dontShowAgain', nls.localize('TaskService.notAgain', 'Don\'t Show Again'), null, true, () => {
this.storageService.store(TaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE);
}
this.__showIgnoreMessage = false;
return undefined;
}, () => undefined);
return TPromise.as(true);
})]
}
});
return TPromise.as(undefined);
}
private runTaskCommand(accessor: ServicesAccessor, arg: any): void {
......@@ -2413,13 +2390,11 @@ let schema: IJSONSchema = {
import schemaVersion1 from './jsonSchema_v1';
import schemaVersion2 from './jsonSchema_v2';
import { IChoiceService, IConfirmationService } from 'vs/platform/dialogs/common/dialogs';
schema.definitions = {
...schemaVersion1.definitions,
...schemaVersion2.definitions,
};
schema.oneOf = [...schemaVersion2.oneOf, ...schemaVersion1.oneOf];
let jsonRegistry = <jsonContributionRegistry.IJSONContributionRegistry>Registry.as(jsonContributionRegistry.Extensions.JSONContribution);
jsonRegistry.registerSchema(schemaId, schema);
......@@ -159,7 +159,7 @@ export class TerminalConfigHelper implements ITerminalConfigHelper {
}
const message = nls.localize('terminal.integrated.allowWorkspaceShell', "Do you allow {0} (defined as a workspace setting) to be launched in the terminal?", changeString);
const options = [nls.localize('allow', "Allow"), nls.localize('disallow', "Disallow")];
this._choiceService.choose(Severity.Info, message, options, 1).then(choice => {
this._choiceService.choose(Severity.Info, message, options).then(choice => {
if (choice === 0) {
this._storageService.store(IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, true, StorageScope.WORKSPACE);
} else {
......
......@@ -22,7 +22,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { getTerminalDefaultShellWindows } from 'vs/workbench/parts/terminal/electron-browser/terminal';
import { TerminalPanel } from 'vs/workbench/parts/terminal/electron-browser/terminalPanel';
import { TerminalTab } from 'vs/workbench/parts/terminal/electron-browser/terminalTab';
import { IChoiceService, IConfirmationService } from 'vs/platform/dialogs/common/dialogs';
import { IChoiceService, IConfirmationService, Choice } from 'vs/platform/dialogs/common/dialogs';
export class TerminalService extends AbstractTerminalService implements ITerminalService {
private _configHelper: TerminalConfigHelper;
......@@ -127,8 +127,8 @@ export class TerminalService extends AbstractTerminalService implements ITermina
}
const message = nls.localize('terminal.integrated.chooseWindowsShellInfo', "You can change the default terminal shell by selecting the customize button.");
const options = [nls.localize('customize', "Customize"), nls.localize('cancel', "Cancel"), nls.localize('never again', "OK, Don't Show Again")];
this._choiceService.choose(Severity.Info, message, options, 1).then(choice => {
const options: Choice[] = [nls.localize('customize', "Customize"), nls.localize('cancel', "Cancel"), { label: nls.localize('never again', "OK, Don't Show Again"), isSecondary: true }];
this._choiceService.choose(Severity.Info, message, options).then(choice => {
switch (choice) {
case 0:
return this.selectDefaultWindowsShell().then(shell => {
......
......@@ -194,7 +194,7 @@ export class ConfigurationEditingService {
: operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY ? nls.localize('openLaunchConfiguration', "Open Launch Configuration")
: null;
if (openStandAloneConfigurationActionLabel) {
this.choiceService.choose(Severity.Error, error.message, [openStandAloneConfigurationActionLabel, nls.localize('close', "Close")], 1)
this.choiceService.choose(Severity.Error, error.message, [openStandAloneConfigurationActionLabel])
.then(option => {
switch (option) {
case 0:
......@@ -203,7 +203,7 @@ export class ConfigurationEditingService {
}
});
} else {
this.choiceService.choose(Severity.Error, error.message, [nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 1)
this.choiceService.choose(Severity.Error, error.message, [nls.localize('open', "Open Settings")])
.then(option => {
switch (option) {
case 0:
......@@ -219,7 +219,7 @@ export class ConfigurationEditingService {
: operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY ? nls.localize('openLaunchConfiguration', "Open Launch Configuration")
: null;
if (openStandAloneConfigurationActionLabel) {
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), openStandAloneConfigurationActionLabel, nls.localize('close', "Close")], 2)
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), openStandAloneConfigurationActionLabel])
.then(option => {
switch (option) {
case 0:
......@@ -232,7 +232,7 @@ export class ConfigurationEditingService {
}
});
} else {
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 2)
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), nls.localize('open', "Open Settings")])
.then(option => {
switch (option) {
case 0:
......
......@@ -13,8 +13,8 @@ import { isLinux } from 'vs/base/common/platform';
import { Action } from 'vs/base/common/actions';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { IConfirmationService, IChoiceService, IConfirmation, IConfirmationResult } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService, INotificationHandle } from 'vs/platform/notification/common/notification';
import { IConfirmationService, IChoiceService, IConfirmation, IConfirmationResult, Choice } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService, INotificationHandle, INotificationActions } from 'vs/platform/notification/common/notification';
import { once } from 'vs/base/common/event';
import URI from 'vs/base/common/uri';
import { basename } from 'vs/base/common/paths';
......@@ -86,21 +86,30 @@ export class DialogService implements IChoiceService, IConfirmationService {
return opts;
}
public choose(severity: Severity, message: string, options: string[], cancelId: number, modal: boolean = false): TPromise<number> {
public choose(severity: Severity, message: string, choices: Choice[], cancelId?: number, modal: boolean = false): TPromise<number> {
if (modal) {
return this.doChooseWithDialog(severity, message, options, cancelId);
return this.doChooseWithDialog(severity, message, choices, cancelId);
}
return this.doChooseWithNotification(severity, message, options);
return this.doChooseWithNotification(severity, message, choices);
}
private doChooseWithDialog(severity: Severity, message: string, options: string[], cancelId: number): TPromise<number> {
private doChooseWithDialog(severity: Severity, message: string, choices: Choice[], cancelId?: number): TPromise<number> {
const type: 'none' | 'info' | 'error' | 'question' | 'warning' = severity === Severity.Info ? 'question' : severity === Severity.Error ? 'error' : severity === Severity.Warning ? 'warning' : 'none';
const options: string[] = [];
choices.forEach(choice => {
if (typeof choice === 'string') {
options.push(choice);
} else {
options.push(choice.label);
}
});
return this.doShowMessageBox({ message, buttons: options, type, cancelId });
}
private doChooseWithNotification(severity: Severity, message: string, options: string[]): TPromise<number> {
private doChooseWithNotification(severity: Severity, message: string, choices: Choice[]): TPromise<number> {
let handle: INotificationHandle;
const promise = new TPromise<number>((c, e) => {
......@@ -112,13 +121,34 @@ export class DialogService implements IChoiceService, IConfirmationService {
return TPromise.as(void 0);
};
// Show notification with actions
handle = this.notificationService.notify({
severity,
message,
actions: { primary: options.map((option, index) => new Action('?', option, '', true, callback(index))) }
// Convert choices into primary/secondary actions
const actions: INotificationActions = {
primary: [],
secondary: []
};
choices.forEach((choice, index) => {
let isPrimary = true;
let label: string;
if (typeof choice === 'string') {
label = choice;
} else {
label = choice.label;
isPrimary = !choice.isSecondary;
}
const action = new Action(`workbench.dialog.choice.${index}`, label, null, true, callback(index));
if (isPrimary) {
actions.primary.push(action);
} else {
actions.secondary.push(action);
}
});
// Show notification with actions
handle = this.notificationService.notify({ severity, message, actions });
// Cancel promise when notification gets disposed
once(handle.onDidHide)(() => promise.cancel());
......
......@@ -176,7 +176,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
}
private askToOpenWorkspaceConfigurationFile(message: string): TPromise<void> {
return this.choiceService.choose(Severity.Error, message, [nls.localize('openWorkspaceConfigurationFile', "Open Workspace Configuration File"), nls.localize('close', "Close")], 1)
return this.choiceService.choose(Severity.Error, message, [nls.localize('openWorkspaceConfigurationFile', "Open Workspace Configuration")])
.then(option => {
switch (option) {
case 0:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册