mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-30 08:40:29 -04:00
Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd (#5074)
* Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd * fix tests
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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."),
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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[] {
|
||||
|
||||
@@ -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', {
|
||||
|
||||
Reference in New Issue
Block a user