Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,6 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
throw new ExtensionManagementError(nls.localize('malicious extension', "Can't install '{0}' extension since it was reported to be problematic.", extension.identifier.id), ExtensionManagementErrorCode.Malicious);
}

const deprecated = report.deprecated[extension.identifier.id.toLowerCase()];
if (deprecated?.disallowInstall) {
const message = deprecated.extension ? nls.localize('unsupported extension with alternative', "Can't install '{0}' extension because it is deprecated. Use {1} extension instead.", extension.identifier.id, deprecated.extension.displayName)
: nls.localize('unsupported extension without alternative and no message', "Can't install '{0}' extension because it is deprecated.", extension.identifier.id);
throw new ExtensionManagementError(message, ExtensionManagementErrorCode.Deprecated);
}

if (!await this.canInstall(extension)) {
const targetPlatform = await this.getTargetPlatform();
throw new ExtensionManagementError(nls.localize('incompatible platform', "The '{0}' extension is not available in {1} for {2}.", extension.identifier.id, this.productService.nameLong, TargetPlatformToString(targetPlatform)), ExtensionManagementErrorCode.IncompatibleTargetPlatform);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
UpdateAction, ReloadAction, EnableDropDownAction, DisableDropDownAction, ExtensionStatusLabelAction, SetFileIconThemeAction, SetColorThemeAction,
RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ToggleSyncExtensionAction, SetProductIconThemeAction,
ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, UninstallAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction,
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtension
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
Expand Down Expand Up @@ -338,6 +338,7 @@ export class ExtensionEditor extends EditorPane {
this.instantiationService.createInstance(InstallingLabelAction),
this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.uninstall', UninstallAction.UninstallLabel, [
[
this.instantiationService.createInstance(MigrateDeprecatedExtension, false),
this.instantiationService.createInstance(UninstallAction),
this.instantiationService.createInstance(InstallAnotherVersionAction),
]
Expand Down
81 changes: 70 additions & 11 deletions src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,22 @@ export abstract class AbstractInstallAction extends ExtensionAction {
}

if (this.extension.deprecationInfo) {
const result = await this.dialogService.confirm({
type: 'warning',
message: localize('install confirmation', "Are you sure you want to install '{0}'?", this.extension.displayName),
detail: localize('deprecated message', "This extension is no longer being maintained and is deprecated."),
primaryButton: localize('install anyway', "Install Anyway"),
});
if (!result.confirmed) {
const result = await this.dialogService.show(
Severity.Warning,
localize('install confirmation', "Are you sure you want to install '{0}'?", this.extension.displayName),
[
localize('install anyway', "Install Anyway"),
localize('open extension', "Open Extension"),
localize('cancel', "Cancel"),
],
{
detail: localize('deprecated message', "This extension is no longer being maintained and is deprecated."),
cancelId: 2,
});
if (result.choice === 1) {
return this.extensionsWorkbenchService.open(this.extension, { showPreReleaseVersion: this.installPreReleaseVersion });
}
if (result.choice === 2) {
return;
}
}
Expand Down Expand Up @@ -757,10 +766,15 @@ export class UpdateAction extends ExtensionAction {
}

private async computeAndUpdateEnablement(): Promise<void> {
this.enabled = false;
this.class = UpdateAction.DisabledClass;
this.label = this.getLabel();

if (!this.extension) {
this.enabled = false;
this.class = UpdateAction.DisabledClass;
this.label = this.getLabel();
return;
}

if (this.extension.deprecationInfo) {
return;
}

Expand Down Expand Up @@ -800,6 +814,51 @@ export class UpdateAction extends ExtensionAction {
}
}

export class MigrateDeprecatedExtension extends ExtensionAction {

private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} prominent migrate`;
private static readonly DisabledClass = `${MigrateDeprecatedExtension.EnabledClass} disabled`;

constructor(
private readonly small: boolean,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
) {
super('extensions.uninstall', localize('migrateExtension', "Migrate"), MigrateDeprecatedExtension.DisabledClass, false);
this.update();
}

update(): void {
this.enabled = false;
this.class = MigrateDeprecatedExtension.DisabledClass;
if (!this.extension?.local) {
return;
}
if (this.extension.state !== ExtensionState.Installed) {
return;
}
if (!this.extension.deprecationInfo?.extension) {
return;
}
const id = this.extension.deprecationInfo.extension.id;
if (this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, { id }))) {
return;
}
this.enabled = true;
this.class = MigrateDeprecatedExtension.EnabledClass;
this.tooltip = localize('migrate to', "Migrate to {0}", this.extension.deprecationInfo.extension.displayName);
this.label = this.small ? localize('migrate', "Migrate") : this.tooltip;
}

override async run(): Promise<any> {
if (!this.extension?.deprecationInfo?.extension) {
return;
}
await this.extensionsWorkbenchService.uninstall(this.extension);
const [extension] = await this.extensionsWorkbenchService.getExtensions([{ id: this.extension.deprecationInfo.extension.id, preRelease: this.extension.deprecationInfo?.extension?.preRelease }], CancellationToken.None);
await this.extensionsWorkbenchService.install(extension);
}
}

export class ExtensionActionWithDropdownActionViewItem extends ActionWithDropdownActionViewItem {

constructor(
Expand Down Expand Up @@ -1138,7 +1197,7 @@ export class InstallAnotherVersionAction extends ExtensionAction {
}

update(): void {
this.enabled = !!this.extension && !this.extension.isBuiltin && !!this.extension.gallery && !!this.extension.local && !!this.extension.server && this.extension.state === ExtensionState.Installed;
this.enabled = !!this.extension && !this.extension.isBuiltin && !!this.extension.gallery && !!this.extension.local && !!this.extension.server && this.extension.state === ExtensionState.Installed && !this.extension.deprecationInfo;
}

override async run(): Promise<any> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
.monaco-action-bar .action-item.disabled .action-label.extension-action.uninstall:not(.uninstalling),
.monaco-action-bar .action-item.disabled .action-label.extension-action.hide-when-disabled,
.monaco-action-bar .action-item.disabled .action-label.extension-action.update,
.monaco-action-bar .action-item.disabled .action-label.extension-action.migrate,
.monaco-action-bar .action-item.disabled .action-label.extension-action.theme,
.monaco-action-bar .action-item.disabled .action-label.extension-action.extension-sync,
.monaco-action-bar .action-item.action-dropdown-item.disabled,
Expand Down