From 5d57dce327b84d019bc34b2de02df4a4be87758a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 25 Aug 2016 15:34:02 +0200 Subject: [PATCH] simple ext tips, contexts in extension viewlet --- .../common/extensionManagement.ts | 2 +- .../electron-browser/extensionTipsService.ts | 13 +-- .../extensions/electron-browser/extensions.ts | 1 - .../electron-browser/extensionsViewlet.ts | 100 +++++++++++++----- .../extensionsWorkbenchService.ts | 13 +-- 5 files changed, 78 insertions(+), 51 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 57c8dfc78f4..644e6c6ddf8 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -200,7 +200,7 @@ export const IExtensionTipsService = createDecorator('ext export interface IExtensionTipsService { _serviceBrand: any; - getRecommendations(): TPromise; + getRecommendations(): string[]; } export const ExtensionsLabel = nls.localize('extensions', "Extensions"); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 91d7bcfd993..4af77ab5c32 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -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 { - 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 { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts index 8aa02725c6f..d12377a515e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts @@ -54,7 +54,6 @@ export interface IExtensionsWorkbenchService { local: IExtension[]; queryLocal(): TPromise; queryGallery(options?: IQueryOptions): TPromise>; - getRecommendations(): TPromise; canInstall(extension: IExtension): boolean; install(extension: IExtension): TPromise; uninstall(extension: IExtension): TPromise; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index e7910e2c5c1..6124eea3803 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -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>; +} + +class LocalContext implements IContext { + + constructor(private value: string, private extensionsWorkbenchService: IExtensionsWorkbenchService) {} + + query(): TPromise> { + 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> { + let options: TPromise = 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; @@ -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 { - const progressRunner = this.progressService.show(true); - let promise: TPromise | 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(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(promise: TPromise): TPromise { + const progressRunner = this.progressService.show(true); + return always(promise, () => progressRunner.done()); + } + dispose(): void { this.disposables = dispose(this.disposables); super.dispose(); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index c6989803a5b..e739b4e1766 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -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 { - 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;