welcomePage.ts 26.5 KB
Newer Older
C
Christof Marti 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

7
import 'vs/css!./welcomePage';
C
Christof Marti 已提交
8 9
import URI from 'vs/base/common/uri';
import * as path from 'path';
10
import * as arrays from 'vs/base/common/arrays';
11
import { WalkThroughInput } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughInput';
C
Christof Marti 已提交
12 13 14 15
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { Position } from 'vs/platform/editor/common/editor';
16
import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors';
B
Benjamin Pasero 已提交
17
import { IWindowService } from 'vs/platform/windows/common/windows';
C
Christof Marti 已提交
18 19
import { TPromise } from 'vs/base/common/winjs.base';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
20
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
C
Christof Marti 已提交
21 22
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
C
Christof Marti 已提交
23
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
24
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
25
import { Schemas } from 'vs/base/common/network';
26
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
27
import { getInstalledExtensions, IExtensionStatus, onExtensionChanged, isKeymapExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsUtils';
S
Sandeep Somavarapu 已提交
28
import { IExtensionEnablementService, IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
29
import { used } from 'vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page';
30
import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
31
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
B
Benjamin Pasero 已提交
32
import { tildify, getBaseLabel } from 'vs/base/common/labels';
C
Christof Marti 已提交
33
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
34
import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, foreground, descriptionForeground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
35
import { getExtraColor } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughUtils';
36
import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions';
B
Benjamin Pasero 已提交
37
import { IStorageService } from 'vs/platform/storage/common/storage';
B
Benjamin Pasero 已提交
38
import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
39
import { IEditorInputFactory, EditorInput } from 'vs/workbench/common/editor';
40
import { getIdAndVersionFromLocalExtensionId } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
41
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
42 43

used();
C
Christof Marti 已提交
44

45 46
const configurationKey = 'workbench.startupEditor';
const oldConfigurationKey = 'workbench.welcome.enabled';
47
const telemetryFrom = 'welcomePage';
C
Christof Marti 已提交
48 49 50 51 52 53

export class WelcomePageContribution implements IWorkbenchContribution {

	constructor(
		@IInstantiationService instantiationService: IInstantiationService,
		@IConfigurationService configurationService: IConfigurationService,
54
		@IWorkbenchEditorService editorService: IWorkbenchEditorService,
55
		@IBackupFileService backupFileService: IBackupFileService,
56
		@ITelemetryService telemetryService: ITelemetryService,
57
		@ILifecycleService lifecycleService: ILifecycleService,
58
		@IStorageService storageService: IStorageService
C
Christof Marti 已提交
59
	) {
60
		const enabled = isWelcomePageEnabled(configurationService);
61
		if (enabled && lifecycleService.startupKind !== StartupKind.ReloadedWindow) {
62
			backupFileService.hasBackups().then(hasBackups => {
63
				const activeInput = editorService.getActiveEditorInput();
C
Christof Marti 已提交
64
				if (!activeInput && !hasBackups) {
65 66
					return instantiationService.createInstance(WelcomePage)
						.openEditor();
67
				}
68
				return undefined;
C
Christof Marti 已提交
69 70 71 72 73
			}).then(null, onUnexpectedError);
		}
	}
}

74
function isWelcomePageEnabled(configurationService: IConfigurationService) {
75
	const startupEditor = configurationService.inspect(configurationKey);
76
	if (!startupEditor.user && !startupEditor.workspace) {
77
		const welcomeEnabled = configurationService.inspect(oldConfigurationKey);
78 79 80 81 82
		if (welcomeEnabled.value !== undefined && welcomeEnabled.value !== null) {
			return welcomeEnabled.value;
		}
	}
	return startupEditor.value === 'welcomePage';
83 84
}

C
Christof Marti 已提交
85 86
export class WelcomePageAction extends Action {

M
Matt Bierner 已提交
87 88
	public static readonly ID = 'workbench.action.showWelcomePage';
	public static readonly LABEL = localize('welcomePage', "Welcome");
C
Christof Marti 已提交
89 90 91 92 93 94 95 96 97 98

	constructor(
		id: string,
		label: string,
		@IInstantiationService private instantiationService: IInstantiationService
	) {
		super(id, label);
	}

	public run(): TPromise<void> {
99 100 101
		return this.instantiationService.createInstance(WelcomePage)
			.openEditor()
			.then(() => undefined);
C
Christof Marti 已提交
102 103 104
	}
}

105 106
interface ExtensionSuggestion {
	name: string;
C
Christof Marti 已提交
107
	title?: string;
108 109
	id: string;
	isKeymap?: boolean;
C
Christof Marti 已提交
110
	isCommand?: boolean;
111 112 113 114 115
}

const extensionPacks: ExtensionSuggestion[] = [
	{ name: localize('welcomePage.javaScript', "JavaScript"), id: 'dbaeumer.vscode-eslint' },
	{ name: localize('welcomePage.typeScript', "TypeScript"), id: 'eg2.tslint' },
116 117
	{ name: localize('welcomePage.python', "Python"), id: 'ms-python.python' },
	// { name: localize('welcomePage.go', "Go"), id: 'lukehoban.go' },
118
	{ name: localize('welcomePage.php', "PHP"), id: 'felixfbecker.php-pack' },
C
Christof Marti 已提交
119
	{ name: localize('welcomePage.azure', "Azure"), title: localize('welcomePage.showAzureExtensions', "Show Azure extensions"), id: 'workbench.extensions.action.showAzureExtensions', isCommand: true },
120 121 122 123 124 125 126 127 128 129 130 131
	{ name: localize('welcomePage.docker', "Docker"), id: 'PeterJausovec.vscode-docker' },
];

const keymapExtensions: ExtensionSuggestion[] = [
	{ name: localize('welcomePage.vim', "Vim"), id: 'vscodevim.vim', isKeymap: true },
	{ name: localize('welcomePage.sublime', "Sublime"), id: 'ms-vscode.sublime-keybindings', isKeymap: true },
	{ name: localize('welcomePage.atom', "Atom"), id: 'ms-vscode.atom-keybindings', isKeymap: true },
];

interface Strings {
	installEvent: string;
	installedEvent: string;
132
	detailsEvent: string;
133 134 135 136 137 138 139

	alreadyInstalled: string;
	reloadAfterInstall: string;
	installing: string;
	extensionNotFound: string;
}

K
kieferrm 已提交
140
/* __GDPR__
K
kieferrm 已提交
141 142 143 144 145 146
	"installExtension" : {
		"${include}": [
			"${WelcomePageInstall-1}"
		]
	}
*/
K
kieferrm 已提交
147
/* __GDPR__
K
kieferrm 已提交
148 149 150 151 152 153 154 155 156 157
	"installedExtension" : {
		"${include}": [
			"${WelcomePageInstalled-1}",
			"${WelcomePageInstalled-2}",
			"${WelcomePageInstalled-3}",
			"${WelcomePageInstalled-4}",
			"${WelcomePageInstalled-6}"
		]
	}
*/
K
kieferrm 已提交
158
/* __GDPR__
K
kieferrm 已提交
159 160 161 162 163 164
	"detailsExtension" : {
		"${include}": [
			"${WelcomePageDetails-1}"
		]
	}
*/
165 166 167
const extensionPackStrings: Strings = {
	installEvent: 'installExtension',
	installedEvent: 'installedExtension',
168
	detailsEvent: 'detailsExtension',
169 170

	alreadyInstalled: localize('welcomePage.extensionPackAlreadyInstalled', "Support for {0} is already installed."),
171 172
	reloadAfterInstall: localize('welcomePage.willReloadAfterInstallingExtensionPack', "The window will reload after installing additional support for {0}."),
	installing: localize('welcomePage.installingExtensionPack', "Installing additional support for {0}..."),
173 174 175
	extensionNotFound: localize('welcomePage.extensionPackNotFound', "Support for {0} with id {1} could not be found."),
};

K
kieferrm 已提交
176
/* __GDPR__
K
kieferrm 已提交
177 178 179 180 181 182
	"installKeymap" : {
		"${include}": [
			"${WelcomePageInstall-1}"
		]
	}
*/
K
kieferrm 已提交
183
/* __GDPR__
K
kieferrm 已提交
184 185 186 187 188 189 190 191 192 193
	"installedKeymap" : {
		"${include}": [
			"${WelcomePageInstalled-1}",
			"${WelcomePageInstalled-2}",
			"${WelcomePageInstalled-3}",
			"${WelcomePageInstalled-4}",
			"${WelcomePageInstalled-6}"
		]
	}
*/
K
kieferrm 已提交
194
/* __GDPR__
K
kieferrm 已提交
195 196 197 198 199 200
	"detailsKeymap" : {
		"${include}": [
			"${WelcomePageDetails-1}"
		]
	}
*/
201 202 203
const keymapStrings: Strings = {
	installEvent: 'installKeymap',
	installedEvent: 'installedKeymap',
204
	detailsEvent: 'detailsKeymap',
205 206 207 208 209 210 211

	alreadyInstalled: localize('welcomePage.keymapAlreadyInstalled', "The {0} keyboard shortcuts are already installed."),
	reloadAfterInstall: localize('welcomePage.willReloadAfterInstallingKeymap', "The window will reload after installing the {0} keyboard shortcuts."),
	installing: localize('welcomePage.installingKeymap', "Installing the {0} keyboard shortcuts..."),
	extensionNotFound: localize('welcomePage.keymapNotFound', "The {0} keyboard shortcuts with id {1} could not be found."),
};

212 213
const welcomeInputTypeId = 'workbench.editors.welcomePageInput';

C
Christof Marti 已提交
214 215
class WelcomePage {

216 217
	private disposables: IDisposable[] = [];

218 219
	readonly editorInput: WalkThroughInput;

C
Christof Marti 已提交
220 221 222 223 224 225
	constructor(
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
		@IInstantiationService private instantiationService: IInstantiationService,
		@IWindowService private windowService: IWindowService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
		@IConfigurationService private configurationService: IConfigurationService,
226
		@IEnvironmentService private environmentService: IEnvironmentService,
227
		@INotificationService private notificationService: INotificationService,
228 229 230
		@IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService,
		@IExtensionGalleryService private extensionGalleryService: IExtensionGalleryService,
		@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
231
		@IExtensionTipsService private tipsService: IExtensionTipsService,
232
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
233
		@ILifecycleService lifecycleService: ILifecycleService,
C
Christof Marti 已提交
234
		@ITelemetryService private telemetryService: ITelemetryService
C
Christof Marti 已提交
235
	) {
236
		this.disposables.push(lifecycleService.onShutdown(() => this.dispose()));
C
Christof Marti 已提交
237

B
Benjamin Pasero 已提交
238
		const recentlyOpened = this.windowService.getRecentlyOpened();
239
		const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions);
240
		const resource = URI.parse(require.toUrl('./vs_code_welcome_page'))
241 242 243 244
			.with({
				scheme: Schemas.walkThrough,
				query: JSON.stringify({ moduleId: 'vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page' })
			});
245 246 247 248 249
		this.editorInput = this.instantiationService.createInstance(WalkThroughInput, {
			typeId: welcomeInputTypeId,
			name: localize('welcome.title', "Welcome"),
			resource,
			telemetryFrom,
250
			onReady: (container: HTMLElement) => this.onReady(container, recentlyOpened, installedExtensions)
251 252 253 254
		});
	}

	public openEditor() {
255
		return this.editorService.openEditor(this.editorInput, { pinned: false }, Position.ONE);
C
Christof Marti 已提交
256 257
	}

258
	private onReady(container: HTMLElement, recentlyOpened: TPromise<{ files: string[]; workspaces: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)[]; }>, installedExtensions: TPromise<IExtensionStatus[]>): void {
259
		const enabled = isWelcomePageEnabled(this.configurationService);
C
Christof Marti 已提交
260 261 262 263 264
		const showOnStartup = <HTMLInputElement>container.querySelector('#showOnStartup');
		if (enabled) {
			showOnStartup.setAttribute('checked', 'checked');
		}
		showOnStartup.addEventListener('click', e => {
265
			this.configurationService.updateValue(configurationKey, showOnStartup.checked ? 'welcomePage' : 'newUntitledFile', ConfigurationTarget.USER);
C
Christof Marti 已提交
266 267
		});

268
		recentlyOpened.then(({ workspaces }) => {
269 270
			// Filter out the current workspace
			workspaces = workspaces.filter(workspace => !this.contextService.isCurrentWorkspace(workspace));
271
			if (!workspaces.length) {
272 273
				const recent = container.querySelector('.welcomePage') as HTMLElement;
				recent.classList.add('emptyRecent');
C
Christof Marti 已提交
274 275
				return;
			}
C
Christof Marti 已提交
276
			const ul = container.querySelector('.recent ul');
277
			const before = ul.firstElementChild;
278
			workspaces.slice(0, 5).forEach(workspace => {
B
Benjamin Pasero 已提交
279 280 281 282
				let label: string;
				let parent: string;
				let wsPath: string;
				if (isSingleFolderWorkspaceIdentifier(workspace)) {
B
Benjamin Pasero 已提交
283
					label = getBaseLabel(workspace);
B
Benjamin Pasero 已提交
284 285 286
					parent = path.dirname(workspace);
					wsPath = workspace;
				} else {
B
Benjamin Pasero 已提交
287 288
					label = getWorkspaceLabel(workspace, this.environmentService);
					parent = path.dirname(workspace.configPath);
B
Benjamin Pasero 已提交
289 290
					wsPath = workspace.configPath;
				}
291

C
Christof Marti 已提交
292 293 294
				const li = document.createElement('li');

				const a = document.createElement('a');
295 296
				let name = label;
				let parentFolder = parent;
297 298 299 300 301
				if (!name && parentFolder) {
					const tmp = name;
					name = parentFolder;
					parentFolder = tmp;
				}
C
Christof Marti 已提交
302 303
				const tildifiedParentFolder = tildify(parentFolder, this.environmentService.userHome);

C
Christof Marti 已提交
304
				a.innerText = name;
305
				a.title = label;
C
Christof Marti 已提交
306
				a.setAttribute('aria-label', localize('welcomePage.openFolderWithPath', "Open folder {0} with path {1}", name, tildifiedParentFolder));
C
Christof Marti 已提交
307 308
				a.href = 'javascript:void(0)';
				a.addEventListener('click', e => {
K
kieferrm 已提交
309
					/* __GDPR__
K
kieferrm 已提交
310 311 312 313 314
						"workbenchActionExecuted" : {
							"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
							"from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
						}
					*/
315 316 317 318
					this.telemetryService.publicLog('workbenchActionExecuted', {
						id: 'openRecentFolder',
						from: telemetryFrom
					});
B
Benjamin Pasero 已提交
319
					this.windowService.openWindow([wsPath], { forceNewWindow: e.ctrlKey || e.metaKey });
C
Christof Marti 已提交
320
					e.preventDefault();
C
Christof Marti 已提交
321
					e.stopPropagation();
C
Christof Marti 已提交
322 323 324 325 326
				});
				li.appendChild(a);

				const span = document.createElement('span');
				span.classList.add('path');
327
				span.classList.add('detail');
C
Christof Marti 已提交
328
				span.innerText = tildifiedParentFolder;
329
				span.title = label;
C
Christof Marti 已提交
330 331
				li.appendChild(span);

332
				ul.insertBefore(li, before);
C
Christof Marti 已提交
333 334
			});
		}).then(null, onUnexpectedError);
335

336 337
		this.addExtensionList(container, '.extensionPackList', extensionPacks, extensionPackStrings);
		this.addExtensionList(container, '.keymapList', keymapExtensions, keymapStrings);
338

339 340
		this.updateInstalledExtensions(container, installedExtensions);
		this.disposables.push(this.instantiationService.invokeFunction(onExtensionChanged)(ids => {
341
			for (const id of ids) {
342
				if (container.querySelector(`.installExtension[data-extension="${stripVersion(id.id)}"], .enabledExtension[data-extension="${stripVersion(id.id)}"]`)) {
343 344
					const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions);
					this.updateInstalledExtensions(container, installedExtensions);
345 346
					break;
				}
347
			}
348
		}));
349 350
	}

