mirror of
https://github.com/Microsoft/vscode
synced 2024-10-04 10:27:46 +00:00
- Have only single installed extension
- Exclude not supported extensions - Show remote badge
This commit is contained in:
parent
2a0a6ebad9
commit
9cc66db3c6
|
@ -1,135 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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/extensionsWidgets';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer } from '../common/extensions';
|
||||
import { append, $, addClass } from 'vs/base/browser/dom';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
|
||||
private _extension: IExtension;
|
||||
get extension(): IExtension { return this._extension; }
|
||||
set extension(extension: IExtension) { this._extension = extension; this.update(); }
|
||||
update(): void { this.render(); }
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
export class Label extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private element: HTMLElement,
|
||||
private fn: (extension: IExtension) => string,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
) {
|
||||
super();
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.element.textContent = this.extension ? this.fn(this.extension) : '';
|
||||
}
|
||||
}
|
||||
|
||||
export class InstallCountWidget extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
private small: boolean,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
) {
|
||||
super();
|
||||
addClass(container, 'extension-install-count');
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.container.innerHTML = '';
|
||||
|
||||
if (!this.extension) {
|
||||
return;
|
||||
}
|
||||
|
||||
const installCount = this.extension.installCount;
|
||||
|
||||
if (installCount === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let installLabel: string;
|
||||
|
||||
if (this.small) {
|
||||
if (installCount > 1000000) {
|
||||
installLabel = `${Math.floor(installCount / 100000) / 10}M`;
|
||||
} else if (installCount > 1000) {
|
||||
installLabel = `${Math.floor(installCount / 1000)}K`;
|
||||
} else {
|
||||
installLabel = String(installCount);
|
||||
}
|
||||
}
|
||||
else {
|
||||
installLabel = installCount.toLocaleString(platform.locale);
|
||||
}
|
||||
|
||||
append(this.container, $('span.octicon.octicon-cloud-download'));
|
||||
const count = append(this.container, $('span.count'));
|
||||
count.textContent = installLabel;
|
||||
}
|
||||
}
|
||||
|
||||
export class RatingsWidget extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
private small: boolean,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
) {
|
||||
super();
|
||||
addClass(container, 'extension-ratings');
|
||||
|
||||
if (this.small) {
|
||||
addClass(container, 'small');
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.container.innerHTML = '';
|
||||
|
||||
if (!this.extension) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.extension.rating === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.small && !this.extension.ratingCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rating = Math.round(this.extension.rating * 2) / 2;
|
||||
|
||||
if (this.small) {
|
||||
append(this.container, $('span.full.star'));
|
||||
|
||||
const count = append(this.container, $('span.count'));
|
||||
count.textContent = String(rating);
|
||||
} else {
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
if (rating >= i) {
|
||||
append(this.container, $('span.full.star'));
|
||||
} else if (rating >= i - 0.5) {
|
||||
append(this.container, $('span.half.star'));
|
||||
} else {
|
||||
append(this.container, $('span.empty.star'));
|
||||
}
|
||||
}
|
||||
}
|
||||
this.container.title = this.extension.ratingCount > 1 ? localize('ratedByUsers', "Rated by {0} users", this.extension.ratingCount) : localize('ratedBySingleUser', "Rated by 1 user");
|
||||
}
|
||||
}
|
|
@ -60,7 +60,6 @@ export interface IExtension {
|
|||
getChangelog(token: CancellationToken): Promise<string>;
|
||||
hasChangelog(): boolean;
|
||||
local?: ILocalExtension;
|
||||
locals?: ILocalExtension[];
|
||||
gallery?: IGalleryExtension;
|
||||
isMalicious: boolean;
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ import { IExtensionManifest, IKeyBinding, IView, IViewContainer, ExtensionType }
|
|||
import { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, IExtensionDependencies, ExtensionContainers } from 'vs/workbench/parts/extensions/common/extensions';
|
||||
import { RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets';
|
||||
import { RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/electron-browser/extensionsWidgets';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, DisabledStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { WebviewElement } from 'vs/workbench/parts/webview/electron-browser/webviewElement';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
|
@ -357,18 +357,17 @@ export class ExtensionEditor extends BaseEditor {
|
|||
const actions = [
|
||||
reloadAction,
|
||||
this.instantiationService.createInstance(UpdateAction),
|
||||
this.instantiationService.createInstance(EnableDropDownAction, runningExtensions),
|
||||
this.instantiationService.createInstance(EnableDropDownAction),
|
||||
this.instantiationService.createInstance(DisableDropDownAction, runningExtensions),
|
||||
this.instantiationService.createInstance(CombinedInstallAction),
|
||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, true),
|
||||
this.instantiationService.createInstance(DisabledStatusLabelAction, runningExtensions)
|
||||
];
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||
extensionContainers.extension = extension;
|
||||
|
||||
this.extensionActionBar.clear();
|
||||
this.extensionActionBar.push(actions, { icon: true, label: true });
|
||||
this.transientDisposables.push(...[...actions, extensionContainers]);
|
||||
this.transientDisposables.push(...[...actions, ...widgets, extensionContainers]);
|
||||
|
||||
this.setSubText(extension, reloadAction);
|
||||
this.content.innerHTML = ''; // Clear content before setting navbar actions.
|
||||
|
|
|
@ -16,9 +16,9 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
|||
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer } from 'vs/workbench/parts/extensions/common/extensions';
|
||||
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extensions/common/extensionsFileTemplate';
|
||||
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionManagementServerService, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { isUIExtension, ExtensionIdentifier, ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
|
@ -54,9 +54,6 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
|||
import { clipboard } from 'electron';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
|
||||
const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error, instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService) => {
|
||||
|
@ -515,7 +512,7 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
|
|||
const groups: ExtensionAction[][] = [];
|
||||
groups.push([
|
||||
this.instantiationService.createInstance(EnableGloballyAction),
|
||||
this.instantiationService.createInstance(CombinedEnableForWorkspaceAction, runningExtensions)
|
||||
this.instantiationService.createInstance(EnableForWorkspaceAction)
|
||||
]);
|
||||
groups.push([
|
||||
this.instantiationService.createInstance(DisableGloballyAction, runningExtensions),
|
||||
|
@ -630,50 +627,6 @@ export class ExtensionInfoAction extends ExtensionAction {
|
|||
}
|
||||
}
|
||||
|
||||
export class CombinedEnableForWorkspaceAction extends ExtensionAction {
|
||||
|
||||
static readonly ID = 'extensions.enableForWorkspace';
|
||||
static LABEL = localize('enableForWorkspaceAction', "Enable (Workspace)");
|
||||
|
||||
private enableForWorkspaceAction: EnableForWorkspaceAction;
|
||||
private installInRemoteServerAction: InstallInRemoteServerAction;
|
||||
|
||||
constructor(readonly runningExtensions: IExtensionDescription[],
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super(CombinedEnableForWorkspaceAction.ID, CombinedEnableForWorkspaceAction.LABEL);
|
||||
|
||||
this.enableForWorkspaceAction = instantiationService.createInstance(EnableForWorkspaceAction);
|
||||
this.installInRemoteServerAction = instantiationService.createInstance(InstallInRemoteServerAction, runningExtensions);
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enableForWorkspaceAction.extension = this.extension;
|
||||
this.installInRemoteServerAction.extension = this.extension;
|
||||
this.enableForWorkspaceAction.update();
|
||||
this.installInRemoteServerAction.update();
|
||||
this.enabled = this.installInRemoteServerAction.enabled || this.enableForWorkspaceAction.enabled;
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
if (this.installInRemoteServerAction.enabled) {
|
||||
return this.installInRemoteServerAction.run();
|
||||
}
|
||||
if (this.enableForWorkspaceAction.enabled) {
|
||||
return this.enableForWorkspaceAction.run();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this.enableForWorkspaceAction.dispose();
|
||||
this.installInRemoteServerAction.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class EnableForWorkspaceAction extends ExtensionAction {
|
||||
|
||||
static readonly ID = 'extensions.enableForWorkspace';
|
||||
|
@ -699,65 +652,6 @@ export class EnableForWorkspaceAction extends ExtensionAction {
|
|||
}
|
||||
}
|
||||
|
||||
export class InstallInRemoteServerAction extends ExtensionAction {
|
||||
|
||||
static readonly ID = 'extensions.installInRemoteServerAction';
|
||||
static LABEL = localize('enableForWorkspaceAction', "Enable (Workspace)");
|
||||
|
||||
constructor(readonly runningExtensions: IExtensionDescription[],
|
||||
@IExtensionsWorkbenchService extensionWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
) {
|
||||
super(InstallInRemoteServerAction.ID, InstallInRemoteServerAction.LABEL);
|
||||
this.update();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer
|
||||
&& this.extension && this.extension.locals && this.extension.locals.length > 0
|
||||
&& !isUIExtension(this.extension.locals[0].manifest, this.configurationService)
|
||||
&& this.extension.state === ExtensionState.Installed) {
|
||||
const installedInRemoteServer = this.extension.locals.some(local => {
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(local.location);
|
||||
return !!server && server.authority === this.extensionManagementServerService.remoteExtensionManagementServer!.authority;
|
||||
});
|
||||
if (!installedInRemoteServer) {
|
||||
this.enabled = !this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async run(): Promise<any> {
|
||||
if (!this.enabled) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (this.storageService.getBoolean('askToInstallRemoteServerExtension', StorageScope.GLOBAL, true)) {
|
||||
const message = localize('install extension', "Enabling the '{0}' extension will also install it in {1}. Would you like to continue?", this.extension.displayName, this.labelService.getHostLabel() || this.extensionManagementServerService.remoteExtensionManagementServer!.authority);
|
||||
const response = await this.dialogService.confirm({ type: 'info', message, checkbox: { label: localize('do not ask me again', "Do not ask me again") } });
|
||||
if (!response || !response.confirmed) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (response.checkboxChecked) {
|
||||
this.storageService.store('askToInstallRemoteServerExtension', false, StorageScope.GLOBAL);
|
||||
}
|
||||
}
|
||||
const galleryExtension = this.extension.gallery ? this.extension.gallery : await this.extensionGalleryService.getExtension(this.extension.local!.identifier);
|
||||
if (galleryExtension) {
|
||||
return this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.installFromGallery(galleryExtension);
|
||||
} else {
|
||||
const zipLocation = await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.zip(this.extension.local!);
|
||||
return this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.unzip(zipLocation, this.extension.type!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class EnableGloballyAction extends ExtensionAction {
|
||||
|
||||
static readonly ID = 'extensions.enableGlobally';
|
||||
|
@ -765,9 +659,7 @@ export class EnableGloballyAction extends ExtensionAction {
|
|||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
) {
|
||||
super(EnableGloballyAction.ID, EnableGloballyAction.LABEL);
|
||||
this.update();
|
||||
|
@ -775,15 +667,7 @@ export class EnableGloballyAction extends ExtensionAction {
|
|||
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
if (this.extension && this.extension.locals && this.extension.local) {
|
||||
if (!isUIExtension(this.extension.local.manifest, this.configurationService) && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
if (!this.extension.locals.some(local => {
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(local.location);
|
||||
return !!server && server.authority === this.extensionManagementServerService.remoteExtensionManagementServer!.authority;
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.extension && this.extension.local) {
|
||||
this.enabled = this.extension.state === ExtensionState.Installed && this.extension.enablementState === EnablementState.Disabled && this.extensionEnablementService.canChangeEnablement(this.extension.local);
|
||||
}
|
||||
}
|
||||
|
@ -891,12 +775,11 @@ export abstract class ExtensionEditorDropDownAction extends ExtensionDropDownAct
|
|||
export class EnableDropDownAction extends ExtensionEditorDropDownAction {
|
||||
|
||||
constructor(
|
||||
runningExtensions: IExtensionDescription[],
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super('extensions.enable', localize('enableAction', "Enable"), [
|
||||
instantiationService.createInstance(EnableGloballyAction),
|
||||
instantiationService.createInstance(CombinedEnableForWorkspaceAction, runningExtensions)
|
||||
instantiationService.createInstance(EnableForWorkspaceAction)
|
||||
], instantiationService);
|
||||
}
|
||||
}
|
||||
|
@ -1080,9 +963,7 @@ export class ReloadAction extends ExtensionAction {
|
|||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
) {
|
||||
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
|
||||
this.throttler = new Throttler();
|
||||
|
@ -1136,33 +1017,14 @@ export class ReloadAction extends ExtensionAction {
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
const uiExtension = isUIExtension(installed.local.manifest, this.configurationService);
|
||||
if (!isDisabled) {
|
||||
let enableReload = true;
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer && installed.locals) {
|
||||
if (uiExtension) {
|
||||
// Only UI extension from local server requires reload if it is not running on the server
|
||||
enableReload = installed.locals.some(local => {
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(local.location);
|
||||
return !!server && server.authority === this.extensionManagementServerService.localExtensionManagementServer.authority;
|
||||
});
|
||||
} else {
|
||||
enableReload = installed.locals.some(local => {
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(local.location);
|
||||
return !!server && server.authority === this.extensionManagementServerService.remoteExtensionManagementServer!.authority;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (enableReload === true) {
|
||||
this.enabled = true;
|
||||
if (!isEnabled) {
|
||||
this.tooltip = localize('postInstallTooltip', "Please reload Visual Studio Code to complete the installation of this extension.");
|
||||
} else {
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to complete the enabling of this extension.");
|
||||
}
|
||||
return;
|
||||
this.enabled = true;
|
||||
if (!isEnabled) {
|
||||
this.tooltip = localize('postInstallTooltip', "Please reload Visual Studio Code to complete the installation of this extension.");
|
||||
} else {
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to complete the enabling of this extension.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -1661,44 +1523,6 @@ export class ChangeSortAction extends Action {
|
|||
}
|
||||
}
|
||||
|
||||
export class ChangeGroupAction extends Action {
|
||||
|
||||
private query: Query;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
onSearchChange: Event<string>,
|
||||
private groupBy: string,
|
||||
@IViewletService private readonly viewletService: IViewletService
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
|
||||
if (groupBy === undefined) {
|
||||
throw new Error('bad arguments');
|
||||
}
|
||||
|
||||
this.query = Query.parse('');
|
||||
onSearchChange(this.onSearchChange, this, this.disposables);
|
||||
this.onSearchChange('');
|
||||
}
|
||||
|
||||
private onSearchChange(value: string): void {
|
||||
const query = Query.parse(value);
|
||||
this.query = new Query(query.value, query.sortBy, this.groupBy || query.groupBy);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.viewletService.openViewlet(VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet as IExtensionsViewlet)
|
||||
.then(viewlet => {
|
||||
viewlet.search(this.query.toString());
|
||||
viewlet.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ConfigureRecommendedExtensionsCommandsContributor extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private workspaceContextKey = new RawContextKey<boolean>('workspaceRecommendations', true);
|
||||
|
@ -2235,43 +2059,6 @@ export class MaliciousStatusLabelAction extends ExtensionAction {
|
|||
}
|
||||
}
|
||||
|
||||
export class DisabledStatusLabelAction extends ExtensionAction {
|
||||
|
||||
private static readonly Class = 'disable-status';
|
||||
|
||||
constructor(
|
||||
private runningExtensions: IExtensionDescription[],
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ILabelService private readonly labelService: ILabelService
|
||||
) {
|
||||
super('extensions.install', localize('disabled', "Disabled"), `${DisabledStatusLabelAction.Class} hide`, false);
|
||||
this.update();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.class = `${DisabledStatusLabelAction.Class} hide`;
|
||||
this.tooltip = '';
|
||||
if (this.extension && this.extension.local && !this.extension.isMalicious && !this.runningExtensions.some(e => ExtensionIdentifier.equals(e.identifier, this.extension.identifier.id))) {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService) && this.extension.locals) {
|
||||
const installedInRemoteServer = this.extension.locals.some(local => {
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(local.location);
|
||||
return !!server && server.authority === this.extensionManagementServerService.remoteExtensionManagementServer!.authority;
|
||||
});
|
||||
if (!installedInRemoteServer) {
|
||||
this.class = `${DisabledStatusLabelAction.Class}`;
|
||||
this.label = localize('disabled NonUI Extension', "Disabled for this Workspace because it is not installed in {0}.", this.labelService.getHostLabel() || this.extensionManagementServerService.remoteExtensionManagementServer.authority);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class DisableAllAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.disableAll';
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { append, $, addClass, removeClass, toggleClass } from 'vs/base/browser/dom';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
|
@ -14,12 +13,11 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
|
|||
import { Event } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IExtension, IExtensionsWorkbenchService, ExtensionContainers } from 'vs/workbench/parts/extensions/common/extensions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, extensionButtonProminentBackground, extensionButtonProminentForeground, MaliciousStatusLabelAction, ExtensionActionItem } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { Label, RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets';
|
||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget } from 'vs/workbench/parts/extensions/electron-browser/extensionsWidgets';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionTipsService, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export interface IExtensionsViewState {
|
||||
|
@ -57,27 +55,17 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
) { }
|
||||
|
||||
get templateId() { return 'extension'; }
|
||||
|
||||
renderTemplate(root: HTMLElement): ITemplateData {
|
||||
const bookmark = append(root, $('span.bookmark'));
|
||||
append(bookmark, $('span.octicon.octicon-star'));
|
||||
const applyBookmarkStyle = (theme) => {
|
||||
const bgColor = theme.getColor(extensionButtonProminentBackground);
|
||||
const fgColor = theme.getColor(extensionButtonProminentForeground);
|
||||
bookmark.style.borderTopColor = bgColor ? bgColor.toString() : 'transparent';
|
||||
bookmark.style.color = fgColor ? fgColor.toString() : 'white';
|
||||
};
|
||||
applyBookmarkStyle(this.themeService.getTheme());
|
||||
const bookmarkStyler = this.themeService.onThemeChange(applyBookmarkStyle.bind(this));
|
||||
|
||||
const recommendationWidget = this.instantiationService.createInstance(RecommendationWidget, root);
|
||||
const element = append(root, $('.extension'));
|
||||
const icon = append(element, $<HTMLImageElement>('img.icon'));
|
||||
const iconContainer = append(element, $('.icon-container'));
|
||||
const icon = append(iconContainer, $<HTMLImageElement>('img.icon'));
|
||||
const badgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer);
|
||||
const details = append(element, $('.details'));
|
||||
const headerContainer = append(details, $('.header-container'));
|
||||
const header = append(headerContainer, $('.header'));
|
||||
|
@ -100,6 +88,8 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
|
||||
|
||||
const widgets = [
|
||||
recommendationWidget,
|
||||
badgeWidget,
|
||||
this.instantiationService.createInstance(Label, version, (e: IExtension) => e.version),
|
||||
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
||||
this.instantiationService.createInstance(RatingsWidget, ratings, true)
|
||||
|
@ -114,7 +104,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||
|
||||
actionbar.push(actions, actionOptions);
|
||||
const disposables = [...actions, ...widgets, actionbar, bookmarkStyler, extensionContainers];
|
||||
const disposables = [...actions, ...widgets, actionbar, extensionContainers];
|
||||
|
||||
return {
|
||||
root, element, icon, name, installCount, ratings, author, description, disposables, actionbar,
|
||||
|
@ -178,13 +168,6 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
data.icon.style.visibility = 'inherit';
|
||||
}
|
||||
|
||||
this.updateRecommendationStatus(extension, data);
|
||||
data.extensionDisposables.push(this.extensionTipsService.onRecommendationChange(change => {
|
||||
if (areSameExtensions({ id: change.extensionId }, extension.identifier)) {
|
||||
this.updateRecommendationStatus(extension, data);
|
||||
}
|
||||
}));
|
||||
|
||||
data.name.textContent = extension.displayName;
|
||||
data.author.textContent = extension.publisherDisplayName;
|
||||
data.description.textContent = extension.description;
|
||||
|
@ -209,24 +192,6 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
}, this, data.extensionDisposables);
|
||||
}
|
||||
|
||||
private updateRecommendationStatus(extension: IExtension, data: ITemplateData) {
|
||||
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
|
||||
let ariaLabel = extension.displayName + '. ';
|
||||
|
||||
if (!extRecommendations[extension.identifier.id.toLowerCase()]) {
|
||||
removeClass(data.root, 'recommended');
|
||||
data.root.title = '';
|
||||
} else {
|
||||
addClass(data.root, 'recommended');
|
||||
ariaLabel += extRecommendations[extension.identifier.id.toLowerCase()].reasonText + ' ';
|
||||
data.root.title = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
|
||||
}
|
||||
|
||||
ariaLabel += localize('viewExtensionDetailsAria', "Press enter for extension details.");
|
||||
data.root.setAttribute('aria-label', ariaLabel);
|
||||
|
||||
}
|
||||
|
||||
disposeTemplate(data: ITemplateData): void {
|
||||
data.disposables = dispose(data.disposables);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, ExtensionS
|
|||
import {
|
||||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction,
|
||||
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, ChangeGroupAction
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
|
||||
} from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput';
|
||||
|
@ -35,7 +35,7 @@ import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/servi
|
|||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ViewsRegistry, IViewDescriptor } from 'vs/workbench/common/views';
|
||||
import { ViewContainerViewlet, IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
@ -47,9 +47,6 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
|
|||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IAddedViewDescriptorRef } from 'vs/workbench/browser/parts/views/views';
|
||||
import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery';
|
||||
import { SuggestEnabledInput, attachSuggestEnabledInputBoxStyler } from 'vs/workbench/parts/codeEditor/electron-browser/suggestEnabledInput';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
|
@ -279,7 +276,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
private extensionsBox: HTMLElement;
|
||||
private primaryActions: IAction[];
|
||||
private secondaryActions: IAction[];
|
||||
private groupByServerAction: IAction;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
|
@ -297,8 +293,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, configurationService, partService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
|
||||
|
||||
|
@ -395,12 +390,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
|
||||
getSecondaryActions(): IAction[] {
|
||||
if (!this.secondaryActions) {
|
||||
if (!this.groupByServerAction) {
|
||||
this.groupByServerAction = this.instantiationService.createInstance(ChangeGroupAction, 'extensions.group.servers', localize('group by servers', "Group By: Server"), this.onSearchChange, 'server');
|
||||
this.disposables.push(this.onSearchChange(value => {
|
||||
this.groupByServerAction.enabled = !value || ExtensionsListView.isInstalledExtensionsQuery(value) || ExtensionsListView.isBuiltInExtensionsQuery(value);
|
||||
}));
|
||||
}
|
||||
this.secondaryActions = [
|
||||
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL),
|
||||
|
@ -414,7 +403,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Sort By: Rating"), this.onSearchChange, 'rating'),
|
||||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Sort By: Name"), this.onSearchChange, 'name'),
|
||||
new Separator(),
|
||||
...(this.extensionManagementServerService.remoteExtensionManagementServer ? [this.groupByServerAction, new Separator()] : []),
|
||||
this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL),
|
||||
...(this.configurationService.getValue(AutoUpdateConfigurationKey) ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]),
|
||||
this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL),
|
||||
|
@ -489,21 +477,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
}
|
||||
}
|
||||
|
||||
protected createView(viewDescriptor: IViewDescriptor, options: IViewletViewOptions): ViewletPanel {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
const extensionManagementServer = viewDescriptor.id === `server.extensionsList.${this.extensionManagementServerService.localExtensionManagementServer.authority}` ? this.extensionManagementServerService.localExtensionManagementServer
|
||||
: viewDescriptor.id === `server.extensionsList.${this.extensionManagementServerService.remoteExtensionManagementServer.authority}` ? this.extensionManagementServerService.remoteExtensionManagementServer : null;
|
||||
if (extensionManagementServer) {
|
||||
const servicesCollection: ServiceCollection = new ServiceCollection();
|
||||
servicesCollection.set(IExtensionManagementService, extensionManagementServer.extensionManagementService);
|
||||
servicesCollection.set(IExtensionsWorkbenchService, new SyncDescriptor(ExtensionsWorkbenchService));
|
||||
const instantiationService = this.instantiationService.createChild(servicesCollection);
|
||||
return instantiationService.createInstance(viewDescriptor.ctor, options, [extensionManagementServer]) as ViewletPanel;
|
||||
}
|
||||
}
|
||||
return this.instantiationService.createInstance(viewDescriptor.ctor, options) as ViewletPanel;
|
||||
}
|
||||
|
||||
private count(): number {
|
||||
return this.panels.reduce((count, view) => (<ExtensionsListView>view).count() + count, 0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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/extensionsWidgets';
|
||||
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer } from '../common/extensions';
|
||||
import { append, $, addClass } from 'vs/base/browser/dom';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { STATUS_BAR_HOST_NAME_BACKGROUND } from 'vs/workbench/parts/remote/electron-browser/remote.contribution';
|
||||
|
||||
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
|
||||
private _extension: IExtension;
|
||||
get extension(): IExtension { return this._extension; }
|
||||
set extension(extension: IExtension) { this._extension = extension; this.update(); }
|
||||
update(): void { this.render(); }
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
export class Label extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private element: HTMLElement,
|
||||
private fn: (extension: IExtension) => string,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
) {
|
||||
super();
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.element.textContent = this.extension ? this.fn(this.extension) : '';
|
||||
}
|
||||
}
|
||||
|
||||
export class InstallCountWidget extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
private small: boolean,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
) {
|
||||
super();
|
||||
addClass(container, 'extension-install-count');
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.container.innerHTML = '';
|
||||
|
||||
if (!this.extension) {
|
||||
return;
|
||||
}
|
||||
|
||||
const installCount = this.extension.installCount;
|
||||
|
||||
if (installCount === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let installLabel: string;
|
||||
|
||||
if (this.small) {
|
||||
if (installCount > 1000000) {
|
||||
installLabel = `${Math.floor(installCount / 100000) / 10}M`;
|
||||
} else if (installCount > 1000) {
|
||||
installLabel = `${Math.floor(installCount / 1000)}K`;
|
||||
} else {
|
||||
installLabel = String(installCount);
|
||||
}
|
||||
}
|
||||
else {
|
||||
installLabel = installCount.toLocaleString(platform.locale);
|
||||
}
|
||||
|
||||
append(this.container, $('span.octicon.octicon-cloud-download'));
|
||||
const count = append(this.container, $('span.count'));
|
||||
count.textContent = installLabel;
|
||||
}
|
||||
}
|
||||
|
||||
export class RatingsWidget extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
private small: boolean
|
||||
) {
|
||||
super();
|
||||
addClass(container, 'extension-ratings');
|
||||
|
||||
if (this.small) {
|
||||
addClass(container, 'small');
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.container.innerHTML = '';
|
||||
|
||||
if (!this.extension) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.extension.rating === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.small && !this.extension.ratingCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rating = Math.round(this.extension.rating * 2) / 2;
|
||||
|
||||
if (this.small) {
|
||||
append(this.container, $('span.full.star'));
|
||||
|
||||
const count = append(this.container, $('span.count'));
|
||||
count.textContent = String(rating);
|
||||
} else {
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
if (rating >= i) {
|
||||
append(this.container, $('span.full.star'));
|
||||
} else if (rating >= i - 0.5) {
|
||||
append(this.container, $('span.half.star'));
|
||||
} else {
|
||||
append(this.container, $('span.empty.star'));
|
||||
}
|
||||
}
|
||||
}
|
||||
this.container.title = this.extension.ratingCount > 1 ? localize('ratedByUsers', "Rated by {0} users", this.extension.ratingCount) : localize('ratedBySingleUser', "Rated by 1 user");
|
||||
}
|
||||
}
|
||||
|
||||
export class RecommendationWidget extends ExtensionWidget {
|
||||
|
||||
private element: HTMLElement;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
private parent: HTMLElement,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService
|
||||
) {
|
||||
super();
|
||||
this.render();
|
||||
this._register(toDisposable(() => this.clear()));
|
||||
}
|
||||
|
||||
private clear(): void {
|
||||
this.parent.title = '';
|
||||
this.parent.setAttribute('aria-label', this.extension ? localize('viewExtensionDetailsAria', "{0}. Press enter for extension details.", this.extension.displayName) : '');
|
||||
if (this.element) {
|
||||
this.parent.removeChild(this.element);
|
||||
}
|
||||
this.element = null;
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.clear();
|
||||
if (!this.extension) {
|
||||
return;
|
||||
}
|
||||
const updateRecommendationMarker = () => {
|
||||
this.clear();
|
||||
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
|
||||
if (extRecommendations[this.extension.identifier.id.toLowerCase()]) {
|
||||
this.element = append(this.parent, $('div.bookmark'));
|
||||
const recommendation = append(this.element, $('.recommendation'));
|
||||
append(recommendation, $('span.octicon.octicon-star'));
|
||||
const applyBookmarkStyle = (theme) => {
|
||||
const bgColor = theme.getColor(extensionButtonProminentBackground);
|
||||
const fgColor = theme.getColor(extensionButtonProminentForeground);
|
||||
recommendation.style.borderTopColor = bgColor ? bgColor.toString() : 'transparent';
|
||||
recommendation.style.color = fgColor ? fgColor.toString() : 'white';
|
||||
};
|
||||
applyBookmarkStyle(this.themeService.getTheme());
|
||||
this.themeService.onThemeChange(applyBookmarkStyle, this, this.disposables);
|
||||
this.parent.title = extRecommendations[this.extension.identifier.id.toLowerCase()].reasonText;
|
||||
this.parent.setAttribute('aria-label', localize('viewRecommendedExtensionDetailsAria', "{0}. {1} Press enter for extension details.", this.extension.displayName, extRecommendations[this.extension.identifier.id.toLowerCase()].reasonText));
|
||||
}
|
||||
};
|
||||
updateRecommendationMarker();
|
||||
this.extensionTipsService.onRecommendationChange(() => updateRecommendationMarker(), this, this.disposables);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
|
||||
private element: HTMLElement | null;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
private parent: HTMLElement,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
) {
|
||||
super();
|
||||
this.render();
|
||||
this._register(toDisposable(() => this.clear()));
|
||||
}
|
||||
|
||||
private clear(): void {
|
||||
if (this.element) {
|
||||
this.parent.removeChild(this.element);
|
||||
}
|
||||
this.element = null;
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.clear();
|
||||
if (!this.extension || !this.extension.local) {
|
||||
return;
|
||||
}
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(this.extension.local.location);
|
||||
if (server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.element = append(this.parent, $('div.extension-remote-badge'));
|
||||
append(this.element, $('span.octicon.octicon-file-symlink-directory'));
|
||||
|
||||
const applyBadgeStyle = (theme) => {
|
||||
const bgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_BACKGROUND);
|
||||
this.element.style.backgroundColor = bgColor ? bgColor.toString() : '';
|
||||
};
|
||||
applyBadgeStyle(this.themeService.getTheme());
|
||||
this.themeService.onThemeChange(applyBadgeStyle, this, this.disposables);
|
||||
|
||||
const updateTitle = () => this.element.title = this.labelService.getHostLabel();
|
||||
this.labelService.onDidChangeFormatters(() => updateTitle(), this, this.disposables);
|
||||
updateTitle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
@ -57,19 +57,18 @@
|
|||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .bookmark {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row.recommended > .bookmark {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .bookmark > .recommendation {
|
||||
border-right: 20px solid transparent;
|
||||
border-top: 20px solid;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .bookmark > .octicon {
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .bookmark > .recommendation > .octicon {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
|
@ -91,7 +90,11 @@
|
|||
background: url('loading.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .extension > .icon {
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .extension > .icon-container > .icon {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
padding: 10px 14px 10px 0;
|
||||
|
@ -99,6 +102,12 @@
|
|||
object-fit: contain;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container > .extension-remote-badge {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
.extensions-viewlet.narrow > .extensions .extension > .icon {
|
||||
display: none;
|
||||
}
|
||||
|
@ -204,8 +213,8 @@
|
|||
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .icon,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .icon,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .icon-container > .icon,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .icon-container > .icon,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .details > .header-container,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .details > .header-container,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .details > .description,
|
||||
|
|
|
@ -46,4 +46,12 @@
|
|||
|
||||
.extension-ratings.small > .count {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.extension-remote-badge {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
border-radius: 20px;
|
||||
text-align: center;
|
||||
}
|
|
@ -30,14 +30,11 @@ import product from 'vs/platform/node/product';
|
|||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { groupBy } from 'vs/base/common/collections';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension, isUIExtension } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
interface IExtensionStateProvider<T> {
|
||||
(extension: Extension): T;
|
||||
|
@ -45,13 +42,12 @@ interface IExtensionStateProvider<T> {
|
|||
|
||||
class Extension implements IExtension {
|
||||
|
||||
public get local(): ILocalExtension { return this.locals[0]; }
|
||||
public enablementState: EnablementState = EnablementState.Enabled;
|
||||
|
||||
constructor(
|
||||
private galleryService: IExtensionGalleryService,
|
||||
private stateProvider: IExtensionStateProvider<ExtensionState>,
|
||||
public locals: ILocalExtension[],
|
||||
public local: ILocalExtension | undefined,
|
||||
public gallery: IGalleryExtension | undefined,
|
||||
private telemetryService: ITelemetryService,
|
||||
private logService: ILogService,
|
||||
|
@ -383,7 +379,6 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
@IWindowService private readonly windowService: IWindowService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IProgressService2 private readonly progressService: IProgressService2,
|
||||
@IExtensionService private readonly runtimeExtensionService: IExtensionService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
|
@ -430,23 +425,20 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
|
||||
queryLocal(): Promise<IExtension[]> {
|
||||
return this.extensionService.getInstalled()
|
||||
.then(installed => this.getDistinctInstalledExtensions(installed)
|
||||
.then(distinctInstalled => {
|
||||
const installedById = index(this.installed, e => e.identifier.id);
|
||||
const groupById = groupBy(installed, i => i.identifier.id);
|
||||
this.installed = distinctInstalled.map(local => {
|
||||
const locals = groupById[local.identifier.id];
|
||||
locals.splice(locals.indexOf(local), 1);
|
||||
locals.splice(0, 0, local);
|
||||
const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, locals, undefined, this.telemetryService, this.logService, this.fileService);
|
||||
extension.locals = locals;
|
||||
extension.enablementState = this.extensionEnablementService.getEnablementState(local);
|
||||
return extension;
|
||||
});
|
||||
.then(installed => {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
installed = installed.filter(installed => this.belongsToWindow(installed));
|
||||
}
|
||||
const installedById = index(this.installed, e => e.identifier.id);
|
||||
this.installed = installed.map(local => {
|
||||
const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, local, undefined, this.telemetryService, this.logService, this.fileService);
|
||||
extension.enablementState = this.extensionEnablementService.getEnablementState(local);
|
||||
return extension;
|
||||
});
|
||||
|
||||
this._onChange.fire(undefined);
|
||||
return this.local;
|
||||
}));
|
||||
this._onChange.fire(undefined);
|
||||
return this.local;
|
||||
});
|
||||
}
|
||||
|
||||
queryGallery(options: IQueryOptions = {}): Promise<IPager<IExtension>> {
|
||||
|
@ -491,52 +483,19 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
return Promise.resolve(this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), undefined, sideByside ? SIDE_GROUP : ACTIVE_GROUP));
|
||||
}
|
||||
|
||||
private getDistinctInstalledExtensions(allInstalled: ILocalExtension[]): Promise<ILocalExtension[]> {
|
||||
if (!this.hasDuplicates(allInstalled)) {
|
||||
return Promise.resolve(allInstalled);
|
||||
private belongsToWindow(extension: ILocalExtension): boolean {
|
||||
if (!this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
return true;
|
||||
}
|
||||
return Promise.all([this.runtimeExtensionService.getExtensions(), this.extensionEnablementService.getDisabledExtensions()])
|
||||
.then(([runtimeExtensions, disabledExtensionIdentifiers]) => {
|
||||
const groups = groupBy(allInstalled, (extension: ILocalExtension) => {
|
||||
const isDisabled = disabledExtensionIdentifiers.some(identifier => areSameExtensions(identifier, extension.identifier));
|
||||
if (isDisabled) {
|
||||
return extension.location.scheme === Schemas.file ? 'disabled:primary' : 'disabled:secondary';
|
||||
} else {
|
||||
return 'enabled';
|
||||
}
|
||||
});
|
||||
const enabled: ILocalExtension[] = [];
|
||||
const notRunningExtensions: ILocalExtension[] = [];
|
||||
const seenExtensions: { [id: string]: boolean } = Object.create({});
|
||||
for (const extension of (groups['enabled'] || [])) {
|
||||
if (runtimeExtensions.some(r => r.extensionLocation.toString() === extension.location.toString())) {
|
||||
enabled.push(extension);
|
||||
seenExtensions[extension.identifier.id] = true;
|
||||
} else {
|
||||
notRunningExtensions.push(extension);
|
||||
}
|
||||
}
|
||||
for (const extension of notRunningExtensions) {
|
||||
if (!seenExtensions[extension.identifier.id]) {
|
||||
enabled.push(extension);
|
||||
seenExtensions[extension.identifier.id] = true;
|
||||
}
|
||||
}
|
||||
const primaryDisabled = groups['disabled:primary'] || [];
|
||||
const secondaryDisabled = (groups['disabled:secondary'] || []).filter(disabled => {
|
||||
return primaryDisabled.every(p => !areSameExtensions(p.identifier, disabled.identifier));
|
||||
});
|
||||
return [...enabled, ...primaryDisabled, ...secondaryDisabled];
|
||||
});
|
||||
}
|
||||
|
||||
private hasDuplicates(extensions: ILocalExtension[]): boolean {
|
||||
const seen: { [key: string]: boolean; } = Object.create(null);
|
||||
for (const i of extensions) {
|
||||
if (seen[i.identifier.id]) {
|
||||
const extensionManagementServer = this.extensionManagementServerService.getExtensionManagementServer(extension.location);
|
||||
if (isUIExtension(extension.manifest, this.configurationService)) {
|
||||
if (this.extensionManagementServerService.localExtensionManagementServer === extensionManagementServer) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer === extensionManagementServer) {
|
||||
return true;
|
||||
}
|
||||
seen[i.identifier.id] = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -554,7 +513,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
this.syncLocalWithGalleryExtension(result, gallery);
|
||||
}
|
||||
} else {
|
||||
result = new Extension(this.galleryService, this.stateProvider, [], gallery, this.telemetryService, this.logService, this.fileService);
|
||||
result = new Extension(this.galleryService, this.stateProvider, undefined, gallery, this.telemetryService, this.logService, this.fileService);
|
||||
}
|
||||
|
||||
if (maliciousExtensionSet.has(result.identifier.id)) {
|
||||
|
@ -581,13 +540,15 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
|
||||
private syncLocalWithGalleryExtension(extension: Extension, gallery: IGalleryExtension) {
|
||||
// Sync the local extension with gallery extension if local extension doesnot has metadata
|
||||
Promise.all(extension.locals.map(local => local.metadata ? Promise.resolve(local) : this.extensionService.updateMetadata(local, { id: gallery.identifier.uuid, publisherDisplayName: gallery.publisherDisplayName, publisherId: gallery.publisherId })))
|
||||
.then(locals => {
|
||||
extension.locals = locals;
|
||||
extension.gallery = gallery;
|
||||
this._onChange.fire(extension);
|
||||
this.eventuallyAutoUpdateExtensions();
|
||||
});
|
||||
if (extension.local) {
|
||||
(extension.local.metadata ? Promise.resolve(extension.local) : this.extensionService.updateMetadata(extension.local, { id: gallery.identifier.uuid, publisherDisplayName: gallery.publisherDisplayName, publisherId: gallery.publisherId }))
|
||||
.then(local => {
|
||||
extension.local = local;
|
||||
extension.gallery = gallery;
|
||||
this._onChange.fire(extension);
|
||||
this.eventuallyAutoUpdateExtensions();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
checkForUpdates(): Promise<void> {
|
||||
|
@ -699,9 +660,9 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
}
|
||||
|
||||
const ext = extension as Extension;
|
||||
const toUninstall: ILocalExtension[] = ext.locals.length ? ext.locals : this.installed.filter(e => areSameExtensions(e.identifier, extension.identifier))[0].locals;
|
||||
const toUninstall: ILocalExtension = ext.local ? ext.local : this.installed.filter(e => areSameExtensions(e.identifier, extension.identifier))[0].local;
|
||||
|
||||
if (!toUninstall || !toUninstall.length) {
|
||||
if (!toUninstall) {
|
||||
return Promise.reject(new Error('Missing local'));
|
||||
}
|
||||
|
||||
|
@ -709,8 +670,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
return this.progressService.withProgress({
|
||||
location: ProgressLocation.Extensions,
|
||||
title: nls.localize('uninstallingExtension', 'Uninstalling extension....'),
|
||||
source: `${toUninstall[0].identifier.id}`
|
||||
}, () => Promise.all(toUninstall.map(local => this.extensionService.uninstall(local))).then(() => undefined));
|
||||
source: `${toUninstall.identifier.id}`
|
||||
}, () => this.extensionService.uninstall(toUninstall).then(() => undefined));
|
||||
}
|
||||
|
||||
installVersion(extension: IExtension, version: string): Promise<void> {
|
||||
|
@ -744,16 +705,16 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
}
|
||||
|
||||
const ext = extension as Extension;
|
||||
const toReinstall: ILocalExtension[] = ext.locals.length ? ext.locals : this.installed.filter(e => areSameExtensions(e.identifier, extension.identifier))[0].locals;
|
||||
const toReinstall: ILocalExtension = ext.local ? ext.local : this.installed.filter(e => areSameExtensions(e.identifier, extension.identifier))[0].local;
|
||||
|
||||
if (!toReinstall || !toReinstall.length) {
|
||||
if (!toReinstall) {
|
||||
return Promise.reject(new Error('Missing local'));
|
||||
}
|
||||
|
||||
return this.progressService.withProgress({
|
||||
location: ProgressLocation.Extensions,
|
||||
source: `${toReinstall[0].identifier.id}`
|
||||
}, () => Promise.all(toReinstall.map(local => this.extensionService.reinstallFromGallery(local))).then(() => undefined));
|
||||
source: `${toReinstall.identifier.id}`
|
||||
}, () => this.extensionService.reinstallFromGallery(toReinstall).then(() => undefined));
|
||||
}
|
||||
|
||||
private installWithProgress(installTask: () => Promise<void>, extensionName?: string): Promise<void> {
|
||||
|
@ -913,7 +874,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
let extension = this.installed.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0];
|
||||
|
||||
if (!extension) {
|
||||
extension = new Extension(this.galleryService, this.stateProvider, [], gallery, this.telemetryService, this.logService, this.fileService);
|
||||
extension = new Extension(this.galleryService, this.stateProvider, undefined, gallery, this.telemetryService, this.logService, this.fileService);
|
||||
}
|
||||
|
||||
this.installing.push(extension);
|
||||
|
@ -924,29 +885,22 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
|||
private onDidInstallExtension(event: DidInstallExtensionEvent): void {
|
||||
const { local, zipPath, error, gallery } = event;
|
||||
const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] : null;
|
||||
let extension: Extension | undefined = installingExtension ? installingExtension : zipPath ? new Extension(this.galleryService, this.stateProvider, local ? [local] : [], undefined, this.telemetryService, this.logService, this.fileService) : undefined;
|
||||
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
|
||||
|
||||
if (local && !this.belongsToWindow(local)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let extension: Extension | undefined = installingExtension ? installingExtension : zipPath ? new Extension(this.galleryService, this.stateProvider, local, undefined, this.telemetryService, this.logService, this.fileService) : undefined;
|
||||
if (extension) {
|
||||
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
|
||||
if (local) {
|
||||
const installed = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier))[0];
|
||||
if (installed) {
|
||||
extension = installed;
|
||||
const newServer = this.extensionManagementServerService.getExtensionManagementServer(local.location);
|
||||
const existingLocal = newServer && installed.locals.filter(l => {
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(l.location);
|
||||
return server && server.authority === newServer.authority;
|
||||
})[0];
|
||||
if (existingLocal) {
|
||||
const locals = [...installed.locals];
|
||||
locals.splice(installed.locals.indexOf(existingLocal), 1, local);
|
||||
installed.locals = locals;
|
||||
} else {
|
||||
installed.locals = [...installed.locals, local];
|
||||
}
|
||||
} else {
|
||||
extension.locals = [local];
|
||||
this.installed.push(extension);
|
||||
}
|
||||
extension.local = local;
|
||||
}
|
||||
}
|
||||
this._onChange.fire(error ? undefined : extension);
|
||||
|
|
|
@ -12,7 +12,7 @@ import { IExtensionsWorkbenchService, ExtensionState, AutoCheckUpdatesConfigurat
|
|||
import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, EnablementState, InstallOperation
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService, IExtensionManagementServer
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
|
@ -37,6 +37,9 @@ import { URLService } from 'vs/platform/url/common/urlService';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService';
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||
|
||||
suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
|
||||
|
@ -73,6 +76,9 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
|||
}
|
||||
});
|
||||
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService, <IExtensionManagementServer>{ authority: 'vscode-local', extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local' }));
|
||||
|
||||
instantiationService.stub(IExtensionManagementService, ExtensionManagementService);
|
||||
instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidInstallExtension', didInstallEvent.event);
|
||||
|
|
Loading…
Reference in a new issue