mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-03 06:51:53 +01:00
Move files under vs/code/electron-browser/issue
This commit is contained in:
88
src/vs/code/electron-browser/issue/bootstrap.css
vendored
Normal file
88
src/vs/code/electron-browser/issue/bootstrap.css
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Table
|
||||
*/
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
background-color: transparent;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid #e9ecef;
|
||||
padding: .75rem;
|
||||
border-top: 1px solid #e9ecef;
|
||||
text-align: inherit;
|
||||
}
|
||||
tr:nth-of-type(even) {
|
||||
background-color: rgba(0,0,0,.05);
|
||||
}
|
||||
td {
|
||||
padding: .75rem;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forms
|
||||
*/
|
||||
input, textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: .375rem .75rem;
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
border-radius: .25rem;
|
||||
border: 1px solid #ced4da;
|
||||
}
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
small {
|
||||
color: #868e96;
|
||||
display: block;
|
||||
margin-top: .25rem;
|
||||
font-size: 80%;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* Button
|
||||
*/
|
||||
button {
|
||||
display: inline-block;
|
||||
font-weight: 400;
|
||||
line-height: 1.25;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
padding: .5rem 1rem;
|
||||
font-size: 1rem;
|
||||
border-radius: .25rem;
|
||||
background: none;
|
||||
}
|
||||
|
||||
select {
|
||||
height: calc(2.25rem + 2px);
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
border-radius: 0.25rem;
|
||||
border: none;
|
||||
}
|
||||
136
src/vs/code/electron-browser/issue/issueReporter.css
Normal file
136
src/vs/code/electron-browser/issue/issueReporter.css
Normal file
@@ -0,0 +1,136 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Ubuntu", "Droid Sans", sans-serif;
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #1E1E1E;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#block-container {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.block {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.block summary {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.block .block-info {
|
||||
width: 100%;
|
||||
font-family: 'Menlo', 'Courier New', 'Courier', monospace;
|
||||
font-size: 14px;
|
||||
overflow: auto;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
pre code {
|
||||
font-family: 'Menlo', 'Courier New', 'Courier', monospace;
|
||||
}
|
||||
|
||||
button:hover:enabled {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
#issue-reporter {
|
||||
max-width: 80vw;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#github-submit-btn {
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
}
|
||||
|
||||
.two-col {
|
||||
display: inline-block;
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
#vscode-version {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
select, input, textarea {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.validation-error {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.caption {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
margin-left: 1em;
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
input:disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
margin-top: 1em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
/* Default styles, overwritten if a theme is provided */
|
||||
input, select, textarea {
|
||||
background-color: #3c3c3c;
|
||||
border: none;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.invalid-input {
|
||||
border: 1px solid #be1100;
|
||||
}
|
||||
|
||||
.required-input {
|
||||
color: #be1100;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #007ACC;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
103
src/vs/code/electron-browser/issue/issueReporter.html
Normal file
103
src/vs/code/electron-browser/issue/issueReporter.html
Normal file
@@ -0,0 +1,103 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
<link rel="stylesheet" href="issueReporter.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="issue-reporter">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="issue-type">This is a</label>
|
||||
<select id="issue-type" class="form-control">
|
||||
<option value="0">Bug Report</option>
|
||||
<option value="1">Performance Issue</option>
|
||||
<option value="2">Feature Request</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="issue-title">Title <span class="required-input">*</span></label>
|
||||
<div id="issue-title-validation-error" class="validation-error hidden">Please enter a title.</div>
|
||||
<input id="issue-title" type="text" required>
|
||||
<small id="similar-issues">
|
||||
<!-- To be dynamically filled -->
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="two-col">
|
||||
<label for="vscode-version">VS Code version <span class="required-input">*</span></label>
|
||||
<input id="vscode-version" type="text" value="Loading..." disabled/>
|
||||
</div>
|
||||
<div class="two-col">
|
||||
<label for="os">OS Version <span class="required-input">*</span></label>
|
||||
<input id="os" type="text" value="Loading..." disabled/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="block-container">
|
||||
<div class="block block-system">
|
||||
<details>
|
||||
<summary>My System Info
|
||||
<input type="checkbox" id="includeSystemInfo" checked>
|
||||
<label class="caption" for="includeSystemInfo">Send this data</label>
|
||||
</input>
|
||||
</summary>
|
||||
<div class="block-info">
|
||||
<!-- To be dynamically filled -->
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<div class="block block-process">
|
||||
<details>
|
||||
<summary>Currently Running Processes
|
||||
<input type="checkbox" id="includeProcessInfo" checked>
|
||||
<label class="caption" for="includeProcessInfo">Send this data</label>
|
||||
</input>
|
||||
</summary>
|
||||
<div class="block-info">
|
||||
<!-- To be dynamically filled -->
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<div class="block block-workspace">
|
||||
<details>
|
||||
<summary>My Workspace Stats
|
||||
<input type="checkbox" id="includeWorkspaceInfo" checked>
|
||||
<label class="caption" for="includeWorkspaceInfo">Send this data</label>
|
||||
</input>
|
||||
</summary>
|
||||
<pre class="block-info">
|
||||
<code>
|
||||
<!-- To be dynamically filled -->
|
||||
</code>
|
||||
</pre>
|
||||
</details>
|
||||
</div>
|
||||
<div class="block block-description">
|
||||
<label class="block-title">
|
||||
<!-- To be dynamically filled -->
|
||||
</label>
|
||||
<small class="block-subtitle">
|
||||
<!-- To be dynamically filled -->
|
||||
</small>
|
||||
<div class="block-info-text">
|
||||
<small>
|
||||
We support GitHub-flavored Markdown.
|
||||
After submitting, you will still be able to edit your issue on GitHub.
|
||||
</small>
|
||||
<div id="description-validation-error" class="validation-error hidden">Please enter a description.</div>
|
||||
<textarea name="description" id="description" cols="100" rows="15" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="github-submit-btn" disabled>Loading data...</button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script src="issueReporter.js"></script>
|
||||
</html>
|
||||
62
src/vs/code/electron-browser/issue/issueReporter.js
Normal file
62
src/vs/code/electron-browser/issue/issueReporter.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
function parseURLQueryArgs() {
|
||||
const search = window.location.search || '';
|
||||
|
||||
return search.split(/[?&]/)
|
||||
.filter(function (param) { return !!param; })
|
||||
.map(function (param) { return param.split('='); })
|
||||
.filter(function (param) { return param.length === 2; })
|
||||
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
|
||||
}
|
||||
|
||||
function createScript(src, onload) {
|
||||
const script = document.createElement('script');
|
||||
script.src = src;
|
||||
script.addEventListener('load', onload);
|
||||
|
||||
const head = document.getElementsByTagName('head')[0];
|
||||
head.insertBefore(script, head.lastChild);
|
||||
}
|
||||
|
||||
function uriFromPath(_path) {
|
||||
var pathName = path.resolve(_path).replace(/\\/g, '/');
|
||||
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
|
||||
pathName = '/' + pathName;
|
||||
}
|
||||
|
||||
return encodeURI('file://' + pathName);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const args = parseURLQueryArgs();
|
||||
const configuration = JSON.parse(args['config'] || '{}') || {};
|
||||
const rootUrl = uriFromPath(configuration.appRoot) + '/out';
|
||||
|
||||
// In the bundled version the nls plugin is packaged with the loader so the NLS Plugins
|
||||
// loads as soon as the loader loads. To be able to have pseudo translation
|
||||
createScript(rootUrl + '/vs/loader.js', function () {
|
||||
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
|
||||
|
||||
window.MonacoEnvironment = {};
|
||||
|
||||
var nlsConfig = { availableLanguages: {} };
|
||||
require.config({
|
||||
baseUrl: rootUrl,
|
||||
'vs/nls': nlsConfig,
|
||||
nodeCachedDataDir: configuration.nodeCachedDataDir,
|
||||
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
|
||||
});
|
||||
|
||||
require(['vs/code/electron-browser/issue/issueReporterMain'], (issueReporter) => {
|
||||
issueReporter.startup(configuration);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
392
src/vs/code/electron-browser/issue/issueReporterMain.ts
Normal file
392
src/vs/code/electron-browser/issue/issueReporterMain.ts
Normal file
@@ -0,0 +1,392 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { shell, ipcRenderer, webFrame } from 'electron';
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import product from 'vs/platform/node/product';
|
||||
import pkg from 'vs/platform/node/package';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser';
|
||||
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IWindowConfiguration, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
|
||||
import { ITelemetryAppenderChannel, TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
|
||||
import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
|
||||
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { IssueReporterModel, IssueReporterData } from 'vs/code/electron-browser/issue/issueReporterModel';
|
||||
import { IssueReporterStyles } from 'vs/platform/issue/common/issue';
|
||||
|
||||
export function startup(configuration: IWindowConfiguration) {
|
||||
const issueReporter = new IssueReporter(configuration);
|
||||
issueReporter.render();
|
||||
}
|
||||
|
||||
export class IssueReporter extends Disposable {
|
||||
private environmentService: IEnvironmentService;
|
||||
private telemetryService: ITelemetryService;
|
||||
private issueReporterModel: IssueReporterModel;
|
||||
|
||||
constructor(configuration: IWindowConfiguration) {
|
||||
super();
|
||||
|
||||
this.issueReporterModel = new IssueReporterModel({
|
||||
issueType: 0,
|
||||
includeSystemInfo: true,
|
||||
includeWorkspaceInfo: true,
|
||||
includeProcessInfo: true
|
||||
});
|
||||
|
||||
ipcRenderer.on('issueStyleResponse', (event, styles: IssueReporterStyles) => {
|
||||
this.applyZoom(styles.zoomLevel);
|
||||
this.applyStyles(styles);
|
||||
});
|
||||
|
||||
ipcRenderer.on('issueInfoResponse', (event, info) => {
|
||||
this.issueReporterModel.update(info);
|
||||
|
||||
this.updateAllBlocks(this.issueReporterModel.getData());
|
||||
|
||||
const submitButton = <HTMLButtonElement>document.getElementById('github-submit-btn');
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = 'Preview on GitHub';
|
||||
});
|
||||
|
||||
ipcRenderer.send('issueInfoRequest');
|
||||
ipcRenderer.send('issueStyleRequest');
|
||||
|
||||
this.initServices(configuration);
|
||||
this.setEventHandlers();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.renderBlocks();
|
||||
}
|
||||
|
||||
private applyZoom(zoomLevel: number) {
|
||||
webFrame.setZoomLevel(zoomLevel);
|
||||
browser.setZoomFactor(webFrame.getZoomFactor());
|
||||
// See https://github.com/Microsoft/vscode/issues/26151
|
||||
// Cannot be trusted because the webFrame might take some time
|
||||
// until it really applies the new zoom level
|
||||
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
|
||||
}
|
||||
|
||||
private applyStyles(styles: IssueReporterStyles) {
|
||||
const styleTag = document.createElement('style');
|
||||
const content: string[] = [];
|
||||
|
||||
if (styles.inputBackground) {
|
||||
content.push(`input, textarea, select { background-color: ${styles.inputBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.inputBorder) {
|
||||
content.push(`input, textarea, select { border: 1px solid ${styles.inputBorder}; }`);
|
||||
} else {
|
||||
content.push(`input, textarea, select { border: none; }`);
|
||||
}
|
||||
|
||||
if (styles.inputForeground) {
|
||||
content.push(`input, textarea, select { color: ${styles.inputForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.inputErrorBorder) {
|
||||
content.push(`.invalid-input, .invalid-input:focus { border: 1px solid ${styles.inputErrorBorder}; }`);
|
||||
}
|
||||
|
||||
if (styles.inputActiveBorder) {
|
||||
content.push(`input[type='text']:focus, textarea:focus, select:focus, summary:focus { border: 1px solid ${styles.inputActiveBorder}; outline-style: none; }`);
|
||||
}
|
||||
|
||||
if (styles.textLinkColor) {
|
||||
content.push(`a { color: ${styles.textLinkColor}; }`);
|
||||
}
|
||||
|
||||
if (styles.buttonBackground) {
|
||||
content.push(`button { background-color: ${styles.buttonBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.buttonForeground) {
|
||||
content.push(`button { color: ${styles.buttonForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.buttonHoverBackground) {
|
||||
content.push(`button:hover:enabled { background-color: ${styles.buttonHoverBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.textLinkColor) {
|
||||
content.push(`a { color: ${styles.textLinkColor}; }`);
|
||||
}
|
||||
|
||||
styleTag.innerHTML = content.join('\n');
|
||||
document.head.appendChild(styleTag);
|
||||
|
||||
document.body.style.backgroundColor = styles.backgroundColor;
|
||||
document.body.style.color = styles.color;
|
||||
}
|
||||
|
||||
private initServices(configuration: IWindowConfiguration): void {
|
||||
const serviceCollection = new ServiceCollection();
|
||||
const mainProcessClient = new ElectronIPCClient(String(`window${configuration.windowId}`));
|
||||
|
||||
const windowsChannel = mainProcessClient.getChannel('windows');
|
||||
serviceCollection.set(IWindowsService, new WindowsChannelClient(windowsChannel));
|
||||
this.environmentService = new EnvironmentService(configuration, configuration.execPath);
|
||||
|
||||
const sharedProcess = (<IWindowsService>serviceCollection.get(IWindowsService)).whenSharedProcessReady()
|
||||
.then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${configuration.windowId}`));
|
||||
|
||||
const instantiationService = new InstantiationService(serviceCollection, true);
|
||||
if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
|
||||
const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
|
||||
const appender = new TelemetryAppenderClient(channel);
|
||||
const commonProperties = resolveCommonProperties(product.commit, pkg.version, configuration.machineId, this.environmentService.installSourcePath);
|
||||
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
|
||||
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths };
|
||||
|
||||
const telemetryService = instantiationService.createInstance(TelemetryService, config);
|
||||
this._register(telemetryService);
|
||||
|
||||
this.telemetryService = telemetryService;
|
||||
} else {
|
||||
this.telemetryService = NullTelemetryService;
|
||||
}
|
||||
}
|
||||
|
||||
private setEventHandlers(): void {
|
||||
document.getElementById('issue-type').addEventListener('change', (event: Event) => {
|
||||
this.issueReporterModel.update({ issueType: parseInt((<HTMLInputElement>event.target).value) });
|
||||
this.render();
|
||||
});
|
||||
|
||||
document.getElementById('includeSystemInfo').addEventListener('click', (event: Event) => {
|
||||
event.stopPropagation();
|
||||
this.issueReporterModel.update({ includeSystemInfo: !this.issueReporterModel.getData().includeSystemInfo });
|
||||
});
|
||||
|
||||
document.getElementById('includeProcessInfo').addEventListener('click', (event: Event) => {
|
||||
event.stopPropagation();
|
||||
this.issueReporterModel.update({ includeProcessInfo: !this.issueReporterModel.getData().includeSystemInfo });
|
||||
});
|
||||
|
||||
document.getElementById('includeWorkspaceInfo').addEventListener('click', (event: Event) => {
|
||||
event.stopPropagation();
|
||||
this.issueReporterModel.update({ includeWorkspaceInfo: !this.issueReporterModel.getData().includeWorkspaceInfo });
|
||||
});
|
||||
|
||||
document.getElementById('description').addEventListener('blur', (event: Event) => {
|
||||
this.issueReporterModel.update({ issueDescription: (<HTMLInputElement>event.target).value });
|
||||
});
|
||||
|
||||
function addIssuesToList(list, issueJSON) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const link = $('a', { href: issueJSON[i].html_url });
|
||||
link.textContent = issueJSON[i].title;
|
||||
link.addEventListener('click', (event) => {
|
||||
shell.openExternal((<HTMLAnchorElement>event.target).href);
|
||||
});
|
||||
|
||||
const item = $('li', {}, link);
|
||||
list.appendChild(item);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('issue-title').addEventListener('blur', (event) => {
|
||||
const title = (<HTMLInputElement>event.target).value;
|
||||
const similarIssues = document.getElementById('similar-issues');
|
||||
similarIssues.innerHTML = '';
|
||||
|
||||
if (title) {
|
||||
const query = `is:issue+repo:microsoft/vscode+${title}`;
|
||||
window.fetch(`https://api.github.com/search/issues?q=${query}&per_page=5`).then((response) => {
|
||||
response.json().then(result => {
|
||||
if (result.items.length) {
|
||||
const issues = $('ul');
|
||||
const issuesText = $('div.list-title');
|
||||
issuesText.textContent = 'Similar issues:';
|
||||
addIssuesToList(issues, result.items);
|
||||
similarIssues.appendChild(issuesText);
|
||||
similarIssues.appendChild(issues);
|
||||
}
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('github-submit-btn').addEventListener('click', () => this.createIssue());
|
||||
}
|
||||
|
||||
private renderBlocks(): void {
|
||||
// Depending on Issue Type, we render different blocks and text
|
||||
const { issueType } = this.issueReporterModel.getData();
|
||||
const systemBlock = document.querySelector('.block-system');
|
||||
const processBlock = document.querySelector('.block-process');
|
||||
const workspaceBlock = document.querySelector('.block-workspace');
|
||||
|
||||
const descriptionTitle = document.querySelector('.block-description .block-title');
|
||||
const descriptionSubtitle = document.querySelector('.block-description .block-subtitle');
|
||||
|
||||
// 1 - Bug
|
||||
if (issueType === 0) {
|
||||
show(systemBlock);
|
||||
hide(processBlock);
|
||||
hide(workspaceBlock);
|
||||
|
||||
descriptionTitle.innerHTML = 'Steps to reproduce <span class="required-input">*</span>';
|
||||
show(descriptionSubtitle);
|
||||
descriptionSubtitle.innerHTML = 'How did you encounter this problem? Clear steps to reproduce the problem help our investigation. What did you expect to happen and what actually happened?';
|
||||
}
|
||||
// 2 - Perf Issue
|
||||
else if (issueType === 1) {
|
||||
show(systemBlock);
|
||||
show(processBlock);
|
||||
show(workspaceBlock);
|
||||
|
||||
descriptionTitle.innerHTML = 'Steps to reproduce <span class="required-input">*</span>';
|
||||
show(descriptionSubtitle);
|
||||
descriptionSubtitle.innerHTML = 'When did this performance issue happen? For example, does it occur on startup or after a specific series of actions? Any details you can provide help our investigation.';
|
||||
}
|
||||
// 3 - Feature Request
|
||||
else {
|
||||
hide(systemBlock);
|
||||
hide(processBlock);
|
||||
hide(workspaceBlock);
|
||||
|
||||
descriptionTitle.innerHTML = 'Description <span class="required-input">*</span>';
|
||||
hide(descriptionSubtitle);
|
||||
}
|
||||
}
|
||||
|
||||
private validateInput(inputId: string): boolean {
|
||||
const inputElement = (<HTMLInputElement>document.getElementById(inputId));
|
||||
if (!inputElement.value) {
|
||||
show(document.getElementById(`${inputId}-validation-error`));
|
||||
inputElement.classList.add('invalid-input');
|
||||
return false;
|
||||
} else {
|
||||
hide(document.getElementById(`${inputId}-validation-error`));
|
||||
inputElement.classList.remove('invalid-input');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private validateInputs(): boolean {
|
||||
let isValid = true;
|
||||
['issue-title', 'description'].forEach(elementId => {
|
||||
isValid = this.validateInput(elementId) && isValid;
|
||||
|
||||
});
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private createIssue(): void {
|
||||
if (!this.validateInputs()) {
|
||||
// If inputs are invalid, set focus to the first one and add listeners on them
|
||||
// to detect further changes
|
||||
(<HTMLInputElement>document.getElementsByClassName('invalid-input')[0]).focus();
|
||||
|
||||
document.getElementById('issue-title').addEventListener('input', (event) => {
|
||||
this.validateInput('issue-title');
|
||||
});
|
||||
|
||||
document.getElementById('description').addEventListener('input', (event) => {
|
||||
this.validateInput('description');
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.telemetryService) {
|
||||
/* __GDPR__
|
||||
"issueReporterSubmit" : {
|
||||
"issueType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('issueReporterSubmit', { issueType: this.issueReporterModel.getData().issueType });
|
||||
}
|
||||
|
||||
const issueTitle = (<HTMLInputElement>document.getElementById('issue-title')).value;
|
||||
const baseUrl = `https://github.com/microsoft/vscode/issues/new?title=${issueTitle}&body=`;
|
||||
const issueBody = this.issueReporterModel.serialize();
|
||||
shell.openExternal(baseUrl + encodeURIComponent(issueBody));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update blocks
|
||||
*/
|
||||
|
||||
private updateAllBlocks(state) {
|
||||
this.updateVersionInfo(state);
|
||||
this.updateSystemInfo(state);
|
||||
this.updateProcessInfo(state);
|
||||
this.updateWorkspaceInfo(state);
|
||||
}
|
||||
|
||||
private updateVersionInfo = (state: IssueReporterData) => {
|
||||
const version = document.getElementById('vscode-version');
|
||||
(<HTMLInputElement>version).value = state.versionInfo.vscodeVersion;
|
||||
|
||||
const osversion = document.getElementById('os');
|
||||
(<HTMLInputElement>osversion).value = state.versionInfo.os;
|
||||
}
|
||||
|
||||
private updateSystemInfo = (state) => {
|
||||
const target = document.querySelector('.block-system .block-info');
|
||||
let tableHtml = '';
|
||||
Object.keys(state.systemInfo).forEach(k => {
|
||||
tableHtml += `
|
||||
<tr>
|
||||
<td>${k}</td>
|
||||
<td>${state.systemInfo[k]}</td>
|
||||
</tr>`;
|
||||
});
|
||||
target.innerHTML = `<table>${tableHtml}</table>`;
|
||||
}
|
||||
|
||||
private updateProcessInfo = (state) => {
|
||||
const target = document.querySelector('.block-process .block-info');
|
||||
|
||||
let tableHtml = `
|
||||
<tr>
|
||||
<th>pid</th>
|
||||
<th>CPU %</th>
|
||||
<th>Memory (MB)</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
`;
|
||||
state.processInfo.forEach(p => {
|
||||
tableHtml += `
|
||||
<tr>
|
||||
<td>${p.pid}</td>
|
||||
<td>${p.cpu}</td>
|
||||
<td>${p.memory}</td>
|
||||
<td>${p.name}</td>
|
||||
</tr>`;
|
||||
});
|
||||
target.innerHTML = `<table>${tableHtml}</table>`;
|
||||
}
|
||||
|
||||
private updateWorkspaceInfo = (state) => {
|
||||
document.querySelector('.block-workspace .block-info code').textContent = '\n' + state.workspaceInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// helper functions
|
||||
|
||||
function hide(el) {
|
||||
el.classList.add('hidden');
|
||||
}
|
||||
function show(el) {
|
||||
el.classList.remove('hidden');
|
||||
}
|
||||
132
src/vs/code/electron-browser/issue/issueReporterModel.ts
Normal file
132
src/vs/code/electron-browser/issue/issueReporterModel.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
|
||||
export interface IssueReporterData {
|
||||
issueType?: number;
|
||||
issueDescription?: string;
|
||||
versionInfo?: any;
|
||||
systemInfo?: any;
|
||||
processInfo?: any;
|
||||
workspaceInfo?: any;
|
||||
includeSystemInfo?: boolean;
|
||||
includeWorkspaceInfo?: boolean;
|
||||
includeProcessInfo?: boolean;
|
||||
}
|
||||
|
||||
export class IssueReporterModel {
|
||||
private _data: IssueReporterData;
|
||||
|
||||
constructor(initialData?: IssueReporterData) {
|
||||
this._data = initialData || {};
|
||||
}
|
||||
|
||||
getData(): IssueReporterData {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
update(newData: IssueReporterData): void {
|
||||
assign(this._data, newData);
|
||||
}
|
||||
|
||||
serialize(): string {
|
||||
return `
|
||||
### Issue Type
|
||||
${this.getIssueTypeTitle()}
|
||||
|
||||
### Description
|
||||
|
||||
${this._data.issueDescription}
|
||||
|
||||
### VS Code Info
|
||||
|
||||
VS Code version: ${this._data.versionInfo && this._data.versionInfo.vscodeVersion}
|
||||
OS version: ${this._data.versionInfo && this._data.versionInfo.os}
|
||||
|
||||
${this.getInfos()}
|
||||
|
||||
<!-- Generated by VS Code Issue Helper -->
|
||||
`;
|
||||
}
|
||||
|
||||
private getIssueTypeTitle(): string {
|
||||
if (this._data.issueType === 0) {
|
||||
return 'Bug';
|
||||
} else if (this._data.issueType === 1) {
|
||||
return 'Performance Issue';
|
||||
} else {
|
||||
return 'Feature Request';
|
||||
}
|
||||
}
|
||||
|
||||
private getInfos(): string {
|
||||
let info = '';
|
||||
|
||||
if (this._data.includeSystemInfo) {
|
||||
info += this.generateSystemInfoMd();
|
||||
}
|
||||
|
||||
// For perf issue, add process info and workspace info too
|
||||
if (this._data.issueType === 1) {
|
||||
|
||||
if (this._data.includeProcessInfo) {
|
||||
info += this.generateProcessInfoMd();
|
||||
}
|
||||
|
||||
if (this._data.includeWorkspaceInfo) {
|
||||
info += this.generateWorkspaceInfoMd();
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private generateSystemInfoMd(): string {
|
||||
let md = `<details>
|
||||
<summary>System Info</summary>
|
||||
|
||||
|Item|Value|
|
||||
|---|---|
|
||||
`;
|
||||
|
||||
Object.keys(this._data.systemInfo).forEach(k => {
|
||||
md += `|${k}|${this._data.systemInfo[k]}|\n`;
|
||||
});
|
||||
|
||||
md += '\n</details>';
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
private generateProcessInfoMd(): string {
|
||||
let md = `<details>
|
||||
<summary>Process Info</summary>
|
||||
|
||||
|pid|CPU|Memory (MB)|Name|
|
||||
|---|---|---|---|
|
||||
`;
|
||||
|
||||
this._data.processInfo.forEach(p => {
|
||||
md += `|${p.pid}|${p.cpu}|${p.memory}|${p.name}|\n`;
|
||||
});
|
||||
|
||||
md += '\n</details>';
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
private generateWorkspaceInfoMd(): string {
|
||||
return `<details>
|
||||
<summary>Workspace Info</summary>
|
||||
|
||||
\`\`\`
|
||||
${this._data.workspaceInfo};
|
||||
\`\`\`
|
||||
|
||||
</details>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel';
|
||||
|
||||
suite('IssueReporter', () => {
|
||||
|
||||
test('serializes model', () => {
|
||||
const issueReporterModel = new IssueReporterModel();
|
||||
assert.equal(issueReporterModel.serialize(),
|
||||
`
|
||||
### Issue Type
|
||||
Feature Request
|
||||
|
||||
### Description
|
||||
|
||||
undefined
|
||||
|
||||
### VS Code Info
|
||||
|
||||
VS Code version: undefined
|
||||
OS version: undefined
|
||||
|
||||
|
||||
|
||||
<!-- Generated by VS Code Issue Helper -->
|
||||
`);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user