Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to ignore recommendations both globally and at a per-workspace level #51941

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
d30415f
WIP
Jun 12, 2018
76472b7
Initail filtering and pulling filter list logic.
Jun 12, 2018
58e1eed
Imporive typing and naming
Jun 12, 2018
6803fc1
Remove the significant duplication
Jun 12, 2018
e9669f4
Bug fixes.
Jun 12, 2018
42e9a32
Fix bug where arrow functions dont maintain `this` in point free style
Jun 12, 2018
828fe0a
WIP on extension ignoring UI.
Jun 13, 2018
7c6c8fa
UI for global ignores.
Jun 13, 2018
0202014
Add "unwantedRecommendations" to extensions.json template and intelis…
Jun 13, 2018
138f45a
Notify of workspace non-recommended extensions
Jun 13, 2018
eb876ac
Wording of extensions.json template
Jun 13, 2018
a711169
More UI for ignore button.
Jun 13, 2018
f287d7f
Use seprate notification channel of recommendation changes.
Jun 13, 2018
08df8e0
Reload search when recommended extensions changes
Jun 14, 2018
d9748db
Tests for ExtensionTipsService
Jun 14, 2018
019f2ac
Test extensions workbench service
Jun 14, 2018
75fddb9
Merge branch 'master' into feature/un-recomend-extensions
Jun 14, 2018
7033d13
Naming and add default vaule to workspace settings
Jun 14, 2018
a9863f1
Merge branch 'master' into feature/un-recomend-extensions
Jun 14, 2018
328eca4
Initial revisions
Jun 15, 2018
3073051
Merge branch 'master' into feature/un-recomend-extensions
Jun 15, 2018
8d3b34b
Global ignore need not call workspace refresh
ramya-rao-a Jun 15, 2018
e80b831
Fix build issues
ramya-rao-a Jun 15, 2018
07af902
Skip refreshing workspace twice
ramya-rao-a Jun 16, 2018
bf04418
WIP
Jun 18, 2018
6dc8862
Merge branch 'master' into feature/un-recomend-extensions
Jun 18, 2018
976978f
Merge branch 'feature/un-recomend-extensions' of github.com:JacksonKe…
Jun 18, 2018
3fa9b65
WIP
Jun 18, 2018
8052abd
Merge branch 'master' into feature/un-recomend-extensions
Jun 18, 2018
cf92a80
Reduce file accesses.
Jun 18, 2018
f33abfe
Fix some of the build issues.
Jun 18, 2018
d9a018b
Hackish thing that fixes the test.
Jun 18, 2018
cc2fe62
Rename id to extensionId in RecommendationChangeNotification
ramya-rao-a Jun 18, 2018
bf1eea8
updateRecommendedness ??
ramya-rao-a Jun 18, 2018
0ddd992
Not needed
ramya-rao-a Jun 18, 2018
1421677
Remove point free style thing
Jun 18, 2018
f520130
Simplify
Jun 18, 2018
3e6310f
Merge branch 'feature/un-recomend-extensions' of github.com:JacksonKe…
Jun 18, 2018
956c8ab
naming
Jun 18, 2018
68ee832
remove extrenous getWrokspaceRecommendations call
Jun 18, 2018
3e8a0e1
Casing
Jun 19, 2018
374e49d
Gracefull handle missing 'extensions' field in multiroot project config
Jun 19, 2018
01a4913
Refresh recommendation views on recommendation change
ramya-rao-a Jun 19, 2018
312cf84
more case sensitivity stuff
Jun 19, 2018
c217a29
naming/refactroing
Jun 19, 2018
2fc3625
Merge branch 'master' into feature/un-recomend-extensions
Jun 19, 2018
ba26860
Simplify return types
ramya-rao-a Jun 19, 2018
b8438bf
Merge branch 'feature/un-recomend-extensions' of github.com:JacksonKe…
Jun 19, 2018
ab52be6
Wording
Jun 19, 2018
0a60392
Add telemetry
Jun 19, 2018
b77ba77
guard telemetry service
Jun 19, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/vs/platform/extensionManagement/common/extensionManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,21 @@ export interface IExtensionEnablementService {
setEnablement(extension: ILocalExtension, state: EnablementState): TPromise<boolean>;
}

