"Report Issue" command opens issue reporter, fixes #42269

This commit is contained in:
Rachel Macfarlane 2018-01-29 09:29:23 -08:00
parent b0e3568730
commit ab684da7e7
3 changed files with 8 additions and 112 deletions

View file

@ -391,7 +391,8 @@ export class IssueReporter extends Disposable {
}
const issueTitle = (<HTMLInputElement>document.getElementById('issue-title')).value;
const baseUrl = `https://github.com/microsoft/vscode/issues/new?title=${issueTitle}&body=`;
const queryStringPrefix = product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&';
const baseUrl = `${product.reportIssueUrl}${queryStringPrefix}title=${issueTitle}&body=`;
const issueBody = this.issueReporterModel.serialize();
shell.openExternal(baseUrl + encodeURIComponent(issueBody));
return true;

View file

@ -8,7 +8,6 @@
import 'vs/css!./media/actions';
import URI from 'vs/base/common/uri';
import * as collections from 'vs/base/common/collections';
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
import { IWindowService, IWindowsService, MenuBarVisibility } from 'vs/platform/windows/common/windows';
@ -21,7 +20,7 @@ import { IMessageService, Severity } from 'vs/platform/message/common/message';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IExtensionManagementService, LocalExtensionType, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, LocalExtensionType, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import paths = require('vs/base/common/paths');
import { isMacintosh, isLinux, language } from 'vs/base/common/platform';
@ -46,7 +45,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IExtensionService, ActivationTimes } from 'vs/platform/extensions/common/extensions';
import { getEntries } from 'vs/base/common/performance';
import { IEditor } from 'vs/platform/editor/common/editor';
import { IIssueService } from 'vs/platform/issue/common/issue';
import { IIssueService, IssueReporterData } from 'vs/platform/issue/common/issue';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { textLinkForeground, inputBackground, inputBorder, inputForeground, buttonBackground, buttonHoverBackground, buttonForeground, inputValidationErrorBorder, foreground, inputActiveOptionBorder } from 'vs/platform/theme/common/colorRegistry';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
@ -750,7 +749,7 @@ export class CloseMessagesAction extends Action {
export class OpenIssueReporterAction extends Action {
public static readonly ID = 'workbench.action.openIssueReporter';
public static readonly LABEL = nls.localize('openIssueReporter', "Open Issue Reporter");
public static readonly LABEL = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue");
constructor(
id: string,
@ -782,7 +781,7 @@ export class OpenIssueReporterAction extends Action {
zoomLevel: webFrame.getZoomLevel(),
extensions
};
const issueReporterData = {
const issueReporterData: IssueReporterData = {
styles,
zoomLevel: webFrame.getZoomLevel(),
enabledExtensions
@ -795,109 +794,6 @@ export class OpenIssueReporterAction extends Action {
}
}
export class ReportIssueAction extends Action {
public static readonly ID = 'workbench.action.reportIssues';
public static readonly LABEL = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue");
constructor(
id: string,
label: string,
@IIntegrityService private integrityService: IIntegrityService,
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService,
@IEnvironmentService private environmentService: IEnvironmentService
) {
super(id, label);
}
private _optimisticIsPure(): TPromise<boolean> {
let isPure = true;
let integrityPromise = this.integrityService.isPure().then(res => {
isPure = res.isPure;
});
return TPromise.any([TPromise.timeout(100), integrityPromise]).then(() => {
return isPure;
});
}
public run(): TPromise<boolean> {
return this._optimisticIsPure().then(isPure => {
return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => {
extensions = extensions.filter(extension => this.extensionEnablementService.isEnabled(extension.identifier));
const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, isPure, extensions, this.environmentService.disableExtensions);
window.open(issueUrl);
return TPromise.as(true);
});
});
}
private generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, extensions: ILocalExtension[], areExtensionsDisabled: boolean): string {
// Avoid backticks, these can trigger XSS detectors. (https://github.com/Microsoft/vscode/issues/13098)
const osVersion = `${os.type()} ${os.arch()} ${os.release()}`;
const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&';
const body = encodeURIComponent(
`<ul>
<li>VSCode Version: ${name} ${version}${isPure ? '' : ' **[Unsupported]**'} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})</li>
<li>OS Version: ${osVersion}</li>
<li>${areExtensionsDisabled ? 'Extensions: Extensions are disabled' : this.generateExtensionTable(extensions)}</li>
</ul>
---
Steps to Reproduce:
1.
2.` + (extensions.length ? `
<!-- Launch with \`code --disable-extensions\` to check. -->
Reproduces without extensions: Yes/No` : '')
);
return `${baseUrl}${queryStringPrefix}body=${body}`;
}
private generateExtensionTable(extensions: ILocalExtension[]): string {
const { nonThemes, themes } = collections.groupBy(extensions, ext => {
const manifestKeys = ext.manifest.contributes ? Object.keys(ext.manifest.contributes) : [];
const onlyTheme = !ext.manifest.activationEvents && manifestKeys.length === 1 && manifestKeys[0] === 'themes';
return onlyTheme ? 'themes' : 'nonThemes';
});
const themeExclusionStr = (themes && themes.length) ? `\n(${themes.length} theme extensions excluded)` : '';
extensions = nonThemes || [];
if (!extensions.length) {
return 'Extensions: none' + themeExclusionStr;
}
let tableHeader = `Extension|Author (truncated)|Version
---|---|---`;
const table = extensions.map(e => {
return `${e.manifest.name}|${e.manifest.publisher.substr(0, 3)}|${e.manifest.version}`;
}).join('\n');
const extensionTable = `<details><summary>Extensions (${extensions.length})</summary>
${tableHeader}
${table}
${themeExclusionStr}
</details>`;
// 2000 chars is browsers de-facto limit for URLs, 400 chars are allowed for other string parts of the issue URL
// http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
if (encodeURIComponent(extensionTable).length > 1600) {
return 'the listing length exceeds browsers\' URL characters limit';
}
return extensionTable;
}
}
export class ReportPerformanceIssueAction extends Action {
public static readonly ID = 'workbench.action.reportPerformanceIssue';

View file

@ -14,7 +14,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenIssueReporterAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, ConfigureLocaleAction } from 'vs/workbench/electron-browser/actions';
import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenIssueReporterAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, ConfigureLocaleAction } from 'vs/workbench/electron-browser/actions';
import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { registerCommands } from 'vs/workbench/electron-browser/commands';
@ -46,9 +46,8 @@ if (isMacintosh) {
}
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIssueReporterAction, OpenIssueReporterAction.ID, OpenIssueReporterAction.LABEL), 'Help: Open Issue Reporter', helpCategory);
if (!!product.reportIssueUrl) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportIssueAction, ReportIssueAction.ID, ReportIssueAction.LABEL), 'Help: Report Issues', helpCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIssueReporterAction, OpenIssueReporterAction.ID, OpenIssueReporterAction.LABEL), 'Help: Open Issue Reporter', helpCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueAction, ReportPerformanceIssueAction.ID, ReportPerformanceIssueAction.LABEL), 'Help: Report Performance Issue', helpCategory);
}