351 352 353 354 355 356 357 358 359 360
	private addExtensionList(container: HTMLElement, listSelector: string, suggestions: ExtensionSuggestion[], strings: Strings) {
		const list = container.querySelector(listSelector);
		if (list) {
			suggestions.forEach((extension, i) => {
				if (i) {
					list.appendChild(document.createTextNode(localize('welcomePage.extensionListSeparator', ", ")));
				}

				const a = document.createElement('a');
				a.innerText = extension.name;
C
Christof Marti 已提交
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
				a.title = extension.title || (extension.isKeymap ? localize('welcomePage.installKeymap', "Install {0} keymap", extension.name) : localize('welcomePage.installExtensionPack', "Install additional support for {0}", extension.name));
				if (extension.isCommand) {
					a.href = `command:${extension.id}`;
					list.appendChild(a);
				} else {
					a.classList.add('installExtension');
					a.setAttribute('data-extension', extension.id);
					a.href = 'javascript:void(0)';
					a.addEventListener('click', e => {
						this.installExtension(extension, strings);
						e.preventDefault();
						e.stopPropagation();
					});
					list.appendChild(a);

					const span = document.createElement('span');
					span.innerText = extension.name;
					span.title = extension.isKeymap ? localize('welcomePage.installedKeymap', "{0} keymap is already installed", extension.name) : localize('welcomePage.installedExtensionPack', "{0} support is already installed", extension.name);
					span.classList.add('enabledExtension');
					span.setAttribute('data-extension', extension.id);
					list.appendChild(span);
				}
383 384 385 386 387
			});
		}
	}

	private installExtension(extensionSuggestion: ExtensionSuggestion, strings: Strings): void {
K
kieferrm 已提交
388
		/* __GDPR__FRAGMENT__
K
kieferrm 已提交
389 390 391 392 393
			"WelcomePageInstall-1" : {
				"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
			}
		*/
394
		this.telemetryService.publicLog(strings.installEvent, {
395
			from: telemetryFrom,
396
			extensionId: extensionSuggestion.id,
397
		});
398
		this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => {
399
			const installedExtension = arrays.first(extensions, extension => stripVersion(extension.identifier.id) === extensionSuggestion.id);
400
			if (installedExtension && installedExtension.globallyEnabled) {
K
kieferrm 已提交
401
				/* __GDPR__FRAGMENT__
K
kieferrm 已提交
402 403 404 405 406 407
					"WelcomePageInstalled-1" : {
						"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
						"extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
						"outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
					}
				*/
408
				this.telemetryService.publicLog(strings.installedEvent, {
409
					from: telemetryFrom,
410
					extensionId: extensionSuggestion.id,
411 412
					outcome: 'already_enabled',
				});
413
				this.notificationService.info(strings.alreadyInstalled.replace('{0}', extensionSuggestion.name));
414 415
				return;
			}
S
Sandeep Somavarapu 已提交
416
			const foundAndInstalled = installedExtension ? TPromise.as(installedExtension.local) : this.extensionGalleryService.query({ names: [extensionSuggestion.id], source: telemetryFrom })
417 418 419
				.then(result => {
					const [extension] = result.firstPage;
					if (!extension) {
420
						return null;
421
					}
S
Sandeep Somavarapu 已提交
422
					return this.extensionManagementService.installFromGallery(extension)
S
Sandeep Somavarapu 已提交
423
						.then(local => {
424
							// TODO: Do this as part of the install to avoid multiple events.
S
Sandeep Somavarapu 已提交
425
							return this.extensionEnablementService.setEnablement(local, EnablementState.Disabled).then(() => local);
426 427
						});
				});
428

429 430 431 432 433 434
			this.notificationService.prompt(
				Severity.Info,
				strings.reloadAfterInstall.replace('{0}', extensionSuggestion.name),
				[{
					label: localize('ok', "OK"),
					run: () => {
435 436
						const messageDelay = TPromise.timeout(300);
						messageDelay.then(() => {
437
							this.notificationService.info(strings.installing.replace('{0}', extensionSuggestion.name));
438
						});
439
						TPromise.join(extensionSuggestion.isKeymap ? extensions.filter(extension => isKeymapExtension(this.tipsService, extension) && extension.globallyEnabled)
440
							.map(extension => {
S
Sandeep Somavarapu 已提交
441
								return this.extensionEnablementService.setEnablement(extension.local, EnablementState.Disabled);
442
							}) : []).then(() => {
443
								return foundAndInstalled.then(foundExtension => {
444
									messageDelay.cancel();
445 446
									if (foundExtension) {
										return this.extensionEnablementService.setEnablement(foundExtension, EnablementState.Enabled)
447
											.then(() => {
K
kieferrm 已提交
448
												/* __GDPR__FRAGMENT__
K
kieferrm 已提交
449 450 451 452 453 454
													"WelcomePageInstalled-2" : {
														"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
														"extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
														"outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
													}
												*/
455
												this.telemetryService.publicLog(strings.installedEvent, {
456
													from: telemetryFrom,
457 458
													extensionId: extensionSuggestion.id,
													outcome: installedExtension ? 'enabled' : 'installed',
459
												});
460 461
												return this.windowService.reloadWindow();
											});
462
									} else {
K
kieferrm 已提交
463
										/* __GDPR__FRAGMENT__
K
kieferrm 已提交
464 465 466 467 468 469
											"WelcomePageInstalled-3" : {
												"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
												"extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
												"outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
											}
										*/
470
										this.telemetryService.publicLog(strings.installedEvent, {
471
											from: telemetryFrom,
472
											extensionId: extensionSuggestion.id,
473 474
											outcome: 'not_found',
										});
475
										this.notificationService.error(strings.extensionNotFound.replace('{0}', extensionSuggestion.name).replace('{1}', extensionSuggestion.id));
476 477 478
										return undefined;
									}
								});
479
							}).then(null, err => {
K
kieferrm 已提交
480
								/* __GDPR__FRAGMENT__
K
kieferrm 已提交
481 482 483 484
									"WelcomePageInstalled-4" : {
										"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
										"extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
										"outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
485
										"error": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }
K
kieferrm 已提交
486 487
									}
								*/
488
								this.telemetryService.publicLog(strings.installedEvent, {
489
									from: telemetryFrom,
490
									extensionId: extensionSuggestion.id,
491 492 493
									outcome: isPromiseCanceledError(err) ? 'canceled' : 'error',
									error: String(err),
								});
494
								this.notificationService.error(err);
495
							});
496 497 498 499
					}
				}, {
					label: localize('details', "Details"),
					run: () => {
K
kieferrm 已提交
500
						/* __GDPR__FRAGMENT__
K
kieferrm 已提交
501 502 503 504 505
							"WelcomePageDetails-1" : {
								"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
								"extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
							}
						*/
506 507 508 509 510 511 512
						this.telemetryService.publicLog(strings.detailsEvent, {
							from: telemetryFrom,
							extensionId: extensionSuggestion.id,
						});
						this.extensionsWorkbenchService.queryGallery({ names: [extensionSuggestion.id] })
							.then(result => this.extensionsWorkbenchService.open(result.firstPage[0]))
							.then(null, onUnexpectedError);
513 514 515
					}
				}]
			);
R
Ron Buckton 已提交
516
		}).then(null, err => {
K
kieferrm 已提交
517
			/* __GDPR__FRAGMENT__
K
kieferrm 已提交
518 519 520 521
				"WelcomePageInstalled-6" : {
					"from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
					"extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
					"outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
522
					"error": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }
K
kieferrm 已提交
523 524
				}
			*/
525
			this.telemetryService.publicLog(strings.installedEvent, {
526
				from: telemetryFrom,
527
				extensionId: extensionSuggestion.id,
528 529 530
				outcome: isPromiseCanceledError(err) ? 'canceled' : 'error',
				error: String(err),
			});
531
			this.notificationService.error(err);
532
		});
