mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
#136301 - support whenNotInstalled for config based and exe recommendations
This commit is contained in:
parent
a64e8e5673
commit
a0a9e5dbd3
|
@ -165,14 +165,14 @@ export interface IConfigBasedExtensionTip {
|
|||
configPath: string;
|
||||
configName: string;
|
||||
configScheme?: string;
|
||||
recommendations: IStringDictionary<{ name: string; remotes?: string[]; important?: boolean; isExtensionPack?: boolean }>;
|
||||
recommendations: IStringDictionary<{ name: string; remotes?: string[]; important?: boolean; isExtensionPack?: boolean; whenNotInstalled?: string[] }>;
|
||||
}
|
||||
|
||||
export interface IExeBasedExtensionTip {
|
||||
friendlyName: string;
|
||||
windowsPath?: string;
|
||||
important?: boolean;
|
||||
recommendations: IStringDictionary<{ name: string; important?: boolean; isExtensionPack?: boolean }>;
|
||||
recommendations: IStringDictionary<{ name: string; important?: boolean; isExtensionPack?: boolean; whenNotInstalled?: string[] }>;
|
||||
}
|
||||
|
||||
export interface IRemoteExtensionTip {
|
||||
|
|
|
@ -465,6 +465,7 @@ export type IConfigBasedExtensionTip = {
|
|||
readonly isExtensionPack: boolean;
|
||||
readonly configName: string;
|
||||
readonly important: boolean;
|
||||
readonly whenNotInstalled?: string[];
|
||||
};
|
||||
|
||||
export type IExecutableBasedExtensionTip = {
|
||||
|
@ -474,6 +475,7 @@ export type IExecutableBasedExtensionTip = {
|
|||
readonly exeName: string;
|
||||
readonly exeFriendlyName: string;
|
||||
readonly windowsPath?: string;
|
||||
readonly whenNotInstalled?: string[];
|
||||
};
|
||||
|
||||
export type IWorkspaceTips = { readonly remoteSet: string[]; readonly recommendations: string[] };
|
||||
|
|
|
@ -68,7 +68,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||
extensionName: value.name,
|
||||
configName: tip.configName,
|
||||
important: !!value.important,
|
||||
isExtensionPack: !!value.isExtensionPack
|
||||
isExtensionPack: !!value.isExtensionPack,
|
||||
whenNotInstalled: value.whenNotInstalled
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
@ -77,7 +78,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||
extensionName: value.name,
|
||||
configName: tip.configName,
|
||||
important: !!value.important,
|
||||
isExtensionPack: !!value.isExtensionPack
|
||||
isExtensionPack: !!value.isExtensionPack,
|
||||
whenNotInstalled: value.whenNotInstalled
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -14,8 +14,10 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { localize } from 'vs/nls';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IExecutableBasedExtensionTip, IExtensionManagementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionTipsService as BaseExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionTipsService';
|
||||
import { IExtensionRecommendationNotificationService, RecommendationsNotificationResult, RecommendationSource } from 'vs/platform/extensionRecommendations/common/extensionRecommendations';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
|
@ -32,7 +34,7 @@ type ExeExtensionRecommendationsClassification = {
|
|||
type IExeBasedExtensionTips = {
|
||||
readonly exeFriendlyName: string;
|
||||
readonly windowsPath?: string;
|
||||
readonly recommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean }[];
|
||||
readonly recommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean; whenNotInstalled?: string[] }[];
|
||||
};
|
||||
|
||||
const promptedExecutableTipsStorageKey = 'extensionTips/promptedExecutableTips';
|
||||
|
@ -242,8 +244,11 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
|
|||
});
|
||||
}
|
||||
|
||||
private promptExeRecommendations(tips: IExecutableBasedExtensionTip[]): Promise<RecommendationsNotificationResult> {
|
||||
const extensionIds = tips.map(({ extensionId }) => extensionId.toLowerCase());
|
||||
private async promptExeRecommendations(tips: IExecutableBasedExtensionTip[]): Promise<RecommendationsNotificationResult> {
|
||||
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const extensionIds = tips
|
||||
.filter(tip => !tip.whenNotInstalled || tip.whenNotInstalled.every(id => installed.every(local => !areSameExtensions(local.identifier, { id }))))
|
||||
.map(({ extensionId }) => extensionId.toLowerCase());
|
||||
const message = localize({ key: 'exeRecommended', comment: ['Placeholder string is the name of the software that is installed.'] }, "You have {0} installed on your system. Do you want to install the recommended extensions for it?", tips[0].exeFriendlyName);
|
||||
return this.extensionRecommendationNotificationService.promptImportantExtensionsInstallNotification(extensionIds, message, `@exe:"${tips[0].exeName}"`, RecommendationSource.EXE);
|
||||
}
|
||||
|
@ -316,7 +321,7 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
|
|||
checkedExecutables.set(exePath, exists);
|
||||
}
|
||||
if (exists) {
|
||||
for (const { extensionId, extensionName, isExtensionPack } of extensionTip.recommendations) {
|
||||
for (const { extensionId, extensionName, isExtensionPack, whenNotInstalled } of extensionTip.recommendations) {
|
||||
result.push({
|
||||
extensionId,
|
||||
extensionName,
|
||||
|
@ -324,6 +329,7 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
|
|||
exeName,
|
||||
exeFriendlyName: extensionTip.exeFriendlyName,
|
||||
windowsPath: extensionTip.windowsPath,
|
||||
whenNotInstalled: whenNotInstalled
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionRe
|
|||
import { IWorkspaceContextService, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export type ConfigBasedExtensionRecommendation = ExtensionRecommendation & { whenNotInstalled: string[] | undefined };
|
||||
|
||||
export class ConfigBasedRecommendations extends ExtensionRecommendations {
|
||||
|
||||
private importantTips: IConfigBasedExtensionTip[] = [];
|
||||
|
@ -18,13 +20,13 @@ export class ConfigBasedRecommendations extends ExtensionRecommendations {
|
|||
private _onDidChangeRecommendations = this._register(new Emitter<void>());
|
||||
readonly onDidChangeRecommendations = this._onDidChangeRecommendations.event;
|
||||
|
||||
private _otherRecommendations: ExtensionRecommendation[] = [];
|
||||
get otherRecommendations(): ReadonlyArray<ExtensionRecommendation> { return this._otherRecommendations; }
|
||||
private _otherRecommendations: ConfigBasedExtensionRecommendation[] = [];
|
||||
get otherRecommendations(): ReadonlyArray<ConfigBasedExtensionRecommendation> { return this._otherRecommendations; }
|
||||
|
||||
private _importantRecommendations: ExtensionRecommendation[] = [];
|
||||
get importantRecommendations(): ReadonlyArray<ExtensionRecommendation> { return this._importantRecommendations; }
|
||||
private _importantRecommendations: ConfigBasedExtensionRecommendation[] = [];
|
||||
get importantRecommendations(): ReadonlyArray<ConfigBasedExtensionRecommendation> { return this._importantRecommendations; }
|
||||
|
||||
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return [...this.importantRecommendations, ...this.otherRecommendations]; }
|
||||
get recommendations(): ReadonlyArray<ConfigBasedExtensionRecommendation> { return [...this.importantRecommendations, ...this.otherRecommendations]; }
|
||||
|
||||
constructor(
|
||||
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
|
||||
|
@ -69,13 +71,14 @@ export class ConfigBasedRecommendations extends ExtensionRecommendations {
|
|||
}
|
||||
}
|
||||
|
||||
private toExtensionRecommendation(tip: IConfigBasedExtensionTip): ExtensionRecommendation {
|
||||
private toExtensionRecommendation(tip: IConfigBasedExtensionTip): ConfigBasedExtensionRecommendation {
|
||||
return {
|
||||
extensionId: tip.extensionId,
|
||||
reason: {
|
||||
reasonId: ExtensionRecommendationReason.WorkspaceConfig,
|
||||
reasonText: localize('exeBasedRecommendation', "This extension is recommended because of the current workspace configuration")
|
||||
}
|
||||
},
|
||||
whenNotInstalled: tip.whenNotInstalled
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ import { IExtensionRecommendationNotificationService } from 'vs/platform/extensi
|
|||
import { timeout } from 'vs/base/common/async';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { WebRecommendations } from 'vs/workbench/contrib/extensions/browser/webRecommendations';
|
||||
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
|
||||
type IgnoreRecommendationClassification = {
|
||||
recommendationReason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true };
|
||||
|
@ -61,6 +63,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
|
|||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IExtensionIgnoredRecommendationsService private readonly extensionRecommendationsManagementService: IExtensionIgnoredRecommendationsService,
|
||||
@IExtensionRecommendationNotificationService private readonly extensionRecommendationNotificationService: IExtensionRecommendationNotificationService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -260,7 +263,12 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
|
|||
}
|
||||
|
||||
private async promptWorkspaceRecommendations(): Promise<void> {
|
||||
const allowedRecommendations = [...this.workspaceRecommendations.recommendations, ...this.configBasedRecommendations.importantRecommendations]
|
||||
const installed = await this.extensionsWorkbenchService.queryLocal();
|
||||
const allowedRecommendations = [
|
||||
...this.workspaceRecommendations.recommendations,
|
||||
...this.configBasedRecommendations.importantRecommendations.filter(
|
||||
recommendation => !recommendation.whenNotInstalled || recommendation.whenNotInstalled.every(id => installed.every(local => !areSameExtensions(local.identifier, { id }))))
|
||||
]
|
||||
.map(({ extensionId }) => extensionId)
|
||||
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId));
|
||||
|
||||
|
|
Loading…
Reference in a new issue