Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extension Badge represents number of outdated and reloadrequired extensions #161046

Merged
merged 16 commits into from
Sep 21, 2022
Merged
135 changes: 8 additions & 127 deletions src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1483,31 +1483,22 @@ export class ReloadAction extends ExtensionAction {
private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`;

updateWhenCounterExtensionChanges: boolean = true;
private _runningExtensions: IExtensionDescription[] | null = null;

constructor(
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IHostService private readonly hostService: IHostService,
@IExtensionService private readonly extensionService: IExtensionService,
@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@IProductService productService: IProductService,
@IConfigurationService configurationService: IConfigurationService,
) {
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
this.updateRunningExtensions();
}

private updateRunningExtensions(): void {
this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
this._register(this.extensionService.onDidChangeExtensions(this.update));
this.update();
}

update(): void {
this.enabled = false;
this.tooltip = '';
if (!this.extension || !this._runningExtensions) {
if (!this.extension) {
return;
}
const state = this.extension.state;
Expand All @@ -1517,123 +1508,13 @@ export class ReloadAction extends ExtensionAction {
if (this.extension.local && this.extension.local.manifest && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.localizations && this.extension.local.manifest.contributes.localizations.length > 0) {
return;
}
this.computeReloadState();
this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass;
}

private computeReloadState(): void {
if (!this._runningExtensions || !this.extension) {
return;
}

const isUninstalled = this.extension.state === ExtensionState.Uninstalled;
const runningExtension = this._runningExtensions.find(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier));

if (isUninstalled) {
const canRemoveRunningExtension = runningExtension && this.extensionService.canRemoveExtension(runningExtension);
const isSameExtensionRunning = runningExtension && (!this.extension.server || this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)));
if (!canRemoveRunningExtension && isSameExtensionRunning) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postUninstallTooltip', "Please reload Visual Studio Code to complete the uninstallation of this extension.");
alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension.displayName));
}
return;
}
if (this.extension.local) {
const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension));
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
const reloadTooltip = this.extension.reloadRequiredStatus;
this.enabled = reloadTooltip !== undefined;
this.label = reloadTooltip !== undefined ? localize('reload required', 'Reload Required') : '';
this.tooltip = reloadTooltip !== undefined ? reloadTooltip : '';

// Extension is running
if (runningExtension) {
if (isEnabled) {
// No Reload is required if extension can run without reload
if (this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
return;
}
const runningExtensionServer = this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension));

if (isSameExtensionRunning) {
// Different version or target platform of same extension is running. Requires reload to run the current version
if (this.extension.version !== runningExtension.version || this.extension.local.targetPlatform !== runningExtension.targetPlatform) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postUpdateTooltip', "Please reload Visual Studio Code to enable the updated extension.");
return;
}

const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)[0];
if (extensionInOtherServer) {
// This extension prefers to run on UI/Local side but is running in remote
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(this.extension.local!.manifest)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('enable locally', "Please reload Visual Studio Code to enable this extension locally.");
return;
}

// This extension prefers to run on Workspace/Remote side but is running in local
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(this.extension.local!.manifest)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('enable remote', "Please reload Visual Studio Code to enable this extension in {0}.", this.extensionManagementServerService.remoteExtensionManagementServer?.label);
return;
}
}

} else {

if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
// This extension prefers to run on UI/Local side but is running in remote
if (this.extensionManifestPropertiesService.prefersExecuteOnUI(this.extension.local!.manifest)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
}
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
// This extension prefers to run on Workspace/Remote side but is running in local
if (this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(this.extension.local!.manifest)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
}
}
}
return;
} else {
if (isSameExtensionRunning) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postDisableTooltip', "Please reload Visual Studio Code to disable this extension.");
}
}
return;
}

// Extension is not running
else {
if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
return;
}

const otherServer = this.extension.server ? this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer : null;
if (otherServer && this.extension.enablementState === EnablementState.DisabledByExtensionKind) {
const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === otherServer)[0];
// Same extension in other server exists and
if (extensionInOtherServer && extensionInOtherServer.local && this.extensionEnablementService.isEnabled(extensionInOtherServer.local)) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
alert(localize('installExtensionCompletedAndReloadRequired', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName));
return;
}
}
}
}
this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass;
}

override run(): Promise<any> {
Expand Down
10 changes: 6 additions & 4 deletions src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -803,12 +803,14 @@ export class StatusUpdater extends Disposable implements IWorkbenchContribution
this._register(extensionsWorkbenchService.onChange(this.onServiceChange, this));
}

private onServiceChange(): void {
private async onServiceChange(): Promise<void> {
this.badgeHandle.clear();

const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0);
if (outdated > 0) {
const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n));
const extensionsReloadRequired = this.extensionsWorkbenchService.installed.filter(e => e.reloadRequiredStatus !== undefined);
const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) && !extensionsReloadRequired.includes(e) ? 1 : 0), 0);
const newBadgeNumber = outdated + extensionsReloadRequired.length;
if (newBadgeNumber > 0) {
const badge = new NumberBadge(newBadgeNumber, n => localize('outdatedExtensions', '{0} Outdated Extensions', n));
benibenj marked this conversation as resolved.
Show resolved Hide resolved
this.badgeHandle.value = this.activityService.showViewContainerActivity(VIEWLET_ID, { badge, clazz: 'extensions-badge count-badge' });
}
}
Expand Down