C
Christof Marti 已提交
533
	}
534

535 536 537
	private updateInstalledExtensions(container: HTMLElement, installedExtensions: TPromise<IExtensionStatus[]>) {
		installedExtensions.then(extensions => {
			const elements = container.querySelectorAll('.installExtension, .enabledExtension');
538 539 540 541
			for (let i = 0; i < elements.length; i++) {
				elements[i].classList.remove('installed');
			}
			extensions.filter(ext => ext.globallyEnabled)
542
				.map(ext => stripVersion(ext.identifier.id))
543
				.forEach(id => {
544 545 546
					const install = container.querySelectorAll(`.installExtension[data-extension="${id}"]`);
					for (let i = 0; i < install.length; i++) {
						install[i].classList.add('installed');
547
					}
548 549 550
					const enabled = container.querySelectorAll(`.enabledExtension[data-extension="${id}"]`);
					for (let i = 0; i < enabled.length; i++) {
						enabled[i].classList.add('installed');
551 552 553 554 555 556 557 558
					}
				});
		}).then(null, onUnexpectedError);
	}

	dispose(): void {
		this.disposables = dispose(this.disposables);
	}
C
Christof Marti 已提交
559
}
560

561 562 563 564
function stripVersion(id: string): string {
	return getIdAndVersionFromLocalExtensionId(id).id;
}

