/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/extensionActions'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { IAction, Action } from 'vs/base/common/actions'; import { Throttler } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import severity from 'vs/base/common/severity'; import paths = require('vs/base/common/paths'); import Event from 'vs/base/common/event'; import { ActionItem, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extensions/common/extensionsFileTemplate'; import { LocalExtensionType, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import { ToggleViewletAction } from 'vs/workbench/browser/viewlet'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewletService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IExtensionService, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import URI from 'vs/base/common/uri'; export class InstallAction extends Action { private static InstallLabel = localize('installAction', "Install"); private static InstallingLabel = localize('installing', "Installing"); private static Class = 'extension-action install'; private static InstallingClass = 'extension-action install installing'; private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor( @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super('extensions.install', InstallAction.InstallLabel, InstallAction.Class, false); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { if (!this.extension || this.extension.type === LocalExtensionType.System) { this.enabled = false; this.class = InstallAction.Class; this.label = InstallAction.InstallLabel; return; } this.enabled = this.extensionsWorkbenchService.canInstall(this.extension) && this.extension.state === ExtensionState.Uninstalled; if (this.extension.state === ExtensionState.Installing) { this.label = InstallAction.InstallingLabel; this.class = InstallAction.InstallingClass; } else { this.label = InstallAction.InstallLabel; this.class = InstallAction.Class; } } run(): TPromise { return this.extensionsWorkbenchService.install(this.extension); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class UninstallAction extends Action { private static UninstallLabel = localize('uninstallAction', "Uninstall"); private static UninstallingLabel = localize('Uninstalling', "Uninstalling"); private static UninstallClass = 'extension-action uninstall'; private static UnInstallingClass = 'extension-action uninstall uninstalling'; private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor( @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IMessageService private messageService: IMessageService, @IInstantiationService private instantiationService: IInstantiationService ) { super('extensions.uninstall', UninstallAction.UninstallLabel, UninstallAction.UninstallClass, false); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { if (!this.extension) { this.enabled = false; return; } const state = this.extension.state; if (state === ExtensionState.Uninstalling) { this.label = UninstallAction.UninstallingLabel; this.class = UninstallAction.UnInstallingClass; this.enabled = false; return; } this.label = UninstallAction.UninstallLabel; this.class = UninstallAction.UninstallClass; const installedExtensions = this.extensionsWorkbenchService.local.filter(e => e.identifier === this.extension.identifier); if (!installedExtensions.length) { this.enabled = false; return; } if (installedExtensions[0].type !== LocalExtensionType.User) { this.enabled = false; return; } this.enabled = true; } run(): TPromise { return this.extensionsWorkbenchService.uninstall(this.extension); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class CombinedInstallAction extends Action { private static NoExtensionClass = 'extension-action install no-extension'; private installAction: InstallAction; private uninstallAction: UninstallAction; private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.installAction.extension = extension; this.uninstallAction.extension = extension; } constructor( @IInstantiationService instantiationService: IInstantiationService ) { super('extensions.combinedInstall', '', '', false); this.installAction = instantiationService.createInstance(InstallAction); this.uninstallAction = instantiationService.createInstance(UninstallAction); this.disposables.push(this.installAction, this.uninstallAction); this.installAction.onDidChange(this.update, this, this.disposables); this.uninstallAction.onDidChange(this.update, this, this.disposables); this.update(); } private update(): void { if (!this.extension || this.extension.type === LocalExtensionType.System) { this.enabled = false; this.class = CombinedInstallAction.NoExtensionClass; } else if (this.installAction.enabled) { this.enabled = true; this.label = this.installAction.label; this.class = this.installAction.class; } else if (this.uninstallAction.enabled) { this.enabled = true; this.label = this.uninstallAction.label; this.class = this.uninstallAction.class; } else if (this.extension.state === ExtensionState.Installing) { this.enabled = false; this.label = this.installAction.label; this.class = this.installAction.class; } else if (this.extension.state === ExtensionState.Uninstalling) { this.enabled = false; this.label = this.uninstallAction.label; this.class = this.uninstallAction.class; } else { this.enabled = false; this.label = this.installAction.label; this.class = this.installAction.class; } } run(): TPromise { if (this.installAction.enabled) { return this.installAction.run(); } else if (this.uninstallAction.enabled) { return this.uninstallAction.run(); } return TPromise.as(null); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class UpdateAction extends Action { private static EnabledClass = 'extension-action update'; private static DisabledClass = `${UpdateAction.EnabledClass} disabled`; private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor( @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super('extensions.update', localize('updateAction', "Update"), UpdateAction.DisabledClass, false); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { if (!this.extension) { this.enabled = false; this.class = UpdateAction.DisabledClass; return; } if (this.extension.type !== LocalExtensionType.User) { this.enabled = false; this.class = UpdateAction.DisabledClass; return; } const canInstall = this.extensionsWorkbenchService.canInstall(this.extension); const isInstalled = this.extension.state === ExtensionState.Installed; this.enabled = canInstall && isInstalled && this.extension.outdated; this.class = this.enabled ? UpdateAction.EnabledClass : UpdateAction.DisabledClass; } run(): TPromise { return this.extensionsWorkbenchService.install(this.extension); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export interface IExtensionAction extends IAction { extension: IExtension; } export class DropDownMenuActionItem extends ActionItem { private disposables: IDisposable[] = []; private _extension: IExtension; constructor(action: IAction, private menuActionGroups: IExtensionAction[][], private contextMenuService: IContextMenuService) { super(null, action, { icon: true, label: true }); for (const menuActions of menuActionGroups) { this.disposables = [...this.disposables, ...menuActions]; } } get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; for (const menuActions of this.menuActionGroups) { for (const menuAction of menuActions) { menuAction.extension = extension; } } } public showMenu(): void { const actions = this.getActions(); let elementPosition = DOM.getDomNodePagePosition(this.builder.getHTMLElement()); const anchor = { x: elementPosition.left, y: elementPosition.top + elementPosition.height + 10 }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, getActions: () => TPromise.wrap(actions) }); } private getActions(): IAction[] { let actions = []; for (const menuActions of this.menuActionGroups) { const filtered = menuActions.filter(a => a.enabled); if (filtered.length > 0) { actions = [...actions, ...filtered, new Separator()]; } } return actions.length ? actions.slice(0, actions.length - 1) : actions; } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class ManageExtensionActionItem extends DropDownMenuActionItem { constructor( action: IAction, @IInstantiationService instantiationService: IInstantiationService, @IContextMenuService contextMenuService: IContextMenuService) { super(action, [ [instantiationService.createInstance(EnableForWorkspaceAction, localize('enableForWorkspaceAction.label', "Enable (Workspace)")), instantiationService.createInstance(EnableGloballyAction, localize('enableAlwaysAction.label', "Enable")), instantiationService.createInstance(DisableForWorkspaceAction, localize('disableForWorkspaceAction.label', "Disable (Workspace)")), instantiationService.createInstance(DisableGloballyAction, localize('disableAlwaysAction.label', "Disable"))], [instantiationService.createInstance(UninstallAction)] ], contextMenuService); } } export class ManageExtensionAction extends Action { static ID = 'extensions.manage'; private static Class = 'extension-action manage'; private static NoExtensionClass = `${ManageExtensionAction.Class} no-extension`; private _actionItem: EnableActionItem; get actionItem(): IActionItem { return this._actionItem; } private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this._actionItem.extension = extension; this.update(); } constructor( @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, @IInstantiationService private instantiationService: IInstantiationService ) { super(ManageExtensionAction.ID); this._actionItem = this.instantiationService.createInstance(ManageExtensionActionItem, this); this.disposables.push(this._actionItem); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { this.class = ManageExtensionAction.NoExtensionClass; this.tooltip = ''; this.enabled = false; if (this.extension) { const state = this.extension.state; this.enabled = state === ExtensionState.Installed; this.class = this.enabled || state === ExtensionState.Uninstalling ? ManageExtensionAction.Class : ManageExtensionAction.NoExtensionClass; this.tooltip = state === ExtensionState.Uninstalling ? localize('ManageExtensionAction.uninstallingTooltip', "Uninstalling") : ''; } } public run(): TPromise { this._actionItem.showMenu(); return TPromise.wrap(null); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class EnableForWorkspaceAction extends Action implements IExtensionAction { static ID = 'extensions.enableForWorkspace'; static LABEL = localize('enableForWorkspaceAction', "Workspace"); private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor(label: string, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, @IInstantiationService private instantiationService: IInstantiationService ) { super(EnableForWorkspaceAction.ID, label); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { this.enabled = false; if (this.extension) { this.enabled = !this.extension.disabledGlobally && this.extension.disabledForWorkspace && this.extensionEnablementService.canEnable(this.extension.identifier); } } run(): TPromise { return this.extensionsWorkbenchService.setEnablement(this.extension, true, true); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class EnableGloballyAction extends Action implements IExtensionAction { static ID = 'extensions.enableGlobally'; static LABEL = localize('enableGloballyAction', "Always"); private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor(label: string, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, @IInstantiationService private instantiationService: IInstantiationService ) { super(EnableGloballyAction.ID, label); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { this.enabled = false; if (this.extension) { this.enabled = this.extension.disabledGlobally && this.extensionEnablementService.canEnable(this.extension.identifier); } } run(): TPromise { return this.extensionsWorkbenchService.setEnablement(this.extension, true, false); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class EnableAction extends Action { static ID = 'extensions.enable'; private static EnabledClass = 'extension-action enable'; private static DisabledClass = `${EnableAction.EnabledClass} disabled`; private disposables: IDisposable[] = []; private _actionItem: EnableActionItem; get actionItem(): IActionItem { return this._actionItem; } private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this._actionItem.extension = extension; this.update(); } constructor( @IInstantiationService private instantiationService: IInstantiationService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(EnableAction.ID, localize('enableAction', "Enable"), EnableAction.DisabledClass, false); this._actionItem = this.instantiationService.createInstance(EnableActionItem, this); this.disposables.push(this._actionItem); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { if (!this.extension) { this.enabled = false; this.class = EnableAction.DisabledClass; return; } this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.disabledGlobally || this.extension.disabledForWorkspace) && this.extensionEnablementService.canEnable(this.extension.identifier); this.class = this.enabled ? EnableAction.EnabledClass : EnableAction.DisabledClass; } public run(): TPromise { this._actionItem.showMenu(); return TPromise.wrap(null); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class DisableForWorkspaceAction extends Action implements IExtensionAction { static ID = 'extensions.disableForWorkspace'; static LABEL = localize('disableForWorkspaceAction', "Workspace"); private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor(label: string, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IInstantiationService private instantiationService: IInstantiationService ) { super(DisableForWorkspaceAction.ID, label); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { this.enabled = false; if (this.extension && this.workspaceContextService.getWorkspace()) { this.enabled = this.extension.type !== LocalExtensionType.System && !this.extension.disabledGlobally && !this.extension.disabledForWorkspace; } } run(): TPromise { return this.extensionsWorkbenchService.setEnablement(this.extension, false, true); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class DisableGloballyAction extends Action implements IExtensionAction { static ID = 'extensions.disableGlobally'; static LABEL = localize('disableGloballyAction', "Always"); private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor(label: string, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IInstantiationService private instantiationService: IInstantiationService ) { super(DisableGloballyAction.ID, label); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { this.enabled = false; if (this.extension) { this.enabled = this.extension.type !== LocalExtensionType.System && !this.extension.disabledGlobally && !this.extension.disabledForWorkspace; } } run(): TPromise { return this.extensionsWorkbenchService.setEnablement(this.extension, false, false); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class DisableAction extends Action { static ID = 'extensions.disable'; private static EnabledClass = 'extension-action disable'; private static DisabledClass = `${DisableAction.EnabledClass} disabled`; private disposables: IDisposable[] = []; private _actionItem: DisableActionItem; get actionItem(): IActionItem { return this._actionItem; } private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this._actionItem.extension = extension; this.update(); } constructor( @IInstantiationService private instantiationService: IInstantiationService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, ) { super(DisableAction.ID, localize('disableAction', "Disable"), DisableAction.DisabledClass, false); this._actionItem = this.instantiationService.createInstance(DisableActionItem, this); this.disposables.push(this._actionItem); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { if (!this.extension) { this.enabled = false; this.class = DisableAction.DisabledClass; return; } this.enabled = this.extension.state === ExtensionState.Installed && this.extension.type !== LocalExtensionType.System && !this.extension.disabledGlobally && !this.extension.disabledForWorkspace; this.class = this.enabled ? DisableAction.EnabledClass : DisableAction.DisabledClass; } public run(): TPromise { this._actionItem.showMenu(); return TPromise.wrap(null); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class EnableActionItem extends DropDownMenuActionItem { constructor( action: IAction, @IInstantiationService instantiationService: IInstantiationService, @IContextMenuService contextMenuService: IContextMenuService) { super(action, [[instantiationService.createInstance(EnableForWorkspaceAction, EnableForWorkspaceAction.LABEL), instantiationService.createInstance(EnableGloballyAction, EnableGloballyAction.LABEL)]], contextMenuService); } } export class DisableActionItem extends DropDownMenuActionItem { constructor( action: IAction, @IInstantiationService instantiationService: IInstantiationService, @IContextMenuService contextMenuService: IContextMenuService) { super(action, [[instantiationService.createInstance(DisableForWorkspaceAction, DisableForWorkspaceAction.LABEL), instantiationService.createInstance(DisableGloballyAction, DisableGloballyAction.LABEL)]], contextMenuService); } } export class UpdateAllAction extends Action { static ID = 'workbench.extensions.action.updateAllExtensions'; static LABEL = localize('updateAll', "Update All Extensions"); private disposables: IDisposable[] = []; constructor( id = UpdateAllAction.ID, label = UpdateAllAction.LABEL, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(id, label, '', false); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private get outdated(): IExtension[] { return this.extensionsWorkbenchService.local.filter(e => e.outdated && e.state !== ExtensionState.Installing); } private update(): void { this.enabled = this.outdated.length > 0; } run(): TPromise { return TPromise.join(this.outdated.map(e => this.extensionsWorkbenchService.install(e))); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class ReloadAction extends Action { private static EnabledClass = 'extension-action reload'; private static DisabledClass = `${ReloadAction.EnabledClass} disabled`; private disposables: IDisposable[] = []; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } reloadMessaage: string = ''; private throttler: Throttler; constructor( @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IMessageService private messageService: IMessageService, @IInstantiationService private instantiationService: IInstantiationService, @IExtensionService private extensionService: IExtensionService, @ICommandService private commandService: ICommandService ) { super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false); this.throttler = new Throttler(); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } private update(): void { this.throttler.queue(() => { this.enabled = false; this.tooltip = ''; this.reloadMessaage = ''; if (!this.extension) { return TPromise.wrap(null); } const state = this.extension.state; if (state === ExtensionState.Installing || state === ExtensionState.Uninstalling) { return TPromise.wrap(null); } return this.extensionService.getExtensions() .then(runningExtensions => this.computeReloadState(runningExtensions)); }).done(() => { this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass; }); } private computeReloadState(runningExtensions: IExtensionDescription[]): void { const isInstalled = this.extensionsWorkbenchService.local.some(e => e.identifier === this.extension.identifier); const isUninstalled = this.extension.state === ExtensionState.Uninstalled; const isDisabled = this.extension.disabledForWorkspace || this.extension.disabledGlobally; const filteredExtensions = runningExtensions.filter(e => e.id === this.extension.identifier); const isExtensionRunning = filteredExtensions.length > 0; const isDifferentVersionRunning = filteredExtensions.length > 0 && this.extension.version !== filteredExtensions[0].version; if (isInstalled) { if (isDifferentVersionRunning && !isDisabled) { // Requires reload to run the updated extension this.enabled = true; this.tooltip = localize('postUpdateTooltip', "Reload to update"); this.reloadMessaage = localize('postUpdateMessage', "Reload this window to activate the updated extension '{0}'?", this.extension.displayName); return; } if (!isExtensionRunning && !isDisabled) { // Requires reload to enable the extension this.enabled = true; this.tooltip = localize('postEnableTooltip', "Reload to activate"); this.reloadMessaage = localize('postEnableMessage', "Reload this window to activate the extension '{0}'?", this.extension.displayName); return; } if (isExtensionRunning && isDisabled) { // Requires reload to disable the extension this.enabled = true; this.tooltip = localize('postDisableTooltip', "Reload to deactivate"); this.reloadMessaage = localize('postDisableMessage', "Reload this window to deactivate the extension '{0}'?", this.extension.displayName); return; } return; } if (isUninstalled && isExtensionRunning) { // Requires reload to deactivate the extension this.enabled = true; this.tooltip = localize('postUninstallTooltip', "Reload to deactivate"); this.reloadMessaage = localize('postUninstallMessage', "Reload this window to deactivate the uninstalled extension '{0}'?", this.extension.displayName); return; } } run(): TPromise { if (this.messageService.confirm({ message: this.reloadMessaage })) { // TODO: @sandy: Temporary hack. Adopt to new IWindowService from @bpasero and @jaoa this.commandService.executeCommand('workbench.action.reloadWindow'); } return TPromise.wrap(null); } } export class OpenExtensionsViewletAction extends ToggleViewletAction { static ID = VIEWLET_ID; static LABEL = localize('toggleExtensionsViewlet', "Show Extensions"); constructor( id: string, label: string, @IViewletService viewletService: IViewletService, @IWorkbenchEditorService editorService: IWorkbenchEditorService ) { super(id, label, VIEWLET_ID, viewletService, editorService); } } export class InstallExtensionsAction extends OpenExtensionsViewletAction { static ID = 'workbench.extensions.action.installExtensions'; static LABEL = localize('installExtensions', "Install Extensions"); } export class ShowInstalledExtensionsAction extends Action { static ID = 'workbench.extensions.action.showInstalledExtensions'; static LABEL = localize('showInstalledExtensions', "Show Installed Extensions"); constructor( id: string, label: string, @IViewletService private viewletService: IViewletService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(id, label, 'clear-extensions', true); } run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { viewlet.search(''); viewlet.focus(); }); } } export class ShowDisabledExtensionsAction extends Action { static ID = 'workbench.extensions.action.showDisabledExtensions'; static LABEL = localize('showDisabledExtensions', "Show Disabled Extensions"); constructor( id: string, label: string, @IViewletService private viewletService: IViewletService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(id, label, 'null', true); } run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { viewlet.search('@disabled '); viewlet.focus(); }); } } export class ClearExtensionsInputAction extends ShowInstalledExtensionsAction { static ID = 'workbench.extensions.action.clearExtensionsInput'; static LABEL = localize('clearExtensionsInput', "Clear Extensions Input"); private disposables: IDisposable[] = []; constructor( id: string, label: string, onSearchChange: Event, @IViewletService viewletService: IViewletService, @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(id, label, viewletService, extensionsWorkbenchService); this.enabled = false; onSearchChange(this.onSearchChange, this, this.disposables); } private onSearchChange(value: string): void { this.enabled = !!value; } dispose(): void { this.disposables = dispose(this.disposables); } } export class ShowOutdatedExtensionsAction extends Action { static ID = 'workbench.extensions.action.listOutdatedExtensions'; static LABEL = localize('showOutdatedExtensions', "Show Outdated Extensions"); constructor( id: string, label: string, @IViewletService private viewletService: IViewletService ) { super(id, label, null, true); } run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { viewlet.search('@outdated '); viewlet.focus(); }); } protected isEnabled(): boolean { return true; } } export class ShowPopularExtensionsAction extends Action { static ID = 'workbench.extensions.action.showPopularExtensions'; static LABEL = localize('showPopularExtensions', "Show Popular Extensions"); constructor( id: string, label: string, @IViewletService private viewletService: IViewletService ) { super(id, label, null, true); } run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { viewlet.search('@sort:installs '); viewlet.focus(); }); } protected isEnabled(): boolean { return true; } } export class ShowRecommendedExtensionsAction extends Action { static ID = 'workbench.extensions.action.showRecommendedExtensions'; static LABEL = localize('showRecommendedExtensions', "Show Recommended Extensions"); constructor( id: string, label: string, @IViewletService private viewletService: IViewletService ) { super(id, label, null, true); } run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { viewlet.search('@recommended '); viewlet.focus(); }); } protected isEnabled(): boolean { return true; } } export class ShowWorkspaceRecommendedExtensionsAction extends Action { static ID = 'workbench.extensions.action.showWorkspaceRecommendedExtensions'; static LABEL = localize('showWorkspaceRecommendedExtensions', "Show Workspace Recommended Extensions"); constructor( id: string, label: string, @IWorkspaceContextService contextService: IWorkspaceContextService, @IViewletService private viewletService: IViewletService ) { super(id, label, null, !!contextService.getWorkspace()); } run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { viewlet.search('@recommended:workspace '); viewlet.focus(); }); } protected isEnabled(): boolean { return true; } } export class ChangeSortAction extends Action { private query: Query; private disposables: IDisposable[] = []; constructor( id: string, label: string, onSearchChange: Event, private sortBy: string, private sortOrder: string, @IViewletService private viewletService: IViewletService ) { super(id, label, null, true); if (sortBy === undefined && sortOrder === undefined) { throw new Error('bad arguments'); } this.query = Query.parse(''); this.enabled = false; onSearchChange(this.onSearchChange, this, this.disposables); } private onSearchChange(value: string): void { const query = Query.parse(value); this.query = new Query(query.value, this.sortBy || query.sortBy, this.sortOrder || query.sortOrder); this.enabled = value && this.query.isValid() && !this.query.equals(query); } run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { viewlet.search(this.query.toString()); viewlet.focus(); }); } protected isEnabled(): boolean { return true; } } export class ConfigureWorkspaceRecommendedExtensionsAction extends Action { static ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions'; static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)"); constructor( id: string, label: string, @IFileService private fileService: IFileService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsService: IExtensionsWorkbenchService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IMessageService private messageService: IMessageService ) { super(id, label, null, !!contextService.getWorkspace()); } public run(event: any): TPromise { return this.openExtensionsFile(); } private openExtensionsFile(): TPromise { if (!this.contextService.getWorkspace()) { this.messageService.show(severity.Info, localize('ConfigureWorkspaceRecommendations.noWorkspace', 'Recommendations are only available on a workspace folder.')); return TPromise.as(undefined); } return this.getOrCreateExtensionsFile().then(value => { return this.editorService.openEditor({ resource: value.extensionsFileResource, options: { forceOpen: true, pinned: value.created }, }); }, (error) => TPromise.wrapError(new Error(localize('OpenExtensionsFile.failed', "Unable to create 'extensions.json' file inside the '.vscode' folder ({0}).", error)))); } private getOrCreateExtensionsFile(): TPromise<{ created: boolean, extensionsFileResource: URI }> { const extensionsFileResource = URI.file(paths.join(this.contextService.getWorkspace().resource.fsPath, '.vscode', `${ConfigurationKey}.json`)); return this.fileService.resolveContent(extensionsFileResource).then(content => { return { created: false, extensionsFileResource }; }, err => { return this.fileService.updateContent(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => { return { created: true, extensionsFileResource }; }); }); } } export class BuiltinStatusLabelAction extends Action { private static Class = 'extension-action built-in-status'; private _extension: IExtension; get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor() { super('extensions.install', localize('builtin', "Built-in"), '', false); } private update(): void { if (this.extension && this.extension.type === LocalExtensionType.System) { this.class = `${BuiltinStatusLabelAction.Class} system`; } else { this.class = `${BuiltinStatusLabelAction.Class} user`; } } run(): TPromise { return TPromise.as(null); } } export class DisableAllAction extends Action { static ID = 'workbench.extensions.action.disableAll'; static LABEL = localize('disableAll', "Disable All Installed Extensions"); private disposables: IDisposable[] = []; constructor( id: string = DisableAllAction.ID, label: string = DisableAllAction.LABEL, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(id, label); this.update(); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); } private update(): void { this.enabled = this.extensionsWorkbenchService.local.some(e => e.type === LocalExtensionType.User && !e.disabledForWorkspace && !e.disabledGlobally); } run(): TPromise { return TPromise.join(this.extensionsWorkbenchService.local.map(e => this.extensionsWorkbenchService.setEnablement(e, false))); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class DisableAllWorkpsaceAction extends Action { static ID = 'workbench.extensions.action.disableAllWorkspace'; static LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace"); private disposables: IDisposable[] = []; constructor( id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(id, label); this.update(); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); } private update(): void { this.enabled = !!this.workspaceContextService.getWorkspace() && this.extensionsWorkbenchService.local.some(e => e.type === LocalExtensionType.User && !e.disabledForWorkspace && !e.disabledGlobally); } run(): TPromise { return TPromise.join(this.extensionsWorkbenchService.local.map(e => this.extensionsWorkbenchService.setEnablement(e, false, true))); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class EnableAllAction extends Action { static ID = 'workbench.extensions.action.enableAll'; static LABEL = localize('enableAll', "Enable All Installed Extensions"); private disposables: IDisposable[] = []; constructor( id: string = EnableAllAction.ID, label: string = EnableAllAction.LABEL, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(id, label); this.update(); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); } private update(): void { this.enabled = this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.identifier) && e.disabledGlobally); } run(): TPromise { return TPromise.join(this.extensionsWorkbenchService.local.map(e => this.extensionsWorkbenchService.setEnablement(e, true))); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } } export class EnableAllWorkpsaceAction extends Action { static ID = 'workbench.extensions.action.enableAllWorkspace'; static LABEL = localize('enableAllWorkspace', "Enable All Installed Extensions for this Workspace"); private disposables: IDisposable[] = []; constructor( id: string = EnableAllWorkpsaceAction.ID, label: string = EnableAllWorkpsaceAction.LABEL, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(id, label); this.update(); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); } private update(): void { this.enabled = !!this.workspaceContextService.getWorkspace() && this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.identifier) && !e.disabledGlobally && e.disabledForWorkspace); } run(): TPromise { return TPromise.join(this.extensionsWorkbenchService.local.map(e => this.extensionsWorkbenchService.setEnablement(e, true, true))); } dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); } }