diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 38a17acbbf0..c456dfa178b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -49,11 +49,11 @@ import { IEditorOpenContext } from 'vs/workbench/common/editor'; import { ViewContainerLocation } from 'vs/workbench/common/views'; import { ExtensionFeaturesTab } from 'vs/workbench/contrib/extensions/browser/extensionFeaturesTab'; import { - ActionWithDropDownAction, + ButtonWithDropDownExtensionAction, ClearLanguageAction, DisableDropDownAction, EnableDropDownAction, - ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, + ButtonWithDropdownExtensionActionViewItem, DropDownExtensionAction, ExtensionEditorManageExtensionAction, ExtensionStatusAction, ExtensionStatusLabelAction, @@ -71,7 +71,8 @@ import { UninstallAction, UpdateAction, WebInstallAction, - TogglePreReleaseExtensionAction + TogglePreReleaseExtensionAction, + ExtensionAction, } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { Delegate } from 'vs/workbench/contrib/extensions/browser/extensionsList'; import { ExtensionData, ExtensionsGridView, ExtensionsTree, getExtensions } from 'vs/workbench/contrib/extensions/browser/extensionsViewer'; @@ -333,7 +334,7 @@ export class ExtensionEditor extends EditorPane { const actions = [ this.instantiationService.createInstance(ExtensionRuntimeStateAction), this.instantiationService.createInstance(ExtensionStatusLabelAction), - this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '', + this.instantiationService.createInstance(ButtonWithDropDownExtensionAction, 'extensions.updateActions', ExtensionAction.PROMINENT_LABEL_ACTION_CLASS, [[this.instantiationService.createInstance(UpdateAction, true)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, true, [true, 'onlyEnabledExtensions'])]]), this.instantiationService.createInstance(SetColorThemeAction), this.instantiationService.createInstance(SetFileIconThemeAction), @@ -348,7 +349,7 @@ export class ExtensionEditor extends EditorPane { this.instantiationService.createInstance(WebInstallAction), installAction, this.instantiationService.createInstance(InstallingLabelAction), - this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.uninstall', UninstallAction.UninstallLabel, [ + this.instantiationService.createInstance(ButtonWithDropDownExtensionAction, 'extensions.uninstall', ExtensionAction.LABEL_ACTION_CLASS, [ [ this.instantiationService.createInstance(MigrateDeprecatedExtensionAction, false), this.instantiationService.createInstance(UninstallAction), @@ -363,11 +364,20 @@ export class ExtensionEditor extends EditorPane { const actionsAndStatusContainer = append(details, $('.actions-status-container')); const extensionActionBar = this._register(new ActionBar(actionsAndStatusContainer, { actionViewItemProvider: (action: IAction, options) => { - if (action instanceof ExtensionDropDownAction) { + if (action instanceof DropDownExtensionAction) { return action.createActionViewItem(options); } - if (action instanceof ActionWithDropDownAction) { - return new ExtensionActionWithDropdownActionViewItem(action, { ...options, icon: true, label: true, menuActionsOrProvider: { getActions: () => action.menuActions }, menuActionClassNames: (action.class || '').split(' ') }, this.contextMenuService); + if (action instanceof ButtonWithDropDownExtensionAction) { + return new ButtonWithDropdownExtensionActionViewItem( + action, + { + ...options, + icon: true, + label: true, + menuActionsOrProvider: { getActions: () => action.menuActions }, + menuActionClassNames: action.menuActionClassNames + }, + this.contextMenuService); } if (action instanceof ToggleAutoUpdateForExtensionAction) { return new CheckboxActionViewItem(undefined, action, { ...options, icon: true, label: true, checkboxStyles: defaultCheckboxStyles }); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index fc174208ee6..cace69aee5b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/extensionActions'; import { localize, localize2 } from 'vs/nls'; -import { IAction, Action, Separator, SubmenuAction } from 'vs/base/common/actions'; +import { IAction, Action, Separator, SubmenuAction, IActionChangeEvent } from 'vs/base/common/actions'; import { Delayer, Promises, Throttler } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { Emitter, Event } from 'vs/base/common/event'; @@ -52,7 +52,6 @@ import { IActionViewItemOptions, ActionViewItem } from 'vs/base/browser/ui/actio import { EXTENSIONS_CONFIG, IExtensionsConfigContent } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig'; import { getErrorMessage, isCancellationError } from 'vs/base/common/errors'; import { IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; -import { ActionWithDropdownActionViewItem, IActionWithDropdownActionViewItemOptions } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; import { IContextMenuProvider } from 'vs/base/browser/contextmenu'; import { ILogService } from 'vs/platform/log/common/log'; import { errorIcon, infoIcon, manageExtensionIcon, syncEnabledIcon, syncIgnoredIcon, trustIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; @@ -73,6 +72,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Extensions, IExtensionFeaturesManagementService, IExtensionFeaturesRegistry } from 'vs/workbench/services/extensionManagement/common/extensionFeatures'; import { Registry } from 'vs/platform/registry/common/platform'; import { IUpdateService } from 'vs/platform/update/common/update'; +import { ActionWithDropdownActionViewItem, IActionWithDropdownActionViewItemOptions } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; export class PromptExtensionInstallFailureAction extends Action { @@ -216,21 +216,52 @@ export class PromptExtensionInstallFailureAction extends Action { } +export interface IExtensionActionChangeEvent extends IActionChangeEvent { + readonly hidden?: boolean; + readonly menuActions?: IAction[]; +} + export abstract class ExtensionAction extends Action implements IExtensionContainer { + + protected override _onDidChange = this._register(new Emitter()); + override readonly onDidChange = this._onDidChange.event; + static readonly EXTENSION_ACTION_CLASS = 'extension-action'; static readonly TEXT_ACTION_CLASS = `${ExtensionAction.EXTENSION_ACTION_CLASS} text`; static readonly LABEL_ACTION_CLASS = `${ExtensionAction.EXTENSION_ACTION_CLASS} label`; + static readonly PROMINENT_LABEL_ACTION_CLASS = `${ExtensionAction.LABEL_ACTION_CLASS} prominent`; static readonly ICON_ACTION_CLASS = `${ExtensionAction.EXTENSION_ACTION_CLASS} icon`; + private _extension: IExtension | null = null; get extension(): IExtension | null { return this._extension; } set extension(extension: IExtension | null) { this._extension = extension; this.update(); } + + private _hidden: boolean = false; + get hidden(): boolean { return this._hidden; } + set hidden(hidden: boolean) { + if (this._hidden !== hidden) { + this._hidden = hidden; + this._onDidChange.fire({ hidden }); + } + } + + protected override _setEnabled(value: boolean): void { + super._setEnabled(value); + if (this.hideOnDisabled) { + this.hidden = !value; + } + } + + protected hideOnDisabled: boolean = true; + abstract update(): void; } -export class ActionWithDropDownAction extends ExtensionAction { +export class ButtonWithDropDownExtensionAction extends ExtensionAction { - private action: IAction | undefined; + private primaryAction: IAction | undefined; + readonly menuActionClassNames: string[] = []; private _menuActions: IAction[] = []; get menuActions(): IAction[] { return [...this._menuActions]; } @@ -246,10 +277,14 @@ export class ActionWithDropDownAction extends ExtensionAction { protected readonly extensionActions: ExtensionAction[]; constructor( - id: string, label: string, + id: string, + clazz: string, private readonly actionsGroups: ExtensionAction[][], ) { - super(id, label); + clazz = `${clazz} action-dropdown`; + super(id, undefined, clazz); + this.menuActionClassNames = clazz.split(' '); + this.hideOnDisabled = false; this.extensionActions = actionsGroups.flat(); this.update(); this._register(Event.any(...this.extensionActions.map(a => a.onDidChange))(() => this.update(true))); @@ -261,36 +296,35 @@ export class ActionWithDropDownAction extends ExtensionAction { this.extensionActions.forEach(a => a.update()); } - const enabledActionsGroups = this.actionsGroups.map(actionsGroup => actionsGroup.filter(a => a.enabled)); + const actionsGroups = this.actionsGroups.map(actionsGroup => actionsGroup.filter(a => !a.hidden)); let actions: IAction[] = []; - for (const enabledActions of enabledActionsGroups) { - if (enabledActions.length) { - actions = [...actions, ...enabledActions, new Separator()]; + for (const visibleActions of actionsGroups) { + if (visibleActions.length) { + actions = [...actions, ...visibleActions, new Separator()]; } } actions = actions.length ? actions.slice(0, actions.length - 1) : actions; - this.action = actions[0]; + this.primaryAction = actions[0]; this._menuActions = actions.length > 1 ? actions : []; + this._onDidChange.fire({ menuActions: this._menuActions }); - this.enabled = !!this.action; - if (this.action) { - this.label = this.getLabel(this.action as ExtensionAction); - this.tooltip = this.action.tooltip; + if (this.primaryAction) { + this.hidden = false; + this.enabled = this.primaryAction.enabled; + this.label = this.getLabel(this.primaryAction as ExtensionAction); + this.tooltip = this.primaryAction.tooltip; + } else { + this.hidden = true; + this.enabled = false; } - - let clazz = (this.action || this.extensionActions[0])?.class || ''; - clazz = clazz ? `${clazz} action-dropdown` : 'action-dropdown'; - if (this._menuActions.length === 0) { - clazz += ' action-dropdown'; - } - this.class = clazz; } - override run(): Promise { - const enabledActions = this.extensionActions.filter(a => a.enabled); - return enabledActions[0].run(); + override async run(): Promise { + if (this.enabled) { + await this.primaryAction?.run(); + } } protected getLabel(action: ExtensionAction): string { @@ -298,9 +332,42 @@ export class ActionWithDropDownAction extends ExtensionAction { } } +export class ButtonWithDropdownExtensionActionViewItem extends ActionWithDropdownActionViewItem { + + constructor( + action: ButtonWithDropDownExtensionAction, + options: IActionViewItemOptions & IActionWithDropdownActionViewItemOptions, + contextMenuProvider: IContextMenuProvider + ) { + super(null, action, options, contextMenuProvider); + this._register(action.onDidChange(e => { + if (e.hidden !== undefined || e.menuActions !== undefined) { + this.updateClass(); + } + })); + } + + override render(container: HTMLElement): void { + super.render(container); + this.updateClass(); + } + + protected override updateClass(): void { + super.updateClass(); + if (this.element && this.dropdownMenuActionViewItem?.element) { + this.element.classList.toggle('hide', (this._action).hidden); + const isMenuEmpty = (this._action).menuActions.length === 0; + this.element.classList.toggle('empty', isMenuEmpty); + this.dropdownMenuActionViewItem.element.classList.toggle('hide', isMenuEmpty); + } + } + +} + export class InstallAction extends ExtensionAction { - static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} prominent install`; + private static readonly CLASS = `${ExtensionAction.LABEL_ACTION_CLASS} prominent install`; + private static readonly HIDE = `${InstallAction.CLASS} hide`; protected _manifest: IExtensionManifest | null = null; set manifest(manifest: IExtensionManifest | null) { @@ -323,7 +390,8 @@ export class InstallAction extends ExtensionAction { @ITelemetryService private readonly telemetryService: ITelemetryService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, ) { - super('extensions.install', localize('install', "Install"), InstallAction.Class, false); + super('extensions.install', localize('install', "Install"), InstallAction.CLASS, false); + this.hideOnDisabled = false; this.options = { ...options, isMachineScoped: false }; this.update(); this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this)); @@ -335,6 +403,8 @@ export class InstallAction extends ExtensionAction { protected async computeAndUpdateEnablement(): Promise { this.enabled = false; + this.class = InstallAction.HIDE; + this.hidden = true; if (!this.extension) { return; } @@ -344,8 +414,19 @@ export class InstallAction extends ExtensionAction { if (this.extensionsWorkbenchService.canSetLanguage(this.extension)) { return; } - if (this.extension.state === ExtensionState.Uninstalled && await this.extensionsWorkbenchService.canInstall(this.extension)) { - this.enabled = this.options.installPreReleaseVersion ? this.extension.hasPreReleaseVersion : this.extension.hasReleaseVersion; + if (this.extension.state !== ExtensionState.Uninstalled) { + return; + } + if (this.options.installPreReleaseVersion && !this.extension.hasPreReleaseVersion) { + return; + } + if (!this.options.installPreReleaseVersion && !this.extension.hasReleaseVersion) { + return; + } + this.hidden = false; + this.class = InstallAction.CLASS; + if (await this.extensionsWorkbenchService.canInstall(this.extension)) { + this.enabled = true; this.updateLabel(); } } @@ -518,7 +599,7 @@ export class InstallAction extends ExtensionAction { } -export class InstallDropdownAction extends ActionWithDropDownAction { +export class InstallDropdownAction extends ButtonWithDropDownExtensionAction { set manifest(manifest: IExtensionManifest | null) { this.extensionActions.forEach(a => (a).manifest = manifest); @@ -529,7 +610,7 @@ export class InstallDropdownAction extends ActionWithDropDownAction { @IInstantiationService instantiationService: IInstantiationService, @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, ) { - super(`extensions.installActions`, '', [ + super(`extensions.installActions`, ExtensionAction.PROMINENT_LABEL_ACTION_CLASS, [ [ instantiationService.createInstance(InstallAction, { installPreReleaseVersion: extensionsWorkbenchService.preferPreReleases }), instantiationService.createInstance(InstallAction, { installPreReleaseVersion: !extensionsWorkbenchService.preferPreReleases }), @@ -562,8 +643,8 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { protected static readonly INSTALL_LABEL = localize('install', "Install"); protected static readonly INSTALLING_LABEL = localize('installing', "Installing"); - private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} prominent install`; - private static readonly InstallingClass = `${ExtensionAction.LABEL_ACTION_CLASS} install installing`; + private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} prominent install-other-server`; + private static readonly InstallingClass = `${ExtensionAction.LABEL_ACTION_CLASS} install-other-server installing`; updateWhenCounterExtensionChanges: boolean = true; @@ -987,32 +1068,7 @@ export class MigrateDeprecatedExtensionAction extends ExtensionAction { } } -export class ExtensionActionWithDropdownActionViewItem extends ActionWithDropdownActionViewItem { - - constructor( - action: ActionWithDropDownAction, - options: IActionViewItemOptions & IActionWithDropdownActionViewItemOptions, - contextMenuProvider: IContextMenuProvider - ) { - super(null, action, options, contextMenuProvider); - } - - override render(container: HTMLElement): void { - super.render(container); - this.updateClass(); - } - - protected override updateClass(): void { - super.updateClass(); - if (this.element && this.dropdownMenuActionViewItem && this.dropdownMenuActionViewItem.element) { - this.element.classList.toggle('empty', (this._action).menuActions.length === 0); - this.dropdownMenuActionViewItem.element.classList.toggle('hide', (this._action).menuActions.length === 0); - } - } - -} - -export abstract class ExtensionDropDownAction extends ExtensionAction { +export abstract class DropDownExtensionAction extends ExtensionAction { constructor( id: string, @@ -1024,9 +1080,9 @@ export abstract class ExtensionDropDownAction extends ExtensionAction { super(id, label, cssClass, enabled); } - private _actionViewItem: DropDownMenuActionViewItem | null = null; - createActionViewItem(options: IActionViewItemOptions): DropDownMenuActionViewItem { - this._actionViewItem = this.instantiationService.createInstance(DropDownMenuActionViewItem, this, options); + private _actionViewItem: DropDownExtensionActionViewItem | null = null; + createActionViewItem(options: IActionViewItemOptions): DropDownExtensionActionViewItem { + this._actionViewItem = this.instantiationService.createInstance(DropDownExtensionActionViewItem, this, options); return this._actionViewItem; } @@ -1036,10 +1092,10 @@ export abstract class ExtensionDropDownAction extends ExtensionAction { } } -export class DropDownMenuActionViewItem extends ActionViewItem { +export class DropDownExtensionActionViewItem extends ActionViewItem { constructor( - action: ExtensionDropDownAction, + action: DropDownExtensionAction, options: IActionViewItemOptions, @IContextMenuService private readonly contextMenuService: IContextMenuService ) { @@ -1137,7 +1193,7 @@ export async function getContextMenuActions(extension: IExtension | undefined | return toActions(actionsGroups, instantiationService); } -export class ManageExtensionAction extends ExtensionDropDownAction { +export class ManageExtensionAction extends DropDownExtensionAction { static readonly ID = 'extensions.manage'; @@ -1221,7 +1277,7 @@ export class ManageExtensionAction extends ExtensionDropDownAction { } } -export class ExtensionEditorManageExtensionAction extends ExtensionDropDownAction { +export class ExtensionEditorManageExtensionAction extends DropDownExtensionAction { constructor( private readonly contextKeyService: IContextKeyService, @@ -1540,12 +1596,12 @@ export class DisableGloballyAction extends ExtensionAction { } } -export class EnableDropDownAction extends ActionWithDropDownAction { +export class EnableDropDownAction extends ButtonWithDropDownExtensionAction { constructor( @IInstantiationService instantiationService: IInstantiationService ) { - super('extensions.enable', localize('enableAction', "Enable"), [ + super('extensions.enable', ExtensionAction.LABEL_ACTION_CLASS, [ [ instantiationService.createInstance(EnableGloballyAction), instantiationService.createInstance(EnableForWorkspaceAction) @@ -1554,12 +1610,12 @@ export class EnableDropDownAction extends ActionWithDropDownAction { } } -export class DisableDropDownAction extends ActionWithDropDownAction { +export class DisableDropDownAction extends ButtonWithDropDownExtensionAction { constructor( @IInstantiationService instantiationService: IInstantiationService ) { - super('extensions.disable', localize('disableAction', "Disable"), [[ + super('extensions.disable', ExtensionAction.LABEL_ACTION_CLASS, [[ instantiationService.createInstance(DisableGloballyAction), instantiationService.createInstance(DisableForWorkspaceAction) ]]); @@ -2284,7 +2340,7 @@ export class ExtensionStatusLabelAction extends Action implements IExtensionCont } -export class ToggleSyncExtensionAction extends ExtensionDropDownAction { +export class ToggleSyncExtensionAction extends DropDownExtensionAction { private static readonly IGNORED_SYNC_CLASS = `${ExtensionAction.ICON_ACTION_CLASS} extension-sync ${ThemeIcon.asClassName(syncIgnoredIcon)}`; private static readonly SYNC_CLASS = `${ToggleSyncExtensionAction.ICON_ACTION_CLASS} extension-sync ${ThemeIcon.asClassName(syncEnabledIcon)}`; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 683098f05b6..4b7ce4a7947 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -13,7 +13,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { Event } from 'vs/base/common/event'; import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; -import { ManageExtensionAction, ExtensionRuntimeStateAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, UpdateAction, ToggleAutoUpdateForExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; +import { ManageExtensionAction, ExtensionRuntimeStateAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ButtonWithDropDownExtensionAction, InstallDropdownAction, InstallingLabelAction, ButtonWithDropdownExtensionActionViewItem, DropDownExtensionAction, WebInstallAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, UpdateAction, ToggleAutoUpdateForExtensionAction, ExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, ExtensionPackCountWidget as ExtensionPackBadgeWidget, SyncIgnoredWidget, ExtensionHoverWidget, ExtensionActivationStatusWidget, PreReleaseBookmarkWidget, extensionVerifiedPublisherIconColor, VerifiedPublisherWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets'; import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions'; @@ -100,10 +100,19 @@ export class Renderer implements IPagedRenderer { const publisherDisplayName = append(publisher, $('.publisher-name.ellipsis')); const actionbar = new ActionBar(footer, { actionViewItemProvider: (action: IAction, options: IActionViewItemOptions) => { - if (action instanceof ActionWithDropDownAction) { - return new ExtensionActionWithDropdownActionViewItem(action, { ...options, icon: true, label: true, menuActionsOrProvider: { getActions: () => action.menuActions }, menuActionClassNames: (action.class || '').split(' ') }, this.contextMenuService); + if (action instanceof ButtonWithDropDownExtensionAction) { + return new ButtonWithDropdownExtensionActionViewItem( + action, + { + ...options, + icon: true, + label: true, + menuActionsOrProvider: { getActions: () => action.menuActions }, + menuActionClassNames: action.menuActionClassNames + }, + this.contextMenuService); } - if (action instanceof ExtensionDropDownAction) { + if (action instanceof DropDownExtensionAction) { return action.createActionViewItem(options); } return undefined; @@ -118,7 +127,7 @@ export class Renderer implements IPagedRenderer { this.instantiationService.createInstance(ExtensionStatusLabelAction), this.instantiationService.createInstance(MigrateDeprecatedExtensionAction, true), this.instantiationService.createInstance(ExtensionRuntimeStateAction), - this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '', + this.instantiationService.createInstance(ButtonWithDropDownExtensionAction, 'extensions.updateActions', ExtensionAction.PROMINENT_LABEL_ACTION_CLASS, [[this.instantiationService.createInstance(UpdateAction, false)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, true, [true, 'onlyEnabledExtensions'])]]), this.instantiationService.createInstance(InstallDropdownAction), this.instantiationService.createInstance(InstallingLabelAction), diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css index 7bca4243703..bd3ae98514d 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css @@ -97,7 +97,8 @@ .monaco-action-bar .action-item.disabled .action-label.extension-action.hide, .monaco-action-bar .action-item.disabled .action-label.extension-action.ignore, .monaco-action-bar .action-item.disabled .action-label.extension-action.undo-ignore, -.monaco-action-bar .action-item.disabled .action-label.extension-action.install:not(.installing), +.monaco-action-bar .action-item .action-label.extension-action.install.hide, +.monaco-action-bar .action-item.disabled .action-label.extension-action.install-other-server:not(.installing), .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, @@ -105,7 +106,7 @@ .monaco-action-bar .action-item.disabled .action-label.extension-action.theme, .monaco-action-bar .action-item.disabled .action-label.extension-action.language, .monaco-action-bar .action-item.disabled .action-label.extension-action.extension-sync, -.monaco-action-bar .action-item.action-dropdown-item.disabled, +.monaco-action-bar .action-item.action-dropdown-item.hide, .monaco-action-bar .action-item.action-dropdown-item .action-label.extension-action.hide, .monaco-action-bar .action-item.disabled .action-label.extension-action.reload, .monaco-action-bar .action-item.disabled .action-label.disable-status.hide, @@ -115,6 +116,10 @@ display: none; } +.monaco-action-bar .action-item.disabled .action-label.extension-action.label { + opacity: 0.4 !important; +} + .monaco-action-bar .action-item.checkbox-action-item.disabled { display: none; } diff --git a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsActions.test.ts index 7bcaed37ba3..197f6059031 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsActions.test.ts @@ -177,7 +177,7 @@ suite('ExtensionsActions', () => { testObject.extension = paged.firstPage[0]; assert.ok(!testObject.enabled); assert.strictEqual('Install', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install hide', testObject.class); }); }); }); @@ -206,7 +206,7 @@ suite('ExtensionsActions', () => { const gallery = aGalleryExtension('a'); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); const paged = await workbenchService.queryGallery(CancellationToken.None); - const promise = Event.toPromise(testObject.onDidChange); + const promise = Event.toPromise(Event.filter(testObject.onDidChange, e => e.enabled === true)); testObject.extension = paged.firstPage[0]; await promise; assert.ok(testObject.enabled); @@ -1733,7 +1733,7 @@ suite('RemoteInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install in remote', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test remote install action when installing local workspace extension', async () => { @@ -1759,12 +1759,12 @@ suite('RemoteInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install in remote', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); onInstallExtension.fire({ identifier: localWorkspaceExtension.identifier, source: gallery, profileLocation: null! }); assert.ok(testObject.enabled); assert.strictEqual('Installing', testObject.label); - assert.strictEqual('extension-action label install installing', testObject.class); + assert.strictEqual('extension-action label install-other-server installing', testObject.class); }); test('Test remote install action when installing local workspace extension is finished', async () => { @@ -1792,12 +1792,12 @@ suite('RemoteInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install in remote', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); onInstallExtension.fire({ identifier: localWorkspaceExtension.identifier, source: gallery, profileLocation: null! }); assert.ok(testObject.enabled); assert.strictEqual('Installing', testObject.label); - assert.strictEqual('extension-action label install installing', testObject.class); + assert.strictEqual('extension-action label install-other-server installing', testObject.class); const installedExtension = aLocalExtension('a', { extensionKind: ['workspace'] }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); const promise = Event.toPromise(testObject.onDidChange); @@ -1826,7 +1826,7 @@ suite('RemoteInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install in remote', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test remote install action is enabled local workspace+ui extension', async () => { @@ -1848,7 +1848,7 @@ suite('RemoteInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install in remote', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test remote install action is enabled for local ui+workapace extension if can install is true', async () => { @@ -1870,7 +1870,7 @@ suite('RemoteInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install in remote', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test remote install action is disabled for local ui+workapace extension if can install is false', async () => { @@ -2111,7 +2111,7 @@ suite('RemoteInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install in remote', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test remote install action is disabled if local language pack extension is uninstalled', async () => { @@ -2164,7 +2164,7 @@ suite('LocalInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install Locally', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test local install action is enabled for remote ui+workspace extension', async () => { @@ -2185,7 +2185,7 @@ suite('LocalInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install Locally', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test local install action when installing remote ui extension', async () => { @@ -2211,12 +2211,12 @@ suite('LocalInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install Locally', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); onInstallExtension.fire({ identifier: remoteUIExtension.identifier, source: gallery, profileLocation: null! }); assert.ok(testObject.enabled); assert.strictEqual('Installing', testObject.label); - assert.strictEqual('extension-action label install installing', testObject.class); + assert.strictEqual('extension-action label install-other-server installing', testObject.class); }); test('Test local install action when installing remote ui extension is finished', async () => { @@ -2244,12 +2244,12 @@ suite('LocalInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install Locally', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); onInstallExtension.fire({ identifier: remoteUIExtension.identifier, source: gallery, profileLocation: null! }); assert.ok(testObject.enabled); assert.strictEqual('Installing', testObject.label); - assert.strictEqual('extension-action label install installing', testObject.class); + assert.strictEqual('extension-action label install-other-server installing', testObject.class); const installedExtension = aLocalExtension('a', { extensionKind: ['ui'] }, { location: URI.file(`pub.a`) }); const promise = Event.toPromise(testObject.onDidChange); @@ -2278,7 +2278,7 @@ suite('LocalInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install Locally', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test local install action is disabled when extension is not set', async () => { @@ -2502,7 +2502,7 @@ suite('LocalInstallAction', () => { testObject.extension = extensions[0]; assert.ok(testObject.enabled); assert.strictEqual('Install Locally', testObject.label); - assert.strictEqual('extension-action label prominent install', testObject.class); + assert.strictEqual('extension-action label prominent install-other-server', testObject.class); }); test('Test local install action is disabled if remote language pack extension is uninstalled', async () => {