565 566 567

export class WelcomeInputFactory implements IEditorInputFactory {

568
	static readonly ID = welcomeInputTypeId;
569 570 571 572 573 574 575 576 577 578 579

	public serialize(editorInput: EditorInput): string {
		return '{}';
	}

	public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): WalkThroughInput {
		return instantiationService.createInstance(WelcomePage)
			.editorInput;
	}
}

580 581
// theming

C
Christof Marti 已提交
582 583
const buttonBackground = registerColor('welcomePage.buttonBackground', { dark: null, light: null, hc: null }, localize('welcomePage.buttonBackground', 'Background color for the buttons on the Welcome page.'));
const buttonHoverBackground = registerColor('welcomePage.buttonHoverBackground', { dark: null, light: null, hc: null }, localize('welcomePage.buttonHoverBackground', 'Hover background color for the buttons on the Welcome page.'));
584 585

registerThemingParticipant((theme, collector) => {
C
Christof Marti 已提交
586 587 588
	const foregroundColor = theme.getColor(foreground);
	if (foregroundColor) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage .caption { color: ${foregroundColor}; }`);
589
	}
C
Christof Marti 已提交
590 591 592
	const descriptionColor = theme.getColor(descriptionForeground);
	if (descriptionColor) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage .detail { color: ${descriptionColor}; }`);
593
	}
