Skip to content

Show extension installation progress in the Extensions view - #328563

Draft
cj (erhsh) wants to merge 1 commit into
microsoft:mainfrom
erhsh:feature/extension-install-progress
Draft

Show extension installation progress in the Extensions view#328563
cj (erhsh) wants to merge 1 commit into
microsoft:mainfrom
erhsh:feature/extension-install-progress

Conversation

@erhsh

@erhsh cj (erhsh) commented Aug 1, 2026

Copy link
Copy Markdown

Summary

Extension installation can appear to be stuck when downloading a large VSIX or when later installation steps take time. This change surfaces internal installation progress in the Extensions view so users can tell what VS Code is doing.

Fixes #328551

The extension card now reports the following stages:

  • Downloading N% when the Marketplace response provides a valid content length
  • Downloading when the total size is unknown
  • Verifying
  • Extracting
  • Installing

Implementation

  • Count bytes while streaming Marketplace VSIX downloads and throttle progress notifications to avoid excessive UI updates.
  • Propagate download progress and installation stages through the extension management service and remote IPC channel.
  • Track progress per installing extension in the workbench and update the existing installing label with localized stage text.
  • Keep the change internal; it does not add or change the public extension API.

User impact

Users get immediate feedback during slow extension installs and can distinguish network download time from signature verification, extraction, and final profile installation.

Verification

  • npm run typecheck-client -- --pretty false
  • Targeted ESLint validation for the modified extension management and workbench files
  • npm run gulp compile-client
  • Added coverage for downloading percentage, verification, and extraction labels in InstallingLabelAction

The targeted Electron UI test could not be executed in this environment because downloading the Electron test runtime from GitHub timed out. Type checking, linting, and core client compilation completed successfully.

How to test

  1. Open the Extensions view.
  2. Install a large extension that is not already present in the download cache.
  3. Confirm that its card transitions through the applicable progress labels.
  4. Confirm that downloads without a valid Content-Length show Downloading without a fabricated percentage.
  5. Repeat in a Remote window and confirm that progress from the remote extension host reaches the client UI.

Copilot AI review requested due to automatic review settings August 1, 2026 15:00
@erhsh

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

Remote/profile progress handling, accessibility, shared-download concurrency, header validation, and test doubles need correction.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Adds staged extension-install progress to the Extensions view, including remote IPC propagation.

Changes:

  • Tracks and throttles VSIX download progress.
  • Propagates installation stages through extension-management services.
  • Displays localized progress labels with targeted action tests.
File summaries
File Description
src/vs/workbench/test/browser/workbenchTestServices.ts Adds the progress event to a test service.
src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts Multiplexes server progress events.
src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts Tests staged labels.
src/vs/workbench/contrib/extensions/common/extensions.ts Exposes progress on workbench extensions.
src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts Tracks per-extension progress.
src/vs/workbench/contrib/extensions/browser/extensionsActions.ts Renders localized stage labels.
src/vs/platform/extensionManagement/node/extensionManagementService.ts Reports extraction and installation stages.
src/vs/platform/extensionManagement/node/extensionDownloader.ts Reports download and verification stages.
src/vs/platform/extensionManagement/common/extensionManagementIpc.ts Transports progress over IPC.
src/vs/platform/extensionManagement/common/extensionManagement.ts Defines progress contracts.
src/vs/platform/extensionManagement/common/extensionGalleryService.ts Counts streamed download bytes.
src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts Emits task progress events.
Review details

Suppressed comments (1)

src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts:655

  • The remote local-download path cannot reach this match. When remote.downloadExtensionsLocally is enabled, or remote download falls back locally, NativeRemoteExtensionManagementService downloads via the local service and then calls super.install(location); that emits a URI-sourced install, which onInstallExtension at lines 815-823 does not add to this.installing. Consequently its extraction/install progress is discarded here, while the preceding local download also has no install-progress callback, so the card remains at generic “Installing” for the entire fallback. Associate that gallery install with the tracked extension and forward its local download progress.
	private onInstallExtensionProgress(event: InstallExtensionProgressEvent): void {
		const extension = this.installing.find(extension => areSameExtensions(extension.identifier, event.identifier));
  • Files reviewed: 12/12 changed files
  • Comments generated: 5
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

) {
super();
this._register(server.extensionManagementService.onInstallExtension(e => this.onInstallExtension(e)));
this._register(server.extensionManagementService.onInstallExtensionProgress(e => this.onInstallExtensionProgress(e)));
Comment on lines +657 to +658
extension.installProgress = event;
this._onChange.fire({ extension });
) {
super(productService, allowedExtensionsService);
this._register(this.channel.listen<InstallExtensionEvent>('onInstallExtension')(e => this.onInstallExtensionEvent({ ...e, source: this.isUriComponents(e.source) ? URI.revive(e.source) : e.source, profileLocation: URI.revive(e.profileLocation) })));
this._register(this.channel.listen<InstallExtensionProgressEvent>('onInstallExtensionProgress')(e => this._onInstallExtensionProgress.fire({ ...e, profileLocation: URI.revive(e.profileLocation) })));
Comment on lines 289 to 294
let promise = this.extractingGalleryExtensions.get(extensionKey.toString());
if (!promise) {
this.extractingGalleryExtensions.set(extensionKey.toString(), promise = this.downloadAndExtractGalleryExtension(extensionKey, extension, operation, options, token));
this.extractingGalleryExtensions.set(extensionKey.toString(), promise = this.downloadAndExtractGalleryExtension(extensionKey, extension, operation, options, token, progress));
promise.finally(() => this.extractingGalleryExtensions.delete(extensionKey.toString()));
}
return promise;
Comment on lines +1707 to +1708
const parsedTotalBytes = Number(context.res.headers['content-length']);
const totalBytes = Number.isFinite(parsedTotalBytes) && parsedTotalBytes >= 0 ? parsedTotalBytes : undefined;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show download and installation progress when installing extension

3 participants