Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd (#5074)

* Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd

* fix tests
This commit is contained in:
Anthony Dresser
2019-04-16 22:11:30 -07:00
committed by GitHub
parent 2f8519cb6b
commit 8956b591f7
217 changed files with 5120 additions and 3926 deletions

View File

@@ -46,6 +46,7 @@ import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/wo
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { extname } from 'vs/base/common/resources';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
const milliSecondsInADay = 1000 * 60 * 60 * 24;
const choiceNever = localize('neverShowAgain', "Don't Show Again");
@@ -111,6 +112,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
@IExperimentService private readonly experimentService: IExperimentService,
@ITextFileService private readonly textFileService: ITextFileService
) {
super();
@@ -339,8 +341,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
return Promise.resolve(null);
}
return Promise.resolve(this.fileService.resolveContent(workspace.configuration)
.then(content => <IExtensionsConfigContent>(json.parse(content.value)['extensions']), err => null));
return Promise.resolve(this.fileService.readFile(workspace.configuration)
.then(content => <IExtensionsConfigContent>(json.parse(content.value.toString())['extensions']), err => null));
}
/**
@@ -350,8 +352,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
const extensionsJsonUri = workspaceFolder.toResource(EXTENSIONS_CONFIG);
return Promise.resolve(this.fileService.resolve(extensionsJsonUri)
.then(() => this.fileService.resolveContent(extensionsJsonUri))
.then(content => <IExtensionsConfigContent>json.parse(content.value), err => null));
.then(() => this.fileService.readFile(extensionsJsonUri))
.then(content => <IExtensionsConfigContent>json.parse(content.value.toString()), err => null));
}
/**
@@ -968,7 +970,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
const storageKey = 'extensionsAssistant/dynamicWorkspaceRecommendations';
const workspaceUri = this.contextService.getWorkspace().folders[0].uri;
return Promise.all([getHashedRemotesFromUri(workspaceUri, this.fileService, false), getHashedRemotesFromUri(workspaceUri, this.fileService, true)]).then(([hashedRemotes1, hashedRemotes2]) => {
return Promise.all([getHashedRemotesFromUri(workspaceUri, this.fileService, this.textFileService, false), getHashedRemotesFromUri(workspaceUri, this.fileService, this.textFileService, true)]).then(([hashedRemotes1, hashedRemotes2]) => {
const hashedRemotes = (hashedRemotes1 || []).concat(hashedRemotes2 || []);
if (!hashedRemotes.length) {
return undefined;

View File

@@ -252,6 +252,30 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
scope: ConfigurationScope.APPLICATION,
default: ExtensionsPolicy.allowAll
},
'extensions.extensionKind': {
type: 'object',
description: localize('extensions.extensionKind', "Configure ui or workspace extensions and allow them to run locally or remotely in a remote window."),
properties: {
'ui': {
type: 'array',
items: {
type: 'string',
pattern: '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$',
}
},
'workspace': {
type: 'array',
items: {
type: 'string',
pattern: '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$',
}
}
},
default: {
ui: [],
workspace: []
}
},
'extensions.showInstalledExtensionsByDefault': {
type: 'boolean',
description: localize('extensions.showInstalledExtensionsByDefault', "When enabled, extensions view shows installed extensions view by default."),

View File

@@ -23,7 +23,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
import { ShowViewletAction } from 'vs/workbench/browser/viewlet';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
import { IFileService, IContent } from 'vs/platform/files/common/files';
import { IFileService, IFileContent } from 'vs/platform/files/common/files';
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -168,8 +168,7 @@ export class InstallAction extends ExtensionAction {
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ILabelService private readonly labelService: ILabelService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@ILabelService private readonly labelService: ILabelService
) {
super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false);
this.update();
@@ -196,12 +195,12 @@ export class InstallAction extends ExtensionAction {
} else {
if (this._manifest && this.workbenchEnvironmentService.configuration.remoteAuthority) {
if (isUIExtension(this._manifest, this.configurationService)) {
this.label = `${InstallAction.INSTALL_LABEL} (${this.extensionManagementServerService.localExtensionManagementServer.label})`;
this.tooltip = `${InstallAction.INSTALL_LABEL} (${this.extensionManagementServerService.localExtensionManagementServer.label})`;
this.label = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
this.tooltip = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
} else {
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote");
this.label = `${InstallAction.INSTALL_LABEL} (${host})`;
this.tooltip = `${InstallAction.INSTALL_LABEL} (${host})`;
this.label = `${InstallAction.INSTALL_LABEL} on ${host}`;
this.tooltip = `${InstallAction.INSTALL_LABEL} on ${host}`;
}
} else {
this.label = InstallAction.INSTALL_LABEL;
@@ -319,7 +318,7 @@ export class RemoteInstallAction extends ExtensionAction {
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
if (remoteAuthority) {
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority) || localize('remote', "Remote");
this.label = `${RemoteInstallAction.INSTALL_LABEL} (${host})`;
this.label = `${RemoteInstallAction.INSTALL_LABEL} on ${host}`;
return;
}
}
@@ -1233,13 +1232,21 @@ export class ReloadAction extends ExtensionAction {
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
if (runningExtension) {
// Extension is running
const isSameVersionRunning = isSameExtensionRunning && this.extension.version === runningExtension.version;
if (isEnabled) {
if (!isSameVersionRunning && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
this.tooltip = localize('postUpdateTooltip', "Please reload Azure Data Studio to enable the updated extension.");
if (!this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
if (isSameExtensionRunning) {
if (this.extension.version !== runningExtension.version) {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
this.tooltip = localize('postUpdateTooltip', "Please reload Azure Data Studio to enable the updated extension.");
}
} else {
this.enabled = true;
this.label = localize('reloadRequired', "Reload Required");
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
}
}
} else {
if (isSameExtensionRunning) {
@@ -2057,7 +2064,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
protected openWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<any> {
return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
.then(content => this.getSelectionPosition(content.value, content.resource, ['extensions', 'recommendations']))
.then(content => this.getSelectionPosition(content.value.toString(), content.resource, ['extensions', 'recommendations']))
.then(selection => this.editorService.openEditor({
resource: workspaceConfigurationFile,
options: {
@@ -2071,7 +2078,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
.then(content => {
const extensionIdLowerCase = extensionId.toLowerCase();
const workspaceExtensionsConfigContent: IExtensionsConfigContent = (json.parse(content.value) || {})['extensions'] || {};
const workspaceExtensionsConfigContent: IExtensionsConfigContent = (json.parse(content.value.toString()) || {})['extensions'] || {};
let insertInto = shouldRecommend ? workspaceExtensionsConfigContent.recommendations || [] : workspaceExtensionsConfigContent.unwantedRecommendations || [];
let removeFrom = shouldRecommend ? workspaceExtensionsConfigContent.unwantedRecommendations || [] : workspaceExtensionsConfigContent.recommendations || [];
@@ -2131,26 +2138,26 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
}
protected getWorkspaceExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
return Promise.resolve(this.fileService.resolveContent(extensionsFileResource))
return Promise.resolve(this.fileService.readFile(extensionsFileResource))
.then(content => {
return (json.parse(content.value) || {})['extensions'] || {};
return (json.parse(content.value.toString()) || {})['extensions'] || {};
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
}
protected getWorkspaceFolderExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
return Promise.resolve(this.fileService.resolveContent(extensionsFileResource))
return Promise.resolve(this.fileService.readFile(extensionsFileResource))
.then(content => {
return (<IExtensionsConfigContent>json.parse(content.value));
return (<IExtensionsConfigContent>json.parse(content.value.toString()));
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
}
private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<IContent> {
return Promise.resolve(this.fileService.resolveContent(workspaceConfigurationFile))
private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<IFileContent> {
return Promise.resolve(this.fileService.readFile(workspaceConfigurationFile))
.then(content => {
const workspaceRecommendations = <IExtensionsConfigContent>json.parse(content.value)['extensions'];
const workspaceRecommendations = <IExtensionsConfigContent>json.parse(content.value.toString())['extensions'];
if (!workspaceRecommendations || !workspaceRecommendations.recommendations) {
return this.jsonEditingService.write(workspaceConfigurationFile, { key: 'extensions', value: { recommendations: [] } }, true)
.then(() => this.fileService.resolveContent(workspaceConfigurationFile));
.then(() => this.fileService.readFile(workspaceConfigurationFile));
}
return content;
});
@@ -2179,8 +2186,8 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
}
private getOrCreateExtensionsFile(extensionsFileResource: URI): Promise<{ created: boolean, extensionsFileResource: URI, content: string }> {
return Promise.resolve(this.fileService.resolveContent(extensionsFileResource)).then(content => {
return { created: false, extensionsFileResource, content: content.value };
return Promise.resolve(this.fileService.readFile(extensionsFileResource)).then(content => {
return { created: false, extensionsFileResource, content: content.value.toString() };
}, err => {
return this.textFileService.write(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
return { created: true, extensionsFileResource, content: ExtensionsConfigurationInitialContent };
@@ -2562,29 +2569,42 @@ export class DisabledLabelAction extends ExtensionAction {
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
private _runningExtensions: IExtensionDescription[] | null = null;
constructor(
private readonly warningAction: SystemDisabledWarningAction,
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
@IExtensionService private readonly extensionService: IExtensionService,
) {
super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false);
warningAction.onDidChange(() => this.update(), this, this.disposables);
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
this.updateRunningExtensions();
}
private updateRunningExtensions(): void {
this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
}
update(): void {
this.class = `${DisabledLabelAction.Class} hide`;
this.label = '';
this.enabled = false;
if (this.warningAction.enabled) {
this.enabled = true;
this.class = DisabledLabelAction.Class;
this.label = this.warningAction.tooltip;
return;
}
if (this.extension && this.extension.local && !this.extensionEnablementService.isEnabled(this.extension.local)) {
this.enabled = true;
this.class = DisabledLabelAction.Class;
this.label = localize('disabled by user', "This extension is disabled by the user.");
return;
if (this.extension && this.extension.local && this._runningExtensions) {
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
const isExtensionRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier));
if (!isExtensionRunning && !isEnabled) {
this.enabled = true;
this.class = DisabledLabelAction.Class;
this.label = localize('disabled by user', "This extension is disabled by the user.");
return;
}
}
}
@@ -2630,31 +2650,37 @@ export class SystemDisabledWarningAction extends ExtensionAction {
this.class = `${SystemDisabledWarningAction.Class} hide`;
this.tooltip = '';
if (this.extension && this.extension.local && this.extension.server && this._runningExtensions && this.workbenchEnvironmentService.configuration.remoteAuthority && this.extensionManagementServerService.remoteExtensionManagementServer) {
if (
// Local Workspace Extension
this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('disabled workspace Extension', "This extension from {0} server is disabled because it cannot run in a window connected to the remote server.", this.getServerLabel(this.extensionManagementServerService.localExtensionManagementServer));
if (!this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
&& this.extensionsWorkbenchService.canInstall(this.extension)
) {
// Extension does not exist in remote
this.tooltip = `${this.tooltip} ${localize('Install in remote server', "Install it in {0} server to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer))}`;
}
return;
}
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
if (
// Not same as running extension
runningExtensionServer && this.extension.server !== runningExtensionServer
) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('disabled because running in another server', "This extension from {0} server is disabled because another instance of same extension from {1} server is enabled.", this.getServerLabel(this.extension.server), this.getServerLabel(runningExtensionServer));
return;
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
const localExtensionServer = localExtension ? localExtension.server : null;
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
return;
}
if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) {
this.enabled = true;
this.class = `${SystemDisabledWarningAction.Class}`;
this.tooltip = localize('Install in local server', "Install the extension locally to enable.");
return;
}
}
}
}
@@ -2878,7 +2904,7 @@ export class InstallVSIXAction extends Action {
this.extensionsWorkbenchService.install(vsix).then(extension => {
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id)
: localize('InstallVSIXAction.success', "Installing the extension {0} is completed.", extension.identifier.id);
: localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id);
const actions = requireReload ? [{
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()
@@ -2911,7 +2937,7 @@ export class InstallVSIXAction extends Action {
this.extensionsWorkbenchService.install(vsix).then(extension => {
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id)
: localize('InstallVSIXAction.success', "Installing the extension {0} is completed.", extension.identifier.id);
: localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id);
const actions = requireReload ? [{
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()

View File

@@ -66,7 +66,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const element = append(root, $('.extension'));
const iconContainer = append(element, $('.icon-container'));
const icon = append(iconContainer, $<HTMLImageElement>('img.icon'));
const badgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer);
const iconRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer);
const details = append(element, $('.details'));
const headerContainer = append(details, $('.header-container'));
const header = append(headerContainer, $('.header'));
@@ -74,6 +74,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const version = append(header, $('span.version'));
const installCount = append(header, $('span.install-count'));
const ratings = append(header, $('span.ratings'));
const headerRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, header);
const description = append(details, $('.description.ellipsis'));
const footer = append(details, $('.footer'));
const author = append(footer, $('.author.ellipsis'));
@@ -89,10 +90,11 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
const systemDisabledWarningAction = this.instantiationService.createInstance(SystemDisabledWarningAction);
const reloadAction = this.instantiationService.createInstance(ReloadAction);
const actions = [
this.instantiationService.createInstance(StatusLabelAction),
this.instantiationService.createInstance(UpdateAction),
this.instantiationService.createInstance(ReloadAction),
reloadAction,
this.instantiationService.createInstance(InstallAction),
this.instantiationService.createInstance(RemoteInstallAction),
this.instantiationService.createInstance(MaliciousStatusLabelAction, false),
@@ -100,10 +102,11 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
this.instantiationService.createInstance(ManageExtensionAction)
];
const disabledLabelAction = this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction);
const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, disabledLabelAction, recommendationWidget);
const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, disabledLabelAction, recommendationWidget, reloadAction);
const widgets = [
recommendationWidget,
badgeWidget,
iconRemoteBadgeWidget,
headerRemoteBadgeWidget,
tooltipWidget,
this.instantiationService.createInstance(Label, version, (e: IExtension) => e.version),
this.instantiationService.createInstance(InstallCountWidget, installCount, true),

View File

@@ -11,13 +11,14 @@ 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, DisabledLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { Emitter, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
private _extension: IExtension;
@@ -148,11 +149,15 @@ export class TooltipWidget extends ExtensionWidget {
constructor(
private readonly parent: HTMLElement,
private readonly extensionLabelAction: DisabledLabelAction,
private readonly recommendationWidget: RecommendationWidget
private readonly recommendationWidget: RecommendationWidget,
private readonly reloadAction: ReloadAction
) {
super();
this._register(this.extensionLabelAction.onDidChange(() => this.render()));
this._register(this.recommendationWidget.onDidChangeTooltip(() => this.render()));
this._register(Event.any<any>(
this.extensionLabelAction.onDidChange,
this.reloadAction.onDidChange,
this.recommendationWidget.onDidChangeTooltip
)(() => this.render()));
}
render(): void {
@@ -166,6 +171,9 @@ export class TooltipWidget extends ExtensionWidget {
}
private getTitle(): string {
if (this.reloadAction.enabled) {
return this.reloadAction.tooltip;
}
if (this.extensionLabelAction.enabled) {
return this.extensionLabelAction.label;
}
@@ -235,30 +243,30 @@ export class RecommendationWidget extends ExtensionWidget {
}
export class RemoteBadgeWidget extends ExtensionWidget {
private element: HTMLElement | null;
private remoteBadge: RemoteBadge | null;
private disposables: IDisposable[] = [];
private element: HTMLElement;
constructor(
private parent: HTMLElement,
@ILabelService private readonly labelService: ILabelService,
@IThemeService private readonly themeService: IThemeService,
parent: HTMLElement,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super();
this.element = append(parent, $('.extension-remote-badge-container'));
this.render();
this._register(toDisposable(() => this.clear()));
}
private clear(): void {
if (this.element) {
this.parent.removeChild(this.element);
if (this.remoteBadge) {
this.element.removeChild(this.remoteBadge.element);
this.remoteBadge.dispose();
}
this.element = null;
this.remoteBadge = null;
this.disposables = dispose(this.disposables);
}
@@ -268,30 +276,56 @@ export class RemoteBadgeWidget extends ExtensionWidget {
return;
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
this.element = append(this.parent, $('div.extension-remote-badge'));
append(this.element, $('span.octicon.octicon-remote'));
const applyBadgeStyle = () => {
if (!this.element) {
return;
}
const bgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_BACKGROUND);
const fgColor = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY ? this.themeService.getTheme().getColor(STATUS_BAR_NO_FOLDER_FOREGROUND) : this.themeService.getTheme().getColor(STATUS_BAR_FOREGROUND);
this.element.style.backgroundColor = bgColor ? bgColor.toString() : '';
this.element.style.color = fgColor ? fgColor.toString() : '';
};
applyBadgeStyle();
this.themeService.onThemeChange(applyBadgeStyle, this, this.disposables);
this.workspaceContextService.onDidChangeWorkbenchState(applyBadgeStyle, this, this.disposables);
const updateTitle = () => {
if (this.element) {
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
}
};
this.labelService.onDidChangeFormatters(() => updateTitle(), this, this.disposables);
updateTitle();
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge);
append(this.element, this.remoteBadge.element);
}
}
dispose(): void {
if (this.remoteBadge) {
this.remoteBadge.dispose();
}
super.dispose();
}
}
class RemoteBadge extends Disposable {
readonly element: HTMLElement;
constructor(
@ILabelService private readonly labelService: ILabelService,
@IThemeService private readonly themeService: IThemeService,
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
) {
super();
this.element = $('div.extension-remote-badge');
this.render();
}
private render(): void {
append(this.element, $('span.octicon.octicon-remote'));
const applyBadgeStyle = () => {
if (!this.element) {
return;
}
const bgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_BACKGROUND);
const fgColor = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY ? this.themeService.getTheme().getColor(STATUS_BAR_NO_FOLDER_FOREGROUND) : this.themeService.getTheme().getColor(STATUS_BAR_FOREGROUND);
this.element.style.backgroundColor = bgColor ? bgColor.toString() : '';
this.element.style.color = fgColor ? fgColor.toString() : '';
};
applyBadgeStyle();
this._register(this.themeService.onThemeChange(() => applyBadgeStyle()));
this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => applyBadgeStyle()));
const updateTitle = () => {
if (this.element) {
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
}
};
this._register(this.labelService.onDidChangeFormatters(() => updateTitle()));
updateTitle();
}
}

View File

@@ -35,7 +35,17 @@
.extension-editor > .header > .icon-container .extension-remote-badge {
position: absolute;
right: 0px;
top: 94px;
top: 88px;
width: 38px;
height: 38px;
line-height: 38px;
border-radius: 20px;
text-align: center;
}
.extension-editor > .header > .icon-container .extension-remote-badge .octicon {
font-size: 32px;
vertical-align: middle;
}
.extension-editor > .header > .details {

View File

@@ -102,10 +102,32 @@
object-fit: contain;
}
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container > .extension-remote-badge {
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container .extension-remote-badge {
position: absolute;
right: 5px;
bottom: 5px;
width: 22px;
height: 22px;
line-height: 22px;
border-radius: 20px;
text-align: center;
}
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header > .extension-remote-badge-container {
margin-left: 6px;
}
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge {
width: 14px;
height: 14px;
line-height: 14px;
border-radius: 20px;
text-align: center;
}
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge > .octicon {
font-size: 13px;
vertical-align: middle;
}
.extensions-viewlet.narrow > .extensions .extension > .icon-container,
@@ -146,10 +168,13 @@
opacity: 0.85;
font-size: 80%;
padding-left: 6px;
flex: 1;
min-width: fit-content;
}
.extensions-viewlet:not(.narrow) > .extensions .extension > .details > .header-container > .header > .version {
flex: 1;
}
.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count:not(:empty) {
font-size: 80%;
margin: 0 6px;
@@ -164,6 +189,7 @@
text-align: right;
}
.extensions-viewlet:not(.narrow) > .extensions .extension > .details > .header-container > .header > .extension-remote-badge-container,
.extensions-viewlet.narrow > .extensions .extension > .details > .header-container > .header > .ratings,
.extensions-viewlet.narrow > .extensions .extension > .details > .header-container > .header > .install-count {
display: none;

View File

@@ -46,12 +46,4 @@
.extension-ratings.small > .count {
margin-left: 2px;
}
.extension-remote-badge {
width: 22px;
height: 22px;
line-height: 22px;
border-radius: 20px;
text-align: center;
}

View File

@@ -254,7 +254,7 @@ class Extension implements IExtension {
}
if (this.local && this.local.readmeUrl) {
return this.fileService.resolveContent(this.local.readmeUrl, { encoding: 'utf8' }).then(content => content.value);
return this.fileService.readFile(this.local.readmeUrl).then(content => content.value.toString());
}
if (this.type === ExtensionType.System) {
@@ -297,7 +297,7 @@ ${this.description}
return Promise.reject(new Error('not available'));
}
return this.fileService.resolveContent(changelogUrl, { encoding: 'utf8' }).then(content => content.value);
return this.fileService.readFile(changelogUrl).then(content => content.value.toString());
}
get dependencies(): string[] {

View File

@@ -21,12 +21,11 @@ import { Emitter } from 'vs/base/common/event';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { TestTextResourceConfigurationService, TestContextService, TestLifecycleService, TestEnvironmentService, TestStorageService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices';
import { TestContextService, TestLifecycleService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices';
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { URI } from 'vs/base/common/uri';
import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
import { LegacyFileService } from 'vs/workbench/services/files/node/fileService';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IPager } from 'vs/base/common/paging';
import { assign } from 'vs/base/common/objects';
@@ -47,6 +46,11 @@ import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/ele
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { FileService } from 'vs/workbench/services/files/common/fileService';
import { NullLogService } from 'vs/platform/log/common/log';
import { Schemas } from 'vs/base/common/network';
import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider';
import { IFileService } from 'vs/platform/files/common/files';
const mockExtensionGallery: IGalleryExtension[] = [
aGalleryExtension('MockExtension1', {