Skip to content

Commit

Permalink
#14379 ExtensionsView: Move secondary actions to context menu
Browse files Browse the repository at this point in the history
  • Loading branch information
sandy081 committed Oct 25, 2016
1 parent bdd1a31 commit 43e0037
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 37 deletions.
179 changes: 157 additions & 22 deletions src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ 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 } from 'vs/base/browser/ui/actionbar/actionbar';
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 { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
Expand Down Expand Up @@ -282,7 +282,7 @@ export class DropDownMenuActionItem extends ActionItem {
private disposables: IDisposable[] = [];
private _extension: IExtension;

constructor(action: IAction, private menuActions: IExtensionAction[], private contextMenuService: IContextMenuService) {
constructor(action: IAction, private menuActions: IAction[], private contextMenuService: IContextMenuService) {
super(null, action, { icon: true, label: true });
this.disposables = [...menuActions];
}
Expand All @@ -292,16 +292,19 @@ export class DropDownMenuActionItem extends ActionItem {
set extension(extension: IExtension) {
this._extension = extension;
for (const menuAction of this.menuActions) {
menuAction.extension = extension;
if (!(menuAction instanceof Separator)) {
(<IExtensionAction>menuAction).extension = extension;
}
}
}

public showMenu(): void {
const actions = this.menuActions.filter(a => a instanceof Separator || a.enabled);
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(this.menuActions),
getActions: () => TPromise.wrap(actions)
});
}

Expand All @@ -311,45 +314,130 @@ export class DropDownMenuActionItem extends ActionItem {
}
}

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")), new Separator(), 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,
@IExtensionsRuntimeService private extensionRuntimeService: IExtensionsRuntimeService,
@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.enabled = false;
if (this.extension) {
this.class = ManageExtensionAction.Class;
this.enabled = ExtensionState.Uninstalled !== this.extension.state;
}
}

public run(): TPromise<any> {
this._actionItem.showMenu();
return TPromise.wrap(null);
}

dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}

export class EnableForWorkspaceAction extends Action {

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(
constructor(label: string,
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService
@IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService,
@IInstantiationService private instantiationService: IInstantiationService
) {
super('extensions.enableForWorkspace', localize('enableForWorkspaceAction', "Workspace"), '', !!workspaceContextService.getWorkspace());
super(EnableForWorkspaceAction.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.extensionsRuntimeService.isDisabledAlways(this.extension.identifier);
this.enabled = ExtensionState.Disabled === this.extension.state && !this.extensionsRuntimeService.isDisabledAlways(this.extension.identifier);
}
}

run(): TPromise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extension, true, true);
}

dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}

export class EnableGloballyAction extends Action {

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(
constructor(label: string,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService
@IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService,
@IInstantiationService private instantiationService: IInstantiationService
) {
super('extensions.enableGlobally', localize('enableGloballyAction', "Always"), '', false);
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.extensionsRuntimeService.isDisabledAlways(this.extension.identifier);
}
Expand All @@ -358,6 +446,11 @@ export class EnableGloballyAction extends Action {
run(): TPromise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extension, true, false);
}

dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}

export class EnableAction extends Action {
Expand Down Expand Up @@ -415,37 +508,79 @@ export class EnableAction extends Action {

export class DisableForWorkspaceAction extends Action {

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; }
set extension(extension: IExtension) { this._extension = extension; this.update(); }

constructor(
constructor(label: string,
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
@IInstantiationService private instantiationService: IInstantiationService
) {
super('extensions.disableForWorkspace', localize('disableForWorkspaceAction', "Workspace"), '', !!workspaceContextService.getWorkspace());
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 = ExtensionState.Enabled === this.extension.state;
}
}

run(): TPromise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extension, false, true);
}

dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}

export class DisableGloballyAction extends Action {

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; }
set extension(extension: IExtension) { this._extension = extension; this.update(); }

constructor(
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
constructor(label: string,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
@IInstantiationService private instantiationService: IInstantiationService
) {
super('extensions.disableGlobally', localize('disableGloballyAction', "Always"), '', true);
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 = ExtensionState.Enabled === this.extension.state;
}
}

run(): TPromise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extension, false, false);
}

dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}

export class DisableAction extends Action {
Expand Down Expand Up @@ -503,7 +638,7 @@ export class EnableActionItem extends DropDownMenuActionItem {
action: IAction,
@IInstantiationService instantiationService: IInstantiationService,
@IContextMenuService contextMenuService: IContextMenuService) {
super(action, [instantiationService.createInstance(EnableForWorkspaceAction), instantiationService.createInstance(EnableGloballyAction)], contextMenuService);
super(action, [instantiationService.createInstance(EnableForWorkspaceAction, EnableForWorkspaceAction.LABEL), instantiationService.createInstance(EnableGloballyAction, EnableGloballyAction.LABEL)], contextMenuService);
}
}

