simple ext tips, contexts in extension viewlet

This commit is contained in:
Joao Moreno
2016-08-25 17:27:28 +02:00
parent 9d707575db
commit 5d57dce327
5 changed files with 78 additions and 51 deletions
@@ -200,7 +200,7 @@ export const IExtensionTipsService = createDecorator<IExtensionTipsService>('ext
export interface IExtensionTipsService {
_serviceBrand: any;
getRecommendations(): TPromise<IGalleryExtension[]>;
getRecommendations(): string[];
}
export const ExtensionsLabel = nls.localize('extensions', "Extensions");
@@ -10,7 +10,7 @@ import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import {TPromise as Promise} from 'vs/base/common/winjs.base';
import {Action} from 'vs/base/common/actions';
import {match} from 'vs/base/common/glob';
import {IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, IGalleryExtension} from 'vs/platform/extensionManagement/common/extensionManagement';
import {IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService} from 'vs/platform/extensionManagement/common/extensionManagement';
import {IModelService} from 'vs/editor/common/services/modelService';
import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage';
import product from 'vs/platform/product';
@@ -72,15 +72,8 @@ export class ExtensionTipsService implements IExtensionTipsService {
this._modelService.getModels().forEach(model => this._suggest(model.uri));
}
getRecommendations(): Promise<IGalleryExtension[]> {
const names = Object.keys(this._recommendations);
if (names.length === 0) {
return Promise.as([]);
}
return this._galleryService.query({ names, pageSize: names.length })
.then(result => result.firstPage, () => []);
getRecommendations(): string[] {
return Object.keys(this._recommendations);
}
private _suggest(uri: URI): Promise<any> {
@@ -54,7 +54,6 @@ export interface IExtensionsWorkbenchService {
local: IExtension[];
queryLocal(): TPromise<IExtension[]>;
queryGallery(options?: IQueryOptions): TPromise<IPager<IExtension>>;
getRecommendations(): TPromise<IExtension[]>;
canInstall(extension: IExtension): boolean;
install(extension: IExtension): TPromise<void>;
uninstall(extension: IExtension): TPromise<void>;
@@ -19,14 +19,14 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Viewlet } from 'vs/workbench/browser/viewlet';
import { append, $, addStandardDisposableListener, EventType, addClass, removeClass, toggleClass } from 'vs/base/browser/dom';
import { IPager, PagedModel } from 'vs/base/common/paging';
import { PagedModel } from 'vs/base/common/paging';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { PagedList } from 'vs/base/browser/ui/list/listPaging';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Delegate, Renderer } from './extensionsList';
import { IExtensionsWorkbenchService, IExtension, IExtensionsViewlet, VIEWLET_ID } from './extensions';
import { ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction } from './extensionsActions';
import { IExtensionManagementService, IExtensionGalleryService, SortBy } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, SortBy, IQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionsInput } from './extensionsInput';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -38,6 +38,54 @@ interface SearchInputEvent extends Event {
immediate?: boolean;
}
interface IContext {
query(): TPromise<PagedModel<IExtension>>;
}
class LocalContext implements IContext {
constructor(private value: string, private extensionsWorkbenchService: IExtensionsWorkbenchService) {}
query(): TPromise<PagedModel<IExtension>> {
let local = this.extensionsWorkbenchService.queryLocal();
if (/@outdated/i.test(this.value)) {
local = local.then(result => result.filter(e => e.outdated));
}
return local.then(result => new PagedModel(result));
}
}
class GalleryContext implements IContext {
constructor(
private value: string,
private extensionsWorkbenchService: IExtensionsWorkbenchService,
private tipsService: IExtensionTipsService
) {}
query(): TPromise<PagedModel<IExtension>> {
let options: TPromise<IQueryOptions> = null;
if (/@popular/i.test(this.value)) {
options = TPromise.as({ sortBy: SortBy.InstallCount });
} else if (/@recommended/i.test(this.value)) {
options = this.extensionsWorkbenchService.queryLocal().then(local => {
const names = this.tipsService.getRecommendations()
.filter(name => local.every(ext => `${ ext.publisher }.${ ext.name }` !== name));
return { names, pageSize: names.length };
});
} else {
options = TPromise.as({ text: this.value });
}
return this.extensionsWorkbenchService.queryGallery(options)
.then(result => new PagedModel(result));
}
}
export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet {
private onSearchChange: EventOf<string>;
@@ -58,7 +106,8 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet {
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
@IURLService urlService: IURLService
@IURLService urlService: IURLService,
@IExtensionTipsService private tipsService: IExtensionTipsService
) {
super(VIEWLET_ID, telemetryService);
this.searchDelayer = new ThrottledDelayer(500);
@@ -172,35 +221,25 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet {
}
private doSearch(value: string = '', suggestPopular = false): TPromise<any> {
const progressRunner = this.progressService.show(true);
let promise: TPromise<IPager<IExtension> | IExtension[]>;
const context = this.getContext(value);
const promise = this.progress(context.query());
if (!value) {
promise = this.extensionsWorkbenchService.queryLocal()
.then(result => {
if (result.length === 0 && suggestPopular) {
this.search('@popular', true);
}
return promise.then(model => {
if (context instanceof LocalContext && model.length === 0 && suggestPopular) {
return this.search('@popular', true);
}
return result;
});
} else if (/@outdated/i.test(value)) {
promise = this.extensionsWorkbenchService.queryLocal()
.then(result => result.filter(e => e.outdated));
} else if (/@popular/i.test(value)) {
promise = this.extensionsWorkbenchService.queryGallery({ sortBy: SortBy.InstallCount });
} else if (/@recommended/i.test(value)) {
promise = this.extensionsWorkbenchService.getRecommendations();
this.list.model = model;
this.list.scrollTop = 0;
});
}
private getContext(value: string): IContext {
if (!value || /@outdated/i.test(value)) {
return new LocalContext(value, this.extensionsWorkbenchService);
} else {
promise = this.extensionsWorkbenchService.queryGallery({ text: value });
return new GalleryContext(value, this.extensionsWorkbenchService, this.tipsService);
}
return always(promise, () => progressRunner.done())
.then(result => new PagedModel<IExtension>(result))
.then(model => {
this.list.model = model;
this.list.scrollTop = 0;
});
}
private openExtension(extension: IExtension): void {
@@ -256,6 +295,11 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet {
});
}
private progress<T>(promise: TPromise<T>): TPromise<T> {
const progressRunner = this.progressService.show(true);
return always(promise, () => progressRunner.done());
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
@@ -14,7 +14,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest } from 'vs/platform/extensionManagement/common/extensionManagement';
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionTelemetry';
import * as semver from 'semver';
import * as path from 'path';
@@ -217,8 +217,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
constructor(
@IExtensionManagementService private extensionService: IExtensionManagementService,
@IExtensionGalleryService private galleryService: IExtensionGalleryService,
@ITelemetryService private telemetryService: ITelemetryService,
@IExtensionTipsService private tipsService: IExtensionTipsService
@ITelemetryService private telemetryService: ITelemetryService
) {
this.stateProvider = ext => this.getExtensionState(ext);
@@ -267,14 +266,6 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
});
}
getRecommendations(): TPromise<IExtension[]> {
return this.tipsService.getRecommendations()
.then(result => result
.map(gallery => this.fromGallery(gallery))
.filter(extension => extension.state === ExtensionState.Uninstalled)
);
}
private fromGallery(gallery: IGalleryExtension): Extension {
const installedByGalleryId = index(this.installed, e => e.local.metadata ? e.local.metadata.id : '');
const id = gallery.id;