C
Christof Marti 已提交
594 595 596
	const buttonColor = getExtraColor(theme, buttonBackground, { dark: 'rgba(0, 0, 0, .2)', extra_dark: 'rgba(200, 235, 255, .042)', light: 'rgba(0,0,0,.04)', hc: 'black' });
	if (buttonColor) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage .commands li button { background: ${buttonColor}; }`);
597
	}
C
Christof Marti 已提交
598 599 600
	const buttonHoverColor = getExtraColor(theme, buttonHoverBackground, { dark: 'rgba(200, 235, 255, .072)', extra_dark: 'rgba(200, 235, 255, .072)', light: 'rgba(0,0,0,.10)', hc: null });
	if (buttonHoverColor) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage .commands li button:hover { background: ${buttonHoverColor}; }`);
601
	}
602 603 604 605
	const link = theme.getColor(textLinkForeground);
	if (link) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage a { color: ${link}; }`);
	}
606 607 608 609 610
	const activeLink = theme.getColor(textLinkActiveForeground);
	if (activeLink) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage a:hover,
			.monaco-workbench > .part.editor > .content .welcomePage a:active { color: ${activeLink}; }`);
	}
611 612 613 614
	const focusColor = theme.getColor(focusBorder);
	if (focusColor) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage a:focus { outline-color: ${focusColor}; }`);
	}
615 616 617 618 619 620 621 622
	const border = theme.getColor(contrastBorder);
	if (border) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage .commands li button { border-color: ${border}; }`);
	}
	const activeBorder = theme.getColor(activeContrastBorder);
	if (activeBorder) {
		collector.addRule(`.monaco-workbench > .part.editor > .content .welcomePage .commands li button:hover { outline-color: ${activeBorder}; }`);
	}
623
});