提交 65894b11 编写于 作者: J Joao Moreno

wip: install action

上级 a0e74e3b
......@@ -4,219 +4,229 @@
*--------------------------------------------------------------------------------------------*/
import nls = require('vs/nls');
import { Promise, TPromise } from 'vs/base/common/winjs.base';
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
import { assign } from 'vs/base/common/objects';
import Severity from 'vs/base/common/severity';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IMessageService } from 'vs/platform/message/common/message';
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import { IExtensionManagementService, ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService';
const CloseAction = new Action('action.close', nls.localize('close', "Close"));
export class ListExtensionsAction extends Action {
static ID = 'workbench.extensions.action.listExtensions';
static LABEL = nls.localize('showInstalledExtensions', "Show Installed Extensions");
constructor(
id: string,
label: string,
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IQuickOpenService private quickOpenService: IQuickOpenService
) {
super(id, label, null, true);
}
run(): Promise {
return this.quickOpenService.show('ext ');
}
protected isEnabled(): boolean {
return true;
}
}
export class InstallExtensionAction extends Action {
static ID = 'workbench.extensions.action.installExtension';
static LABEL = nls.localize('installExtension', "Install Extension");
constructor(
id: string,
label: string,
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IQuickOpenService private quickOpenService: IQuickOpenService
) {
super(id, label, null, true);
}
run(): Promise {
return this.quickOpenService.show('ext install ');
}
protected isEnabled(): boolean {
return true;
}
}
export class ListOutdatedExtensionsAction extends Action {
static ID = 'workbench.extensions.action.listOutdatedExtensions';
static LABEL = nls.localize('showOutdatedExtensions', "Show Outdated Extensions");
constructor(
id: string,
label: string,
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IQuickOpenService private quickOpenService: IQuickOpenService
) {
super(id, label, null, true);
}
run(): Promise {
return this.quickOpenService.show('ext update ');
}
protected isEnabled(): boolean {
return true;
}
}
export class ListSuggestedExtensionsAction extends Action {
static ID = 'workbench.extensions.action.listSuggestedExtensions';
static LABEL = nls.localize('showExtensionRecommendations', "Show Extension Recommendations");
constructor(
id: string,
label: string,
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IQuickOpenService private quickOpenService: IQuickOpenService
) {
super(id, label, null, true);
}
run(): Promise {
return this.quickOpenService.show('ext recommend ');
}
protected isEnabled(): boolean {
return true;
}
}
// import { assign } from 'vs/base/common/objects';
// import Severity from 'vs/base/common/severity';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
// import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
// import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
// import { IMessageService } from 'vs/platform/message/common/message';
// import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import { IExtension, ExtensionsModel, ExtensionState } from './extensionsModel';
// import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
// import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService';
// const CloseAction = new Action('action.close', nls.localize('close', "Close"));
// export class ListExtensionsAction extends Action {
// static ID = 'workbench.extensions.action.listExtensions';
// static LABEL = nls.localize('showInstalledExtensions', "Show Installed Extensions");
// constructor(
// id: string,
// label: string,
// @IExtensionManagementService private extensionManagementService: IExtensionManagementService,
// @IQuickOpenService private quickOpenService: IQuickOpenService
// ) {
// super(id, label, null, true);
// }
// run(): Promise {
// return this.quickOpenService.show('ext ');
// }
// protected isEnabled(): boolean {
// return true;
// }
// }
// export class InstallExtensionAction extends Action {
// static ID = 'workbench.extensions.action.installExtension';
// static LABEL = nls.localize('installExtension', "Install Extension");
// constructor(
// id: string,
// label: string,
// @IExtensionManagementService private extensionManagementService: IExtensionManagementService,
// @IQuickOpenService private quickOpenService: IQuickOpenService
// ) {
// super(id, label, null, true);
// }
// run(): Promise {
// return this.quickOpenService.show('ext install ');
// }
// protected isEnabled(): boolean {
// return true;
// }
// }
// export class ListOutdatedExtensionsAction extends Action {
// static ID = 'workbench.extensions.action.listOutdatedExtensions';
// static LABEL = nls.localize('showOutdatedExtensions', "Show Outdated Extensions");
// constructor(
// id: string,
// label: string,
// @IExtensionManagementService private extensionManagementService: IExtensionManagementService,
// @IQuickOpenService private quickOpenService: IQuickOpenService
// ) {
// super(id, label, null, true);
// }
// run(): Promise {
// return this.quickOpenService.show('ext update ');
// }
// protected isEnabled(): boolean {
// return true;
// }
// }
// export class ListSuggestedExtensionsAction extends Action {
// static ID = 'workbench.extensions.action.listSuggestedExtensions';
// static LABEL = nls.localize('showExtensionRecommendations', "Show Extension Recommendations");
// constructor(
// id: string,
// label: string,
// @IExtensionManagementService private extensionManagementService: IExtensionManagementService,
// @IQuickOpenService private quickOpenService: IQuickOpenService
// ) {
// super(id, label, null, true);
// }
// run(): Promise {
// return this.quickOpenService.show('ext recommend ');
// }
// protected isEnabled(): boolean {
// return true;
// }
// }
export class InstallAction extends Action {
constructor(
label: string,
@IQuickOpenService protected quickOpenService: IQuickOpenService,
@IExtensionManagementService protected extensionManagementService: IExtensionManagementService,
@IMessageService protected messageService: IMessageService,
@ITelemetryService protected telemetryService: ITelemetryService,
@IInstantiationService protected instantiationService: IInstantiationService
) {
super('extensions.install', label, 'octicon octicon-cloud-download', true);
}
private disposables: IDisposable[] = [];
run(extension: IGalleryExtension): TPromise<any> {
this.enabled = false;
return this.extensionManagementService.getInstalled()
.then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension)))
.then(isUpdate => {
return this.extensionManagementService
.install(extension)
.then(() => this.onSuccess(extension, isUpdate), err => this.onError(err, extension, isUpdate))
.then(() => this.enabled = true)
.then(() => null);
});
}
constructor(private model: ExtensionsModel, private extension: IExtension) {
super('extensions.install', nls.localize('installAction', "Install"), 'octicon octicon-cloud-download', false);
private onSuccess(extension: IGalleryExtension, isUpdate: boolean) {
this.reportTelemetry(extension, isUpdate, true);
this.messageService.show(Severity.Info, {
message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.displayName || extension.name),
actions: [
CloseAction,
this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow', "Restart Now"))
]
});
this.disposables.push(this.model.onChange(() => this.updateEnablement()));
this.updateEnablement();
}
private onError(err: Error, extension: IGalleryExtension, isUpdate: boolean) {
this.reportTelemetry(extension, isUpdate, false);
this.messageService.show(Severity.Error, err);
private updateEnablement(): void {
this.enabled = this.extension.state === ExtensionState.Uninstalled;
}
private reportTelemetry(extension: IGalleryExtension, isUpdate: boolean, success: boolean) {
const event = isUpdate ? 'extensionGallery:update' : 'extensionGallery:install';
const data = assign(getTelemetryData(extension), { success });
run(): TPromise<any> {
return this.model.install(this.extension);
this.telemetryService.publicLog(event, data);
}
}
export class UninstallAction extends Action {
// this.enabled = false;
constructor(
@IQuickOpenService protected quickOpenService: IQuickOpenService,
@IExtensionManagementService protected extensionManagementService: IExtensionManagementService,
@IMessageService protected messageService: IMessageService,
@ITelemetryService protected telemetryService: ITelemetryService,
@IInstantiationService protected instantiationService: IInstantiationService
) {
super('extensions.uninstall', nls.localize('uninstall', "Uninstall Extension"), 'octicon octicon-x', true);
// return this.extensionManagementService.getInstalled()
// .then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension)))
// .then(isUpdate => {
// return this.extensionManagementService
// .install(extension)
// .then(() => this.onSuccess(extension, isUpdate), err => this.onError(err, extension, isUpdate))
// .then(() => this.enabled = true)
// .then(() => null);
// });
}
run(extension: ILocalExtension): TPromise<any> {
const name = extension.manifest.displayName || extension.manifest.name;
if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", name))) {
return TPromise.as(null);
}
// private onSuccess(extension: IGalleryExtension, isUpdate: boolean) {
// this.reportTelemetry(extension, isUpdate, true);
// this.messageService.show(Severity.Info, {
// message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.displayName || extension.name),
// actions: [
// CloseAction,
// this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow', "Restart Now"))
// ]
// });
// }
this.enabled = false;
// private onError(err: Error, extension: IGalleryExtension, isUpdate: boolean) {
// this.reportTelemetry(extension, isUpdate, false);
// this.messageService.show(Severity.Error, err);
// }
return this.extensionManagementService.getInstalled().then(localExtensions => {
const [local] = localExtensions.filter(local => extensionEquals(local.manifest, extension.manifest));
// private reportTelemetry(extension: IGalleryExtension, isUpdate: boolean, success: boolean) {
// const event = isUpdate ? 'extensionGallery:update' : 'extensionGallery:install';
// const data = assign(getTelemetryData(extension), { success });
if (!local) {
return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", name));
}
// this.telemetryService.publicLog(event, data);
// }
return this.extensionManagementService.uninstall(local)
.then(() => this.onSuccess(local), err => this.onError(err, local))
.then(() => this.enabled = true)
.then(() => null);
});
}
private onSuccess(extension: ILocalExtension) {
const name = extension.manifest.displayName || extension.manifest.name;
this.reportTelemetry(extension, true);
this.messageService.show(Severity.Info, {
message: nls.localize('success-uninstalled', "'{0}' was successfully uninstalled. Restart to deactivate it.", name),
actions: [
CloseAction,
this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow2', "Restart Now"))
]
});
}
private onError(err: Error, extension: ILocalExtension) {
this.reportTelemetry(extension, false);
this.messageService.show(Severity.Error, err);
}
private reportTelemetry(extension: ILocalExtension, success: boolean) {
const data = assign(getTelemetryData(extension), { success });
this.telemetryService.publicLog('extensionGallery:uninstall', data);
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
// export class UninstallAction extends Action {
// constructor(
// @IQuickOpenService protected quickOpenService: IQuickOpenService,
// @IExtensionManagementService protected extensionManagementService: IExtensionManagementService,
// @IMessageService protected messageService: IMessageService,
// @ITelemetryService protected telemetryService: ITelemetryService,
// @IInstantiationService protected instantiationService: IInstantiationService
// ) {
// super('extensions.uninstall', nls.localize('uninstall', "Uninstall Extension"), 'octicon octicon-x', true);
// }
// run(extension: ILocalExtension): TPromise<any> {
// const name = extension.manifest.displayName || extension.manifest.name;
// if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", name))) {
// return TPromise.as(null);
// }
// this.enabled = false;
// return this.extensionManagementService.getInstalled().then(localExtensions => {
// const [local] = localExtensions.filter(local => extensionEquals(local.manifest, extension.manifest));
// if (!local) {
// return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", name));
// }
// return this.extensionManagementService.uninstall(local)
// .then(() => this.onSuccess(local), err => this.onError(err, local))
// .then(() => this.enabled = true)
// .then(() => null);
// });
// }
// private onSuccess(extension: ILocalExtension) {
// const name = extension.manifest.displayName || extension.manifest.name;
// this.reportTelemetry(extension, true);
// this.messageService.show(Severity.Info, {
// message: nls.localize('success-uninstalled', "'{0}' was successfully uninstalled. Restart to deactivate it.", name),
// actions: [
// CloseAction,
// this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow2', "Restart Now"))
// ]
// });
// }
// private onError(err: Error, extension: ILocalExtension) {
// this.reportTelemetry(extension, false);
// this.messageService.show(Severity.Error, err);
// }
// private reportTelemetry(extension: ILocalExtension, success: boolean) {
// const data = assign(getTelemetryData(extension), { success });
// this.telemetryService.publicLog('extensionGallery:uninstall', data);
// }
// }
......@@ -6,10 +6,13 @@
'use strict';
import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDelegate } from 'vs/base/browser/ui/list/list';
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { IExtension } from './extensionsModel';
import { IExtension, ExtensionsModel } from './extensionsModel';
import { InstallAction } from './extensionsActions';
export interface ITemplateData {
extension: IExtension;
......@@ -19,6 +22,8 @@ export interface ITemplateData {
version: HTMLElement;
author: HTMLElement;
description: HTMLElement;
actionbar: ActionBar;
disposables: IDisposable[];
}
export class Delegate implements IDelegate<IExtension> {
......@@ -32,6 +37,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
get templates(): ITemplateData[] { return this._templates; }
constructor(
private model: ExtensionsModel,
@IInstantiationService private instantiationService: IInstantiationService
) {
this._templates = [];
......@@ -48,13 +54,17 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const version = append(header, $('span.version.ellipsis'));
const author = append(header, $('span.author.ellipsis'));
const description = append(details, $('.description.ellipsis'));
const result = { extension: null, element, icon, name, version, author, description };
const actionbar = new ActionBar(details);
const disposables = [];
const result = { extension: null, element, icon, name, version, author, description, actionbar, disposables };
this._templates.push(result);
return result;
}
renderPlaceholder(index: number, data: ITemplateData): void {
data.disposables = dispose(data.disposables);
addClass(data.element, 'loading');
data.extension = null;
data.icon.src = '';
......@@ -62,17 +72,21 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
data.version.textContent = '';
data.author.textContent = '';
data.description.textContent = '';
data.actionbar.clear();
}
renderElement(extension: IExtension, index: number, data: ITemplateData): void {
data.extension = extension;
removeClass(data.element, 'loading');
data.disposables = dispose(data.disposables);
removeClass(data.element, 'loading');
data.extension = extension;
data.icon.src = extension.iconUrl;
data.name.textContent = extension.displayName;
data.version.textContent = extension.version;
data.author.textContent = extension.publisherDisplayName;
data.description.textContent = extension.description;
data.actionbar.clear();
data.actionbar.push(new InstallAction(this.model, extension));
}
disposeTemplate(data: ITemplateData): void {
......
......@@ -21,6 +21,7 @@ export enum ExtensionState {
}
export interface IExtension {
state: ExtensionState;
name: string;
displayName: string;
publisher: string;
......@@ -30,14 +31,17 @@ export interface IExtension {
iconUrl: string;
}
interface IExtensionStateProvider {
(extension: Extension): ExtensionState;
}
class Extension implements IExtension {
constructor(
private stateProvider: IExtensionStateProvider,
public local: ILocalExtension,
public gallery: IGalleryExtension = null
) {
}
) {}
get name(): string {
return this.local ? this.local.manifest.name : this.gallery.name;
......@@ -86,22 +90,28 @@ class Extension implements IExtension {
return require.toUrl('./media/defaultIcon.png');
}
get state(): ExtensionState {
return this.stateProvider(this);
}
}
export class ExtensionsModel {
private disposables: IDisposable[] = [];
private installing: { id: string; extension: Extension; }[];
private stateProvider: IExtensionStateProvider;
private installing: { id: string; extension: Extension; }[] = [];
private installed: Extension[] = [];
private _onChange: Emitter<void>;
private _onChange: Emitter<void> = new Emitter<void>();
get onChange(): Event<void> { return this._onChange.event; }
constructor(
@IExtensionManagementService private extensionService: IExtensionManagementService,
@IExtensionGalleryService private galleryService: IExtensionGalleryService
) {
this.stateProvider = ext => this.getExtensionState(ext);
this.disposables.push(extensionService.onInstallExtension(({ id, gallery }) => this.onInstallExtension(id, gallery)));
this.disposables.push(extensionService.onDidInstallExtension(({ id, local, error }) => this.onDidInstallExtension(id, local, error)));
}
......@@ -112,7 +122,7 @@ export class ExtensionsModel {
this.installed = result.map(local => {
const id = local.path;
const extension = installedById[id] || new Extension(local);
const extension = installedById[id] || new Extension(this.stateProvider, local);
extension.local = local;
return extension;
});
......@@ -134,27 +144,24 @@ export class ExtensionsModel {
return installed;
}
return new Extension(null, gallery);
return new Extension(this.stateProvider, null, gallery);
});
});
}
getState(extension: IExtension): ExtensionState {
install(extension: IExtension): TPromise<void> {
if (!(extension instanceof Extension)) {
return;
}
const ext = extension as Extension;
const gallery = ext.gallery;
if (this.installed.indexOf(ext) > -1) {
return ExtensionState.Installed;
}
if (this.installing.some(e => e.extension === ext)) {
return ExtensionState.Installing;
if (!gallery) {
return TPromise.wrapError<void>(new Error('Missing gallery'));
}
return ExtensionState.Uninstalled;
return this.extensionService.install(gallery);
}
private onInstallExtension(id: string, gallery: IGalleryExtension): void {
......@@ -165,7 +172,7 @@ export class ExtensionsModel {
let extension = this.installed.filter(e => (e.local.metadata && e.local.metadata.id) === gallery.id)[0];
if (!extension) {
extension = new Extension(null, gallery);
extension = new Extension(this.stateProvider, null, gallery);
}
extension.gallery = gallery;
......@@ -190,6 +197,18 @@ export class ExtensionsModel {
this._onChange.fire();
}
private getExtensionState(extension: Extension): ExtensionState {
if (this.installed.indexOf(extension) > -1) {
return ExtensionState.Installed;
}
if (this.installing.some(e => e.extension === extension)) {
return ExtensionState.Installing;
}
return ExtensionState.Uninstalled;
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
......
......@@ -62,7 +62,7 @@ export class ExtensionsViewlet extends Viewlet {
this.extensionsBox = append(this.root, $('.extensions'));
const delegate = new Delegate();
const renderer = this.instantiationService.createInstance(Renderer);
const renderer = this.instantiationService.createInstance(Renderer, this.model);
this.list = new PagedList(this.extensionsBox, delegate, [renderer]);
this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value);
......
......@@ -5,18 +5,14 @@
import nls = require('vs/nls');
import errors = require('vs/base/common/errors');
import platform = require('vs/platform/platform');
import { Promise } from 'vs/base/common/winjs.base';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, ExtensionsLabel } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IMessageService } from 'vs/platform/message/common/message';
import Severity from 'vs/base/common/severity';
import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService';
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import wbaregistry = require('vs/workbench/common/actionRegistry');
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { ListExtensionsAction } from './extensionsActions';
import {ipcRenderer as ipc} from 'electron';
interface IInstallExtensionsRequest {
......@@ -41,8 +37,8 @@ export class ExtensionsWorkbenchExtension implements IWorkbenchContribution {
this.install(options.extensionsToInstall).done(null, errors.onUnexpectedError);
}
const actionRegistry = (<wbaregistry.IWorkbenchActionRegistry> platform.Registry.as(wbaregistry.Extensions.WorkbenchActions));
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListExtensionsAction, ListExtensionsAction.ID, ListExtensionsAction.LABEL), 'Extensions: Show Installed Extensions', ExtensionsLabel);
// const actionRegistry = (<wbaregistry.IWorkbenchActionRegistry> platform.Registry.as(wbaregistry.Extensions.WorkbenchActions));
// actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListExtensionsAction, ListExtensionsAction.ID, ListExtensionsAction.LABEL), 'Extensions: Show Installed Extensions', ExtensionsLabel);
}
private registerListeners(): void {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册