Change:
Code, search for "bracket pair colorizer" how it is nicely rendered as deprecated on install -notice dialog The dialog should offer a third button to configure built-in settings instead. Same if an extension had an alternative extension. Example: ! fyi
I assume you want the extra button to replicate this link in the hover tip, right? ! As an aside, any doc yet about how an extension gets tagged as deprecated?
yes, a button that will replicate that behaviour correct. No docs yet written. I plan to add them soon. The process is to write an email to us or to ping us on GitHub. In the future we will have a more straightforward approach when MP adds UI.
I feel, the third option would be a general options like More Information... clicking on this shall open the extension editor. This will be consistent and useful so that user will get enough info before taking an action
"More Information..." might work, but in order to have one less hop we could render: "Install EXTENSION_NAME Instead" "Enable Native Settings Instead" That would just do the action right straight away. I am not sure if those button names are too long. So just a suggestion. Whatever you prefer...
Yah I see your point, but going to extension editor gives user more information and an opportunity to look at the alternative extension before installing. And also I do not like that this button changes with extension. More Information... would be consistent.
That's fair. We can start with your proposal and see how it goes. My only concern with "More Information" is that the user might think it is more information about the deprecation. While we actually want to guide the user to a solution. So it is something like "More about the alternative". I am not sure if there is a good button label to represent this.
<img width="308" alt="image (1)" src="https://user-"
Changed the second button as follows ! !
Awesome!!

Discussion:
throw new ExtensionManagementError(nls.localize('malicious extension', "Can't install '{0}' extension since it was reported to be problematic.", extension.identifier.id), ExtensionManagementErrorCode.Malicious); } <del> 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); } </del> 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);

UpdateAction, ReloadAction, EnableDropDownAction, DisableDropDownAction, ExtensionStatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ToggleSyncExtensionAction, SetProductIconThemeAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, UninstallAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, <del> InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction </del> <ins> InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtension </ins> } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';

this.instantiationService.createInstance(InstallingLabelAction), this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.uninstall', UninstallAction.UninstallLabel, [ [ <ins> this.instantiationService.createInstance(MigrateDeprecatedExtension, false), </ins> this.instantiationService.createInstance(UninstallAction), this.instantiationService.createInstance(InstallAnotherVersionAction), ]

} if (this.extension.deprecationInfo) { <del> 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) { </del> <ins> 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) { </ins> return; } }

} private async computeAndUpdateEnablement(): Promise<void> { <ins> this.enabled = false; this.class = UpdateAction.DisabledClass; this.label = this.getLabel(); </ins> if (!this.extension) { <del> this.enabled = false; this.class = UpdateAction.DisabledClass; this.label = this.getLabel(); </del> <ins> return; } if (this.extension.deprecationInfo) { </ins> return; }

} } <ins> 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); } } </ins> export class ExtensionActionWithDropdownActionViewItem extends ActionWithDropdownActionViewItem { constructor(

} update(): void { <del> this.enabled = !!this.extension && !this.extension.isBuiltin && !!this.extension.gallery && !!this.extension.local && !!this.extension.server && this.extension.state === ExtensionState.Installed; </del> <ins> this.enabled = !!this.extension && !this.extension.isBuiltin && !!this.extension.gallery && !!this.extension.local && !!this.extension.server && this.extension.state === ExtensionState.Installed && !this.extension.deprecationInfo; </ins> } override async run(): Promise<any> {

.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, <ins> .monaco-action-bar .action-item.disabled .action-label.extension-action.migrate, </ins> .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,