diff --git a/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts index 983743b9205d0aeab9574faace54f8dc9a16f3e8..2d57d2895343edcce5cf830a5c136f4f910e9f87 100644 --- a/src/vs/platform/telemetry/common/telemetry.ts +++ b/src/vs/platform/telemetry/common/telemetry.ts @@ -22,9 +22,6 @@ export interface ITelemetryData { } export interface ITelemetryExperiments { - showNewUserWatermark: boolean; - openUntitledFile: boolean; - enableWelcomePage: boolean; mergeQuickLinks: boolean; } diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 4a8231e3d3a746479c5ba9a8bf5d79836cf13ed7..ee9c9bf05e10c74c29bba5dffc6516f777898da4 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -13,15 +13,10 @@ import { ConfigurationSource, IConfigurationService } from 'vs/platform/configur import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/common/keybinding'; import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import * as objects from 'vs/base/common/objects'; export const defaultExperiments: ITelemetryExperiments = { - showNewUserWatermark: false, - openUntitledFile: true, - enableWelcomePage: true, mergeQuickLinks: false, }; @@ -45,43 +40,20 @@ export const NullTelemetryService = { }; export function loadExperiments(accessor: ServicesAccessor): ITelemetryExperiments { - const contextService = accessor.get(IWorkspaceContextService); const storageService = accessor.get(IStorageService); const configurationService = accessor.get(IConfigurationService); - updateExperimentsOverrides(configurationService, storageService); - configurationService.onDidUpdateConfiguration(e => updateExperimentsOverrides(configurationService, storageService)); - let { - showNewUserWatermark, - openUntitledFile, - enableWelcomePage, mergeQuickLinks, } = splitExperimentsRandomness(storageService); - const newUserDuration = 24 * 60 * 60 * 1000; - const firstSessionDate = storageService.get('telemetry.firstSessionDate'); - const isNewUser = !firstSessionDate || Date.now() - Date.parse(firstSessionDate) < newUserDuration; - if (!isNewUser || contextService.hasWorkspace()) { - showNewUserWatermark = defaultExperiments.showNewUserWatermark; - openUntitledFile = defaultExperiments.openUntitledFile; - } - return applyOverrides({ - showNewUserWatermark, - openUntitledFile, - enableWelcomePage, mergeQuickLinks, - }, storageService); -} - -export function isWelcomePageEnabled(storageService: IStorageService) { - const overrides = getExperimentsOverrides(storageService); - return 'enableWelcomePage' in overrides ? overrides.enableWelcomePage : splitExperimentsRandomness(storageService).enableWelcomePage; + }, configurationService); } -function applyOverrides(experiments: ITelemetryExperiments, storageService: IStorageService): ITelemetryExperiments { - const experimentsConfig = getExperimentsOverrides(storageService); +function applyOverrides(experiments: ITelemetryExperiments, configurationService: IConfigurationService): ITelemetryExperiments { + const experimentsConfig = getExperimentsOverrides(configurationService); Object.keys(experiments).forEach(key => { if (key in experimentsConfig) { experiments[key] = experimentsConfig[key]; @@ -92,22 +64,18 @@ function applyOverrides(experiments: ITelemetryExperiments, storageService: ISto function splitExperimentsRandomness(storageService: IStorageService): ITelemetryExperiments { const random1 = getExperimentsRandomness(storageService); - const [random2, showNewUserWatermark] = splitRandom(random1); - const [random3, openUntitledFile] = splitRandom(random2); + const [random2, /* showNewUserWatermark */] = splitRandom(random1); + const [random3, /* openUntitledFile */] = splitRandom(random2); const [random4, mergeQuickLinks] = splitRandom(random3); - const [, enableWelcomePage] = splitRandom(random4); + // tslint:disable-next-line:no-unused-variable (https://github.com/Microsoft/TypeScript/issues/16628) + const [random5, /* enableWelcomePage */] = splitRandom(random4); return { - showNewUserWatermark, - openUntitledFile, - enableWelcomePage, mergeQuickLinks, }; } -const GLOBAL_PREFIX = `storage://global/`; // TODO@Christoph debt, why do you need to know? just use the storageservice? - function getExperimentsRandomness(storageService: IStorageService) { - const key = GLOBAL_PREFIX + 'experiments.randomness'; + const key = 'experiments.randomness'; let valueString = storageService.get(key); if (!valueString) { valueString = Math.random().toString(); @@ -123,20 +91,9 @@ function splitRandom(random: number): [number, boolean] { return [scaled - i, i === 1]; } -const experimentsOverridesKey = GLOBAL_PREFIX + 'experiments.overrides'; - -function getExperimentsOverrides(storageService: IStorageService): ITelemetryExperiments { - const valueString = storageService.get(experimentsOverridesKey); - return valueString ? JSON.parse(valueString) : {}; -} - -function updateExperimentsOverrides(configurationService: IConfigurationService, storageService: IStorageService) { - const storageOverrides = getExperimentsOverrides(storageService); +function getExperimentsOverrides(configurationService: IConfigurationService): ITelemetryExperiments { const config: any = configurationService.getConfiguration('telemetry'); - const configOverrides = config && config.experiments || {}; - if (!objects.equals(storageOverrides, configOverrides)) { - storageService.store(experimentsOverridesKey, JSON.stringify(configOverrides)); - } + return config && config.experiments || {}; } export interface ITelemetryAppender { @@ -284,6 +241,7 @@ const configurationValueWhitelist = [ 'php.validate.enable', 'php.validate.run', 'workbench.welcome.enabled', + 'workbench.startupEditor', ]; export function configurationTelemetry(telemetryService: ITelemetryService, configurationService: IConfigurationService): IDisposable { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index b598c69f95333a52974ee46fc9f93316eb1e450e..60d3d8f017c9256e6f4ee877d91ddefe3dd186a7 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -449,8 +449,8 @@ export class Workbench implements IPartService { } } - // Empty workbench: some first time users will not have an untiled file; returning users will always have one - else if (!this.contextService.hasWorkspace() && this.telemetryService.getExperiments().openUntitledFile && !this.configurationService.lookup('workbench.welcome.enabled').value) { + // Empty workbench + else if (!this.contextService.hasWorkspace() && this.openUntitledFile()) { if (this.editorPart.hasEditorsToRestore()) { return TPromise.as([]); // do not open any empty untitled file if we have editors to restore } @@ -467,6 +467,17 @@ export class Workbench implements IPartService { return TPromise.as([]); } + private openUntitledFile() { + const startupEditor = this.configurationService.lookup('workbench.startupEditor'); + if (!startupEditor.user && !startupEditor.workspace) { + const welcomeEnabled = this.configurationService.lookup('workbench.welcome.enabled'); + if (welcomeEnabled.value !== undefined && welcomeEnabled.value !== null) { + return !welcomeEnabled.value; + } + } + return startupEditor.value === 'newUntitledFile'; + } + private initServices(): void { const { serviceCollection } = this.workbenchParams; diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index 466f854261e53eff659aeb18d6b7b74ff5f8ebf5..a8c4f86330683f19230424b1305e29238bf0246e 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -19,17 +19,14 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { GlobalQuickOpenAction } from 'vs/workbench/browser/parts/quickopen/quickopen'; -import { KeybindingsReferenceAction, OpenRecentAction } from 'vs/workbench/electron-browser/actions'; -import { ShowRecommendedKeymapExtensionsAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; +import { OpenRecentAction } from 'vs/workbench/electron-browser/actions'; import { GlobalNewUntitledFileAction, OpenFileAction } from 'vs/workbench/parts/files/browser/fileActions'; import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/fileActions'; import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; import { Parts, IPartService } from 'vs/workbench/services/part/common/partService'; import { StartAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { FindInFilesActionId } from 'vs/workbench/parts/search/common/constants'; -import { OpenGlobalKeybindingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions'; import { ToggleTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; -import { SelectColorThemeAction } from 'vs/workbench/parts/themes/electron-browser/themes.contribution'; interface WatermarkEntry { text: string; @@ -83,32 +80,6 @@ const startDebugging: WatermarkEntry = { ids: [StartAction.ID] }; -const selectTheme: WatermarkEntry = { - text: nls.localize('watermark.selectTheme', "Change Theme"), - ids: [SelectColorThemeAction.ID] -}; -const selectKeymap: WatermarkEntry = { - text: nls.localize('watermark.selectKeymap', "Change Keymap"), - ids: [ShowRecommendedKeymapExtensionsAction.ID] -}; -const keybindingsReference: WatermarkEntry = { - text: nls.localize('watermark.keybindingsReference', "Keyboard Reference"), - ids: [KeybindingsReferenceAction.ID] -}; -const openGlobalKeybindings: WatermarkEntry = { - text: nls.localize('watermark.openGlobalKeybindings', "Keyboard Shortcuts"), - ids: [OpenGlobalKeybindingsAction.ID] -}; - -const newUserEntries = [ - showCommands, - selectTheme, - selectKeymap, - openFolderNonMacOnly, - openFileOrFolderMacOnly, - KeybindingsReferenceAction.AVAILABLE ? keybindingsReference : openGlobalKeybindings -]; - const noFolderEntries = [ showCommands, openFileNonMacOnly, @@ -176,8 +147,7 @@ export class WatermarkContribution implements IWorkbenchContribution { const box = $(this.watermark) .div({ 'class': 'watermark-box' }); const folder = this.contextService.hasWorkspace(); - const newUser = this.telemetryService.getExperiments().showNewUserWatermark; - const selected = (newUser ? newUserEntries : (folder ? folderEntries : noFolderEntries)) + const selected = folder ? folderEntries : noFolderEntries .filter(entry => !('mac' in entry) || entry.mac === isMacintosh); const update = () => { const builder = $(box); diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts index 89337fe2a0112fac3a93db2d120feac05c1287c1..b924959f0370e4bb95ff4f9b67f4466010ee8401 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts @@ -10,6 +10,27 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { WelcomePageContribution, WelcomePageAction } from 'vs/workbench/parts/welcome/page/electron-browser/welcomePage'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; + +Registry.as(ConfigurationExtensions.Configuration) + .registerConfiguration({ + 'id': 'workbench', + 'order': 7, + 'title': localize('workbenchConfigurationTitle', "Workbench"), + 'properties': { + 'workbench.startupEditor': { + 'type': 'string', + 'enum': ['none', 'welcomePage', 'newUntitledFile'], + 'enumDescriptions': [ + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.none' }, "Start without an editor."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePage' }, "Open the Welcome page (default)."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file."), + ], + 'default': 'welcomePage', + 'description': localize('workbench.startupEditor', "Controls which editor is shown at startup, if none is restored from the previous session. Select 'none' to start without an editor, 'welcomePage' to open the Welcome page (default), 'newUntitledFile' to open a new untitled file (only when not opening a folder).") + }, + } + }); Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(WelcomePageContribution); diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts index 11fa510fc6457888b111280bae8c0917f5a8f00c..323050e6c26cf94b1173355b3672594e8ad96958 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts @@ -38,14 +38,12 @@ import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/com import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, foreground, descriptionForeground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { getExtraColor } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughUtils'; import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions'; -import { isWelcomePageEnabled } from 'vs/platform/telemetry/common/telemetryUtils'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IStorageService } from "vs/platform/storage/common/storage"; -import { Registry } from 'vs/platform/registry/common/platform'; used(); -const enabledKey = 'workbench.welcome.enabled'; +const configurationKey = 'workbench.startupEditor'; +const oldConfigurationKey = 'workbench.welcome.enabled'; const telemetryFrom = 'welcomePage'; export class WelcomePageContribution implements IWorkbenchContribution { @@ -59,7 +57,7 @@ export class WelcomePageContribution implements IWorkbenchContribution { @ITelemetryService telemetryService: ITelemetryService, @IStorageService storageService: IStorageService ) { - const enabled = configurationService.lookup(enabledKey).value; + const enabled = isWelcomePageEnabled(configurationService); if (enabled) { TPromise.join([ backupFileService.hasBackups(), @@ -71,20 +69,6 @@ export class WelcomePageContribution implements IWorkbenchContribution { } }).then(null, onUnexpectedError); } - - Registry.as(ConfigurationExtensions.Configuration) - .registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': localize('workbenchConfigurationTitle', "Workbench"), - 'properties': { - 'workbench.welcome.enabled': { - 'type': 'boolean', - 'default': isWelcomePageEnabled(storageService), - 'description': localize('welcomePage.enabled', "When enabled, will show the Welcome page on startup.") - }, - } - }); } public getId() { @@ -92,6 +76,17 @@ export class WelcomePageContribution implements IWorkbenchContribution { } } +function isWelcomePageEnabled(configurationService: IConfigurationService) { + const startupEditor = configurationService.lookup(configurationKey); + if (!startupEditor.user && !startupEditor.workspace) { + const welcomeEnabled = configurationService.lookup(oldConfigurationKey); + if (welcomeEnabled.value !== undefined && welcomeEnabled.value !== null) { + return welcomeEnabled.value; + } + } + return startupEditor.value === 'welcomePage'; +} + export class WelcomePageAction extends Action { public static ID = 'workbench.action.showWelcomePage'; @@ -216,13 +211,13 @@ class WelcomePage { } private onReady(container: HTMLElement, recentlyOpened: TPromise<{ files: string[]; folders: string[]; }>, installedExtensions: TPromise): void { - const enabled = this.configurationService.lookup(enabledKey).value; + const enabled = isWelcomePageEnabled(this.configurationService); const showOnStartup = container.querySelector('#showOnStartup'); if (enabled) { showOnStartup.setAttribute('checked', 'checked'); } showOnStartup.addEventListener('click', e => { - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: enabledKey, value: showOnStartup.checked }); + this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: configurationKey, value: showOnStartup.checked ? 'welcomePage' : 'newUntitledFile' }); }); recentlyOpened.then(({ folders }) => {