export interface IIgnoredRecommendations {
global: string[];
workspace: string[];
}

export interface IExtensionsConfigContent {
recommendations: string[];
unwantedRecommendations: string[];
}

export type RecommendationChangeNotification = {
extensionId: string,
isRecommended: boolean
};

export const IExtensionTipsService = createDecorator<IExtensionTipsService>('extensionTipsService');

export interface IExtensionTipsService {
Expand All @@ -387,6 +402,9 @@ export interface IExtensionTipsService {
getKeymapRecommendations(): string[];
getKeywordsForExtension(extension: string): string[];
getRecommendationsForExtension(extension: string): string[];
getAllIgnoredRecommendations(): IIgnoredRecommendations;
ignoreExtensionRecommendation(extensionId: string): void;
onRecommendationChange: Event<RecommendationChangeNotification>;
}

export enum ExtensionRecommendationReason {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/node/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface IProductConfiguration {
};
extensionTips: { [id: string]: string; };
extensionImportantTips: { [id: string]: { name: string; pattern: string; }; };
exeBasedExtensionTips: { [id: string]: any; };
exeBasedExtensionTips: { [id: string]: { friendlyName: string, windowsPath?: string, recommendations: string[] }; };
extensionKeywords: { [extension: string]: string[]; };
extensionAllowedBadgeProviders: string[];
extensionAllowedProposedApi: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,20 @@ export const ExtensionsConfigurationSchema: IJSONSchema = {
allowComments: true,
type: 'object',
title: localize('app.extensions.json.title', "Extensions"),
additionalProperties: false,
properties: {
recommendations: {
type: 'array',
description: localize('app.extensions.json.recommendations', "List of extensions recommendations. The identifier of an extension is always '${publisher}.${name}'. For example: 'vscode.csharp'."),
description: localize('app.extensions.json.recommendations', "List of extensions which should be recommended for users of this workspace. The identifier of an extension is always '${publisher}.${name}'. For example: 'vscode.csharp'."),
items: {
type: 'string',
pattern: EXTENSION_IDENTIFIER_PATTERN,
errorMessage: localize('app.extension.identifier.errorMessage', "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'.")
},
},
unwantedRecommendations: {
type: 'array',
description: localize('app.extensions.json.unwantedRecommendations', "List of extensions that will be skipped from the recommendations that VS Code makes for the users of this workspace. These are extensions that you may consider to be irrelevant, redundant, or otherwise unwanted. The identifier of an extension is always '${publisher}.${name}'. For example: 'vscode.csharp'."),
items: {
type: 'string',
pattern: EXTENSION_IDENTIFIER_PATTERN,
Expand All @@ -31,6 +41,12 @@ export const ExtensionsConfigurationInitialContent: string = [
'\t// See http://go.microsoft.com/fwlink/?LinkId=827846',
'\t// for the documentation about the extensions.json format',
'\t"recommendations": [',
'\t\t// List of extensions which should be recommended for users of this workspace.',
'\t\t// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp',
'\t\t',
'\t],',
'\t"unwantedRecommendations": [',
'\t\t// List of extensions that will be skipped from the recommendations that VS Code makes for the users of this workspace. These are extensions that you may consider to be irrelevant, redundant, or otherwise unwanted.',
'\t\t// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp',
'\t\t',
'\t]',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { Renderer, DataSource, Controller } from 'vs/workbench/parts/extensions/
import { RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets';
import { EditorOptions } from 'vs/workbench/common/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { CombinedInstallAction, UpdateAction, EnableAction, DisableAction, ReloadAction, MaliciousStatusLabelAction, DisabledStatusLabelAction, MultiServerInstallAction, MultiServerUpdateAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
import { CombinedInstallAction, UpdateAction, EnableAction, DisableAction, ReloadAction, MaliciousStatusLabelAction, DisabledStatusLabelAction, MultiServerInstallAction, MultiServerUpdateAction, IgnoreExtensionRecommendationAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions';
import { WebviewElement } from 'vs/workbench/parts/webview/electron-browser/webviewElement';
import { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
Expand Down Expand Up @@ -164,6 +164,8 @@ export class ExtensionEditor extends BaseEditor {
private navbar: NavBar;
private content: HTMLElement;
private recommendation: HTMLElement;
private recommendationText: any;
private ignoreActionbar: ActionBar;
private header: HTMLElement;

private extensionReadme: Cache<string>;
Expand Down Expand Up @@ -256,15 +258,24 @@ export class ExtensionEditor extends BaseEditor {
return null;
}
});
this.disposables.push(this.extensionActionBar);

this.recommendation = append(details, $('.recommendation'));
this.recommendationText = append(this.recommendation, $('.recommendation-text'));
this.ignoreActionbar = new ActionBar(this.recommendation, { animated: false });

this.disposables.push(this.extensionActionBar);
this.disposables.push(this.ignoreActionbar);

chain(this.extensionActionBar.onDidRun)
.map(({ error }) => error)
.filter(error => !!error)
.on(this.onError, this, this.disposables);

chain(this.ignoreActionbar.onDidRun)
.map(({ error }) => error)
.filter(error => !!error)
.on(this.onError, this, this.disposables);

const body = append(root, $('.body'));
this.navbar = new NavBar(body);

Expand Down Expand Up @@ -295,24 +306,25 @@ export class ExtensionEditor extends BaseEditor {
this.publisher.textContent = extension.publisherDisplayName;
this.description.textContent = extension.description;

removeClass(this.header, 'recommendation-ignored');
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
let recommendationsData = {};
if (extRecommendations[extension.id.toLowerCase()]) {
addClass(this.header, 'recommended');
this.recommendation.textContent = extRecommendations[extension.id.toLowerCase()].reasonText;
this.recommendationText.textContent = extRecommendations[extension.id.toLowerCase()].reasonText;
recommendationsData = { recommendationReason: extRecommendations[extension.id.toLowerCase()].reasonId };
} else {
removeClass(this.header, 'recommended');
this.recommendation.textContent = '';
this.recommendationText.textContent = '';
}

/* __GDPR__
"extensionGallery:openExtension" : {
"recommendationReason": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"${include}": [
"${GalleryExtensionTelemetryData}"
]
}
"extensionGallery:openExtension" : {
"recommendationReason": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"${include}": [
"${GalleryExtensionTelemetryData}"
]
}
*/
this.telemetryService.publicLog('extensionGallery:openExtension', assign(extension.telemetryData, recommendationsData));

Expand Down Expand Up @@ -376,6 +388,21 @@ export class ExtensionEditor extends BaseEditor {
this.extensionActionBar.push([disabledStatusAction, reloadAction, updateAction, enableAction, disableAction, installAction, maliciousStatusAction], { icon: true, label: true });
this.transientDisposables.push(enableAction, updateAction, reloadAction, disableAction, installAction, maliciousStatusAction, disabledStatusAction);

const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction);
ignoreAction.extension = extension;

this.extensionTipsService.onRecommendationChange(change => {
if (change.extensionId.toLowerCase() === extension.id.toLowerCase() && change.isRecommended === false) {
addClass(this.header, 'recommendation-ignored');
removeClass(this.header, 'recommended');
this.recommendationText.textContent = localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.");
}
});

this.ignoreActionbar.clear();
this.ignoreActionbar.push([ignoreAction], { icon: true, label: true });
this.transientDisposables.push(ignoreAction);

this.content.innerHTML = ''; // Clear content before setting navbar actions.

this.navbar.clear();
Expand Down
Loading