Expand All @@ -512,7 +647,7 @@ export class DisableActionItem extends DropDownMenuActionItem {
action: IAction,
@IInstantiationService instantiationService: IInstantiationService,
@IContextMenuService contextMenuService: IContextMenuService) {
super(action, [instantiationService.createInstance(DisableForWorkspaceAction), instantiationService.createInstance(DisableGloballyAction)], contextMenuService);
super(action, [instantiationService.createInstance(DisableForWorkspaceAction, DisableForWorkspaceAction.LABEL), instantiationService.createInstance(DisableGloballyAction, DisableGloballyAction.LABEL)], contextMenuService);
}
}

Expand Down Expand Up @@ -1118,4 +1253,4 @@ export class EnableAllWorkpsaceAction extends Action {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { once } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IExtension, ExtensionState } from '../common/extensions';
import { CombinedInstallAction, UpdateAction, EnableAction, DisableAction, BuiltinStatusLabelAction, ReloadAction } from './extensionsActions';
import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ReloadAction, ManageExtensionAction } from './extensionsActions';
import { Label, RatingsWidget, InstallWidget } from './extensionsWidgets';
import { EventType } from 'vs/base/common/events';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';

export interface ITemplateData {
element: HTMLElement;
Expand All @@ -44,6 +45,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {

constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IMessageService private messageService: IMessageService
) { }

Expand All @@ -65,31 +67,26 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const actionbar = new ActionBar(footer, {
animated: false,
actionItemProvider: (action: Action) => {
if (action.id === EnableAction.ID) {
return (<EnableAction>action).actionItem;
}
if (action.id === DisableAction.ID) {
return (<DisableAction>action).actionItem;
if (action.id === ManageExtensionAction.ID) {
return (<ManageExtensionAction>action).actionItem;
}
return null;
}
});

actionbar.addListener2(EventType.RUN, ({ error }) => error && this.messageService.show(Severity.Error, error));

const versionWidget = this.instantiationService.createInstance(Label, version, e => e.version);
const installCountWidget = this.instantiationService.createInstance(InstallWidget, installCount, { small: true });
const ratingsWidget = this.instantiationService.createInstance(RatingsWidget, ratings, { small: true });

const builtinStatusAction = this.instantiationService.createInstance(BuiltinStatusLabelAction);
const combinedInstallAction = this.instantiationService.createInstance(CombinedInstallAction);
const installAction = this.instantiationService.createInstance(InstallAction);
const updateAction = this.instantiationService.createInstance(UpdateAction);
const enableAction = this.instantiationService.createInstance(EnableAction);
const disableAction = this.instantiationService.createInstance(DisableAction);
const reloadAction = this.instantiationService.createInstance(ReloadAction);
const manageAction = this.instantiationService.createInstance(ManageExtensionAction);

actionbar.push([enableAction, updateAction, disableAction, reloadAction, combinedInstallAction, builtinStatusAction], actionOptions);
const disposables = [versionWidget, installCountWidget, ratingsWidget, combinedInstallAction, builtinStatusAction, updateAction, enableAction, disableAction, reloadAction, actionbar];
actionbar.push([updateAction, reloadAction, installAction, builtinStatusAction, manageAction], actionOptions);
const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, updateAction, reloadAction, manageAction, actionbar];

return {
element, icon, name, installCount, ratings, author, description, disposables,
Expand All @@ -99,11 +96,10 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
installCountWidget.extension = extension;
ratingsWidget.extension = extension;
builtinStatusAction.extension = extension;
combinedInstallAction.extension = extension;
installAction.extension = extension;
updateAction.extension = extension;
enableAction.extension = extension;
disableAction.extension = extension;
reloadAction.extension = extension;
manageAction.extension = extension;
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,19 @@

.extension-editor > .header > .details > .actions > .monaco-action-bar .action-item .action-label.extension-action.built-in-status {
font-weight: normal;
}

.extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar .action-item .action-label.extension-action.manage.no-extension {
display: none;
}

.extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar .action-item .action-label.extension-action.manage {
height: 18px;
width: 10px;
border: none;
background: url('manage.svg') center center no-repeat;
}

.vs-dark .extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar .action-item .action-label.extension-action.manage {
background: url('manage-inverse.svg') center center no-repeat;
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 43e0037

Please sign in to comment.