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

Activate extension on Issue Reporter opened #197092

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 12 additions & 14 deletions src/vs/code/electron-sandbox/issue/issueReporterModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,37 +123,35 @@ ${this.getInfos()}
private getInfos(): string {
let info = '';

if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) {
if (!this._data.fileOnMarketplace && this._data.includeExtensionData && this._data.extensionData) {
const isBugOrPerformanceIssue = this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue;
const isNotOnMarketPlace = !this._data.fileOnMarketplace;

if (isBugOrPerformanceIssue && isNotOnMarketPlace) {
if (this._data.includeExtensionData && this._data.extensionData) {
info += this.getExtensionData();
}
}

if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) {
if (!this._data.fileOnMarketplace && this._data.includeSystemInfo && this._data.systemInfo) {
if (this._data.includeSystemInfo && this._data.systemInfo) {
info += this.generateSystemInfoMd();
}
}

if (this._data.issueType === IssueType.PerformanceIssue) {

if (!this._data.fileOnMarketplace && this._data.includeProcessInfo) {
if (this._data.issueType === IssueType.PerformanceIssue && isNotOnMarketPlace) {
if (this._data.includeProcessInfo) {
info += this.generateProcessInfoMd();
}

if (!this._data.fileOnMarketplace && this._data.includeWorkspaceInfo) {
if (this._data.includeWorkspaceInfo) {
info += this.generateWorkspaceInfoMd();
}
}

if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) {
if (!this._data.fileOnMarketplace && !this._data.fileOnExtension && this._data.includeExtensions) {
if (isBugOrPerformanceIssue && isNotOnMarketPlace) {
if (!this._data.fileOnExtension && this._data.includeExtensions) {
info += this.generateExtensionsMd();
}
}

if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) {
if (!this._data.fileOnMarketplace && this._data.includeExperiments && this._data.experimentInfo) {
if (this._data.includeExperiments && this._data.experimentInfo) {
info += this.generateExperimentsInfoMd();
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/vs/code/electron-sandbox/issue/issueReporterService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ export class IssueReporter extends Disposable {
}
}

private async sendReporterStatus(extension: IssueReporterExtensionData): Promise<boolean[]> {
try {
const data = await this.issueMainService.$sendReporterStatus(extension.id, extension.name);
return data;
} catch (e) {
throw e;
}
}

private setEventHandlers(): void {
this.addEventListener('issue-type', 'change', (event: Event) => {
const issueType = parseInt((<HTMLInputElement>event.target).value);
Expand Down Expand Up @@ -1129,8 +1138,19 @@ export class IssueReporter extends Disposable {
const selectedExtensionId = (<HTMLInputElement>e.target).value;
const extensions = this.issueReporterModel.getData().allExtensions;
const matches = extensions.filter(extension => extension.id === selectedExtensionId);
const foundHandler = matches[0].hasIssueUriRequestHandler;
const foundProvider = matches[0].hasIssueDataProviders;
if (matches.length) {
this.issueReporterModel.update({ selectedExtension: matches[0] });

// if extension is not activated and has a provider/handler w
if (!matches[0].hasIssueDataProviders && !matches[0].hasIssueUriRequestHandler) {
const toActivate = await this.sendReporterStatus(matches[0]);
matches[0].hasIssueDataProviders = toActivate[0];
matches[0].hasIssueUriRequestHandler = toActivate[1];
this.renderBlocks();
}

if (matches[0].hasIssueUriRequestHandler) {
this.updateIssueReporterUri(matches[0]);
} else if (matches[0].hasIssueDataProviders) {
Expand Down Expand Up @@ -1162,6 +1182,8 @@ export class IssueReporter extends Disposable {
this.clearSearchResults();
this.validateSelectedExtension();
}
matches[0].hasIssueDataProviders = foundProvider;
matches[0].hasIssueUriRequestHandler = foundHandler;
this.updatePreviewButtonState();
this.renderBlocks();
});
Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/issue/common/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,6 @@ export interface IIssueMainService {
$getIssueReporterUri(extensionId: string): Promise<URI>;
$getIssueReporterData(extensionId: string): Promise<string>;
$getIssueReporterTemplate(extensionId: string): Promise<string>;
$sendReporterStatus(extensionId: string, extensionName: string): Promise<boolean[]>;
$closeReporter(): Promise<void>;
}
20 changes: 20 additions & 0 deletions src/vs/platform/issue/electron-main/issueMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,26 @@ export class IssueMainService implements IIssueMainService {
});
}

async $sendReporterStatus(extensionId: string, extensionName: string): Promise<boolean[]> {
const window = this.issueReporterWindowCheck();
const replyChannel = `vscode:sendReporterStatus`;
return Promises.withAsyncBody<boolean[]>(async (resolve) => {
const cts = new CancellationTokenSource();
const result = [false, false];
window.sendWhenReady('vscode:sendReporterStatus', cts.token, { replyChannel, extensionId, extensionName });
validatedIpcMain.on('vscode:receiveReporterStatus', (_: unknown, data: boolean[]) => {
resolve(data);
});
try {
await timeout(2000);
cts.cancel();
resolve(result);
} finally {
validatedIpcMain.removeHandler(replyChannel);
}
});
}

async $closeReporter(): Promise<void> {
this.issueReporterWindow?.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,10 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
return result;
}

public activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
return this._activateById(extensionId, reason);
}

public activationEventIsDone(activationEvent: string): boolean {
if (!this._installedExtensionsReady.isOpen()) {
return false;
Expand Down Expand Up @@ -1331,7 +1335,7 @@ export class ExtensionHostCrashTracker {
* This can run correctly only on the renderer process because that is the only place
* where all extension points and all implicit activation events generators are known.
*/
class ImplicitActivationAwareReader implements IActivationEventsReader {
export class ImplicitActivationAwareReader implements IActivationEventsReader {
public readActivationEvents(extensionDescription: IExtensionDescription): string[] {
return ImplicitActivationEvents.readActivationEvents(extensionDescription);
}
Expand Down
7 changes: 7 additions & 0 deletions src/vs/workbench/services/extensions/common/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,12 @@ export interface IExtensionService {
*/
activateByEvent(activationEvent: string, activationKind?: ActivationKind): Promise<void>;

/**
* Send an activation ID and activate interested extensions.
*
*/
activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;

/**
* Determine if `activateByEvent(activationEvent)` has resolved already.
*
Expand Down Expand Up @@ -543,6 +549,7 @@ export class NullExtensionService implements IExtensionService {
onWillStop: Event<WillStopExtensionHostsEvent> = Event.None;
readonly extensions = [];
activateByEvent(_activationEvent: string): Promise<void> { return Promise.resolve(undefined); }
activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> { return Promise.resolve(undefined); }
activationEventIsDone(_activationEvent: string): boolean { return false; }
whenInstalledExtensionsRegistered(): Promise<boolean> { return Promise.resolve(true); }
getExtension() { return Promise.resolve(undefined); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@ export const schema: IJSONSchema = {
body: 'onWalkthrough:${1:walkthroughID}',
description: nls.localize('vscode.extension.activationEvents.onWalkthrough', 'An activation event emitted when a specified walkthrough is opened.'),
},
{
label: 'onIssueReporterOpened',
body: 'onIssueReporterOpened:${1:issueReporterID}',
description: nls.localize('vscode.extension.activationEvents.onIssueReporterOpened', 'An activation event emitted when the issue reporter is opened.'),
},
{
label: '*',
description: nls.localize('vscode.extension.activationEvents.star', 'An activation event emitted on VS Code startup. To ensure a great end user experience, please use this activation event in your extension only when no other activation events combination works in your use-case.'),
Expand Down
24 changes: 22 additions & 2 deletions src/vs/workbench/services/issue/electron-sandbox/issueService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { platform } from 'vs/base/common/process';
import { URI } from 'vs/base/common/uri';
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, ExtensionType } from 'vs/platform/extensions/common/extensions';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles, ProcessExplorerData } from 'vs/platform/issue/common/issue';
import { IProductService } from 'vs/platform/product/common/productService';
Expand All @@ -22,15 +22,17 @@ import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/co
import { IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { ImplicitActivationAwareReader } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity';
import { IIssueDataProvider, IIssueUriRequestHandler, IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
// eslint-disable-next-line local/code-import-patterns

export class NativeIssueService implements IWorkbenchIssueService {
declare readonly _serviceBrand: undefined;

private readonly _handlers = new Map<string, IIssueUriRequestHandler>();
private readonly _providers = new Map<string, IIssueDataProvider>();
private readonly _activationEventReader = new ImplicitActivationAwareReader();

constructor(
@IIssueMainService private readonly issueMainService: IIssueMainService,
Expand All @@ -43,6 +45,7 @@ export class NativeIssueService implements IWorkbenchIssueService {
@IWorkbenchAssignmentService private readonly experimentService: IWorkbenchAssignmentService,
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
@IIntegrityService private readonly integrityService: IIntegrityService,
@IExtensionService private readonly extensionService: IExtensionService,
) {
ipcRenderer.on('vscode:triggerIssueUriRequestHandler', async (event: unknown, request: { replyChannel: string; extensionId: string }) => {
const result = await this.getIssueReporterUri(request.extensionId, CancellationToken.None);
Expand All @@ -56,6 +59,23 @@ export class NativeIssueService implements IWorkbenchIssueService {
const result = await this.getIssueTemplate(request.extensionId, CancellationToken.None);
ipcRenderer.send(request.replyChannel, result);
});
ipcRenderer.on('vscode:sendReporterStatus', async (event, arg) => {
const extensionId = arg.extensionId;
const extension = await this.extensionService.getExtension(extensionId);
if (extension) {
// const extensionDescription = this._registry.getExtensionDescription(extension.identifier);
const activationEvents = this._activationEventReader.readActivationEvents(extension);
for (const activationEvent of activationEvents) {
if (activationEvent === 'onIssueReporterOpened') {
const eventName = `onIssueReporterOpened:${ExtensionIdentifier.toKey(extension.identifier)}`;
await this.extensionService.activateById(extension.identifier, { startup: false, extensionId: extension.identifier, activationEvent: eventName });
break;
}
}
}
const result = [this._providers.has(extensionId.toLowerCase()), this._handlers.has(extensionId.toLowerCase())];
ipcRenderer.send('vscode:receiveReporterStatus', result);
});
}

async openReporter(dataOverrides: Partial<IssueReporterData> = {}): Promise<void> {
Expand Down