mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 06:17:18 +00:00
web reporter refactor and issueFormService (#212951)
* web version working * change to mainWindow * PROPER MOVEMENT * working for web as well * move issueFormService to workbench/contrib/issue * cleaning up{ * more cleanup, added setting * styling * use mainwindow to open and closee * css fixes * fix css again * fix CSS and wonky applyCSS rules * change gulpfile * add and update system info * address some of the comments * move files! small changes * move JS and non window specific back to electron sandbox * fix on issueReporter.js * fix build file * fix gulp file too.... * move everything into contrib * fix workbench import * move everything else into contrib, fix import * change name to web * applying more feedback fixes :D * fix command and remove unused import: * add back issueTroubleshoot * fix gulpile outputs * fix out exclusion:
This commit is contained in:
parent
0d350085d6
commit
d05d280364
|
@ -73,6 +73,8 @@ const vscodeResources = [
|
|||
'out-build/vs/workbench/contrib/terminal/browser/media/*.sh',
|
||||
'out-build/vs/workbench/contrib/terminal/browser/media/*.zsh',
|
||||
'out-build/vs/workbench/contrib/webview/browser/pre/*.js',
|
||||
'!out-build/vs/workbench/contrib/issue/browser/*.html',
|
||||
'!out-build/vs/workbench/contrib/issue/**/*-dev.html',
|
||||
'out-build/vs/**/markdown.css',
|
||||
'out-build/vs/workbench/contrib/tasks/**/*.json',
|
||||
'!**/test/**'
|
||||
|
@ -122,7 +124,8 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
|
|||
},
|
||||
manual: [
|
||||
{ src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/workbench/workbench.js'], out: 'vs/code/electron-sandbox/workbench/workbench.js' },
|
||||
{ src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/issue/issueReporter.js'], out: 'vs/code/electron-sandbox/issue/issueReporter.js' },
|
||||
// TODO: @justchen https://github.com/microsoft/vscode/issues/213332 make sure to remove when we use window.open on desktop.
|
||||
{ src: [...windowBootstrapFiles, 'out-build/vs/workbench/contrib/issue/electron-sandbox/issueReporter.js'], out: 'vs/workbench/contrib/issue/electron-sandbox/issueReporter.js' },
|
||||
{ src: [...windowBootstrapFiles, 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.js'], out: 'vs/code/electron-sandbox/processExplorer/processExplorer.js' }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ exports.workbenchDesktop = [
|
|||
createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'),
|
||||
createModuleDescription('vs/platform/files/node/watcher/watcherMain'),
|
||||
createModuleDescription('vs/platform/terminal/node/ptyHostMain'),
|
||||
createModuleDescription('vs/workbench/api/node/extensionHostProcess')
|
||||
createModuleDescription('vs/workbench/api/node/extensionHostProcess'),
|
||||
createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'),
|
||||
];
|
||||
|
||||
exports.workbenchWeb = [
|
||||
|
@ -76,7 +77,6 @@ exports.code = [
|
|||
createModuleDescription('vs/code/electron-main/main'),
|
||||
createModuleDescription('vs/code/node/cli'),
|
||||
createModuleDescription('vs/code/node/cliProcessMain', ['vs/code/node/cli']),
|
||||
createModuleDescription('vs/code/electron-sandbox/issue/issueReporterMain'),
|
||||
createModuleDescription('vs/code/node/sharedProcess/sharedProcessMain'),
|
||||
createModuleDescription('vs/code/electron-sandbox/processExplorer/processExplorerMain')
|
||||
];
|
||||
|
|
|
@ -173,7 +173,7 @@ export class IssueMainService implements IIssueMainService {
|
|||
});
|
||||
|
||||
this.issueReporterWindow.loadURL(
|
||||
FileAccess.asBrowserUri(`vs/code/electron-sandbox/issue/issueReporter${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)
|
||||
FileAccess.asBrowserUri(`vs/workbench/contrib/issue/electron-sandbox/issueReporter${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)
|
||||
);
|
||||
|
||||
this.issueReporterWindow.on('close', () => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
|
||||
export class ReportExtensionIssueAction extends Action {
|
||||
|
||||
|
|
|
@ -10,10 +10,14 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
|
|||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { WebIssueService } from 'vs/workbench/services/issue/browser/issueService';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { BrowserIssueService } from 'vs/workbench/contrib/issue/browser/issueService';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { BaseIssueContribution } from 'vs/workbench/contrib/issue/common/issue.contribution';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IIssueMainService } from 'vs/platform/issue/common/issue';
|
||||
import { IssueFormService } from 'vs/workbench/contrib/issue/browser/issueFormService';
|
||||
import 'vs/workbench/contrib/issue/browser/issueTroubleshoot';
|
||||
|
||||
|
||||
class WebIssueContribution extends BaseIssueContribution {
|
||||
|
@ -24,8 +28,20 @@ class WebIssueContribution extends BaseIssueContribution {
|
|||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(Extensions.Workbench).registerWorkbenchContribution(WebIssueContribution, LifecyclePhase.Restored);
|
||||
|
||||
registerSingleton(IWorkbenchIssueService, WebIssueService, InstantiationType.Delayed);
|
||||
registerSingleton(IWorkbenchIssueService, BrowserIssueService, InstantiationType.Delayed);
|
||||
registerSingleton(IIssueMainService, IssueFormService, InstantiationType.Delayed);
|
||||
|
||||
CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => {
|
||||
return nls.localize('statusUnsupported', "The --status argument is not yet supported in browsers.");
|
||||
});
|
||||
|
||||
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
||||
.registerConfiguration({
|
||||
properties: {
|
||||
'issueReporter.experimental.webReporter': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Enable experimental issue reporter for web.',
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
|
@ -14,11 +14,12 @@ import { CancellationError } from 'vs/base/common/errors';
|
|||
import { isLinuxSnap } from 'vs/base/common/platform';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/code/browser/issue/issueReporterModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles, IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
|
||||
import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet';
|
||||
import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/workbench/contrib/issue/browser/issueReporterModel';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
|
||||
const MAX_URL_LENGTH = 7500;
|
||||
|
||||
|
@ -156,7 +157,7 @@ export class BaseIssueReporterService extends Disposable {
|
|||
const content: string[] = [];
|
||||
|
||||
if (styles.inputBackground) {
|
||||
content.push(`input[type="text"], textarea, select, .issues-container > .issue > .issue-state, .block-info { background-color: ${styles.inputBackground}; }`);
|
||||
content.push(`input[type="text"], textarea, select, .issues-container > .issue > .issue-state, .block-info { background-color: ${styles.inputBackground} !important; }`);
|
||||
}
|
||||
|
||||
if (styles.inputBorder) {
|
||||
|
@ -166,7 +167,7 @@ export class BaseIssueReporterService extends Disposable {
|
|||
}
|
||||
|
||||
if (styles.inputForeground) {
|
||||
content.push(`input[type="text"], textarea, select, .issues-container > .issue > .issue-state, .block-info { color: ${styles.inputForeground}; }`);
|
||||
content.push(`input[type="text"], textarea, select, .issues-container > .issue > .issue-state, .block-info { color: ${styles.inputForeground} !important; }`);
|
||||
}
|
||||
|
||||
if (styles.inputErrorBorder) {
|
||||
|
@ -825,7 +826,8 @@ export class BaseIssueReporterService extends Disposable {
|
|||
}),
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.data.githubAccessToken}`
|
||||
'Authorization': `Bearer ${this.data.githubAccessToken}`,
|
||||
'User-Agent': 'request'
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -835,8 +837,7 @@ export class BaseIssueReporterService extends Disposable {
|
|||
return false;
|
||||
}
|
||||
const result = await response.json();
|
||||
this.window.open(result.html_url, '_blank');
|
||||
|
||||
mainWindow.open(result.html_url, '_blank');
|
||||
this.close();
|
||||
return true;
|
||||
}
|
180
src/vs/workbench/contrib/issue/browser/issueFormService.ts
Normal file
180
src/vs/workbench/contrib/issue/browser/issueFormService.ts
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { safeInnerHtml } from 'vs/base/browser/dom';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import BaseHtml from 'vs/workbench/contrib/issue/browser/issueReporterPage';
|
||||
import 'vs/css!./media/issueReporter';
|
||||
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { PerformanceInfo, SystemInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { ExtensionIdentifier, ExtensionIdentifierSet } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IIssueMainService, IssueReporterData, ProcessExplorerData } from 'vs/platform/issue/common/issue';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IssueWebReporter } from 'vs/workbench/contrib/issue/browser/issueReporterService';
|
||||
import { AuxiliaryWindowMode, IAuxiliaryWindowService } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService';
|
||||
|
||||
export class IssueFormService implements IIssueMainService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private issueReporterWindow: Window | null = null;
|
||||
private extensionIdentifierSet: ExtensionIdentifierSet = new ExtensionIdentifierSet();
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IAuxiliaryWindowService private readonly auxiliaryWindowService: IAuxiliaryWindowService,
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
|
||||
// listen for messages from the main window
|
||||
mainWindow.addEventListener('message', async (event) => {
|
||||
if (event.data && event.data.sendChannel === 'vscode:triggerReporterMenu') {
|
||||
// creates menu from contributed
|
||||
const menu = this.menuService.createMenu(MenuId.IssueReporter, this.contextKeyService);
|
||||
|
||||
// render menu and dispose
|
||||
const actions = menu.getActions({ renderShortTitle: true }).flatMap(entry => entry[1]);
|
||||
for (const action of actions) {
|
||||
try {
|
||||
if (action.item && 'source' in action.item && action.item.source?.id === event.data.extensionId) {
|
||||
this.extensionIdentifierSet.add(event.data.extensionId);
|
||||
await action.run();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.extensionIdentifierSet.has(event.data.extensionId)) {
|
||||
// send undefined to indicate no action was taken
|
||||
const replyChannel = `vscode:triggerReporterMenuResponse`;
|
||||
mainWindow.postMessage({ replyChannel }, '*');
|
||||
}
|
||||
|
||||
menu.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async openReporter(data: IssueReporterData): Promise<void> {
|
||||
if (data.extensionId && this.extensionIdentifierSet.has(data.extensionId)) {
|
||||
const replyChannel = `vscode:triggerReporterMenuResponse`;
|
||||
mainWindow.postMessage({ data, replyChannel }, '*');
|
||||
this.extensionIdentifierSet.delete(new ExtensionIdentifier(data.extensionId));
|
||||
}
|
||||
|
||||
if (this.issueReporterWindow) {
|
||||
this.issueReporterWindow.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
// Auxiliary Window
|
||||
const auxiliaryWindow = disposables.add(await this.auxiliaryWindowService.open({ mode: AuxiliaryWindowMode.Normal }));
|
||||
|
||||
this.issueReporterWindow = auxiliaryWindow.window;
|
||||
|
||||
|
||||
|
||||
if (auxiliaryWindow) {
|
||||
await auxiliaryWindow.whenStylesHaveLoaded;
|
||||
auxiliaryWindow.window.document.title = 'Issue Reporter';
|
||||
auxiliaryWindow.window.document.body.classList.add('issue-reporter-body');
|
||||
|
||||
// custom issue reporter wrapper
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('monaco-workbench');
|
||||
|
||||
// removes preset monaco-workbench
|
||||
auxiliaryWindow.container.remove();
|
||||
auxiliaryWindow.window.document.body.appendChild(div);
|
||||
safeInnerHtml(div, BaseHtml());
|
||||
|
||||
// create issue reporter and instantiate
|
||||
const issueReporter = this.instantiationService.createInstance(IssueWebReporter, false, data, { type: '', arch: '', release: '' }, product, auxiliaryWindow.window);
|
||||
issueReporter.render();
|
||||
} else {
|
||||
console.error('Failed to open auxiliary window');
|
||||
}
|
||||
|
||||
// handle closing issue reporter
|
||||
this.issueReporterWindow?.addEventListener('beforeunload', () => {
|
||||
auxiliaryWindow.window.close();
|
||||
this.issueReporterWindow = null;
|
||||
});
|
||||
}
|
||||
|
||||
async openProcessExplorer(data: ProcessExplorerData): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
stopTracing(): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSystemStatus(): Promise<string> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$getSystemInfo(): Promise<SystemInfo> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$getPerformanceInfo(): Promise<PerformanceInfo> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$reloadWithExtensionsDisabled(): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$showConfirmCloseDialog(): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$showClipboardDialog(): Promise<boolean> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$getIssueReporterUri(extensionId: string): Promise<URI> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$getIssueReporterData(extensionId: string): Promise<string> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$getIssueReporterTemplate(extensionId: string): Promise<string> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
$getReporterStatus(extensionId: string, extensionName: string): Promise<boolean[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
async $sendReporterMenu(extensionId: string, extensionName: string): Promise<IssueReporterData | undefined> {
|
||||
const sendChannel = `vscode:triggerReporterMenu`;
|
||||
mainWindow.postMessage({ sendChannel, extensionId, extensionName }, '*');
|
||||
|
||||
const result = await new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
mainWindow.removeEventListener('message', listener);
|
||||
reject(new Error('Timeout exceeded'));
|
||||
}, 5000); // Set the timeout value in milliseconds (e.g., 5000 for 5 seconds)
|
||||
|
||||
const listener = (event: MessageEvent) => {
|
||||
const replyChannel = `vscode:triggerReporterMenuResponse`;
|
||||
if (event.data && event.data.replyChannel === replyChannel) {
|
||||
clearTimeout(timeout);
|
||||
mainWindow.removeEventListener('message', listener);
|
||||
resolve(event.data.data);
|
||||
}
|
||||
};
|
||||
mainWindow.addEventListener('message', listener);
|
||||
});
|
||||
|
||||
return result as IssueReporterData | undefined;
|
||||
}
|
||||
|
||||
async $closeReporter(): Promise<void> {
|
||||
this.issueReporterWindow?.close();
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ export interface IssueReporterData {
|
|||
|
||||
versionInfo?: any;
|
||||
systemInfo?: SystemInfo;
|
||||
systemInfoWeb?: string;
|
||||
processInfo?: string;
|
||||
workspaceInfo?: string;
|
||||
|
||||
|
@ -138,6 +139,10 @@ ${this.getInfos()}
|
|||
if (this._data.includeSystemInfo && this._data.systemInfo) {
|
||||
info += this.generateSystemInfoMd();
|
||||
}
|
||||
|
||||
if (this._data.includeSystemInfo && this._data.systemInfoWeb) {
|
||||
info += 'System Info: ' + this._data.systemInfoWeb;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._data.issueType === IssueType.PerformanceIssue) {
|
|
@ -24,7 +24,7 @@ const reviewGuidanceLabel = localize( // intentionally not escaped because of it
|
|||
);
|
||||
|
||||
export default (): string => `
|
||||
<div id="issue-reporter">
|
||||
<div class="issue-reporter" id="issue-reporter">
|
||||
<div id="english" class="input-group hidden">${escape(localize('completeInEnglish', "Please complete the form in English."))}</div>
|
||||
|
||||
<div id="review-guidance-help-text" class="input-group">${reviewGuidanceLabel}</div>
|
|
@ -3,12 +3,14 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { $, reset, windowOpenNoOpener } from 'vs/base/browser/dom';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { groupBy } from 'vs/base/common/collections';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { IProductConfiguration } from 'vs/base/common/product';
|
||||
import { BaseIssueReporterService } from 'vs/code/browser/issue/issue';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
|
||||
import { BaseIssueReporterService } from 'vs/workbench/contrib/issue/browser/issue';
|
||||
|
||||
// GitHub has let us know that we could up our limit here to 8k. We chose 7500 to play it safe.
|
||||
// ref https://github.com/microsoft/vscode/issues/159191
|
||||
|
@ -27,6 +29,17 @@ export class IssueWebReporter extends BaseIssueReporterService {
|
|||
@IIssueMainService issueMainService: IIssueMainService
|
||||
) {
|
||||
super(disableExtensions, data, os, product, window, true, issueMainService);
|
||||
|
||||
const target = this.window.document.querySelector<HTMLElement>('.block-system .block-info');
|
||||
|
||||
const webInfo = this.window.navigator.userAgent;
|
||||
if (webInfo) {
|
||||
target?.appendChild(this.window.document.createTextNode(webInfo));
|
||||
this.receivedSystemInfo = true;
|
||||
this.issueReporterModel.update({ systemInfoWeb: webInfo });
|
||||
|
||||
}
|
||||
|
||||
this.setEventHandlers();
|
||||
this.handleExtensionData(data.enabledExtensions);
|
||||
}
|
||||
|
@ -174,7 +187,31 @@ export class IssueWebReporter extends BaseIssueReporterService {
|
|||
this.issueReporterModel.update({ selectedExtension: matches[0] });
|
||||
const selectedExtension = this.issueReporterModel.getData().selectedExtension;
|
||||
if (selectedExtension) {
|
||||
await this.sendReporterMenu(selectedExtension);
|
||||
const iconElement = document.createElement('span');
|
||||
iconElement.classList.add(...ThemeIcon.asClassNameArray(Codicon.loading), 'codicon-modifier-spin');
|
||||
this.setLoading(iconElement);
|
||||
const openReporterData = await this.sendReporterMenu(selectedExtension);
|
||||
if (openReporterData) {
|
||||
if (this.selectedExtension === selectedExtensionId) {
|
||||
this.removeLoading(iconElement, true);
|
||||
this.data = openReporterData;
|
||||
} else if (this.selectedExtension !== selectedExtensionId) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.loadingExtensionData) {
|
||||
iconElement.classList.remove(...ThemeIcon.asClassNameArray(Codicon.loading), 'codicon-modifier-spin');
|
||||
}
|
||||
this.removeLoading(iconElement);
|
||||
this.clearExtensionData();
|
||||
selectedExtension.data = undefined;
|
||||
selectedExtension.uri = undefined;
|
||||
}
|
||||
if (this.selectedExtension === selectedExtensionId) {
|
||||
// repopulates the fields with the new data given the selected extension.
|
||||
this.updateExtensionStatus(matches[0]);
|
||||
this.openReporter = false;
|
||||
}
|
||||
} else {
|
||||
this.issueReporterModel.update({ selectedExtension: undefined });
|
||||
this.clearSearchResults();
|
210
src/vs/workbench/contrib/issue/browser/issueService.ts
Normal file
210
src/vs/workbench/contrib/issue/browser/issueService.ts
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { userAgent } from 'vs/base/common/platform';
|
||||
import { IExtensionDescription, ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
|
||||
import { getZoomLevel } from 'vs/base/browser/browser';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles } from 'vs/platform/issue/common/issue';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { buttonBackground, buttonForeground, buttonHoverBackground, foreground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
|
||||
import { IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication';
|
||||
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
|
||||
export class BrowserIssueService implements IWorkbenchIssueService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IIssueMainService private readonly issueMainService: IIssueMainService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IWorkbenchAssignmentService private readonly experimentService: IWorkbenchAssignmentService,
|
||||
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService,
|
||||
@IIntegrityService private readonly integrityService: IIntegrityService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) { }
|
||||
|
||||
//TODO @TylerLeonhardt @Tyriar to implement a process explorer for the web
|
||||
async openProcessExplorer(): Promise<void> {
|
||||
console.error('openProcessExplorer is not implemented in web');
|
||||
}
|
||||
|
||||
async openReporter(options: Partial<IssueReporterData>): Promise<void> {
|
||||
if (!this.configurationService.getValue<boolean>('issueReporter.experimental.webReporter')) {
|
||||
const extensionId = options.extensionId;
|
||||
// If we don't have a extensionId, treat this as a Core issue
|
||||
if (!extensionId) {
|
||||
if (this.productService.reportIssueUrl) {
|
||||
const uri = this.getIssueUriFromStaticContent(this.productService.reportIssueUrl);
|
||||
dom.windowOpenNoOpener(uri);
|
||||
return;
|
||||
}
|
||||
throw new Error(`No issue reporting URL configured for ${this.productService.nameLong}.`);
|
||||
}
|
||||
|
||||
const selectedExtension = this.extensionService.extensions.filter(ext => ext.identifier.value === options.extensionId)[0];
|
||||
const extensionGitHubUrl = this.getExtensionGitHubUrl(selectedExtension);
|
||||
if (!extensionGitHubUrl) {
|
||||
throw new Error(`Unable to find issue reporting url for ${extensionId}`);
|
||||
}
|
||||
const uri = this.getIssueUriFromStaticContent(`${extensionGitHubUrl}/issues/new`, selectedExtension);
|
||||
dom.windowOpenNoOpener(uri);
|
||||
}
|
||||
|
||||
if (this.productService.reportIssueUrl) {
|
||||
const theme = this.themeService.getColorTheme();
|
||||
const experiments = await this.experimentService.getCurrentExperiments();
|
||||
|
||||
let githubAccessToken = '';
|
||||
try {
|
||||
const githubSessions = await this.authenticationService.getSessions('github');
|
||||
const potentialSessions = githubSessions.filter(session => session.scopes.includes('repo'));
|
||||
githubAccessToken = potentialSessions[0]?.accessToken;
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// air on the side of caution and have false be the default
|
||||
let isUnsupported = false;
|
||||
try {
|
||||
isUnsupported = !(await this.integrityService.isPure()).isPure;
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
const extensionData: IssueReporterExtensionData[] = [];
|
||||
try {
|
||||
const extensions = await this.extensionManagementService.getInstalled();
|
||||
const enabledExtensions = extensions.filter(extension => this.extensionEnablementService.isEnabled(extension) || (options.extensionId && extension.identifier.id === options.extensionId));
|
||||
extensionData.push(...enabledExtensions.map((extension): IssueReporterExtensionData => {
|
||||
const { manifest } = extension;
|
||||
const manifestKeys = manifest.contributes ? Object.keys(manifest.contributes) : [];
|
||||
const isTheme = !manifest.main && !manifest.browser && manifestKeys.length === 1 && manifestKeys[0] === 'themes';
|
||||
const isBuiltin = extension.type === ExtensionType.System;
|
||||
return {
|
||||
name: manifest.name,
|
||||
publisher: manifest.publisher,
|
||||
version: manifest.version,
|
||||
repositoryUrl: manifest.repository && manifest.repository.url,
|
||||
bugsUrl: manifest.bugs && manifest.bugs.url,
|
||||
displayName: manifest.displayName,
|
||||
id: extension.identifier.id,
|
||||
data: options.data,
|
||||
uri: options.uri,
|
||||
isTheme,
|
||||
isBuiltin,
|
||||
extensionData: 'Extensions data loading',
|
||||
};
|
||||
}));
|
||||
} catch (e) {
|
||||
extensionData.push({
|
||||
name: 'Workbench Issue Service',
|
||||
publisher: 'Unknown',
|
||||
version: 'Unknown',
|
||||
repositoryUrl: undefined,
|
||||
bugsUrl: undefined,
|
||||
extensionData: `Extensions not loaded: ${e}`,
|
||||
displayName: `Extensions not loaded: ${e}`,
|
||||
id: 'workbench.issue',
|
||||
isTheme: false,
|
||||
isBuiltin: true
|
||||
});
|
||||
}
|
||||
|
||||
const issueReporterData: IssueReporterData = Object.assign({
|
||||
styles: getIssueReporterStyles(theme),
|
||||
zoomLevel: getZoomLevel(mainWindow),
|
||||
enabledExtensions: extensionData,
|
||||
experiments: experiments?.join('\n'),
|
||||
restrictedMode: !this.workspaceTrustManagementService.isWorkspaceTrusted(),
|
||||
isUnsupported,
|
||||
githubAccessToken
|
||||
}, options);
|
||||
|
||||
return this.issueMainService.openReporter(issueReporterData);
|
||||
}
|
||||
throw new Error(`No issue reporting URL configured for ${this.productService.nameLong}.`);
|
||||
|
||||
}
|
||||
|
||||
private getExtensionGitHubUrl(extension: IExtensionDescription): string {
|
||||
if (extension.isBuiltin && this.productService.reportIssueUrl) {
|
||||
return normalizeGitHubUrl(this.productService.reportIssueUrl);
|
||||
}
|
||||
|
||||
let repositoryUrl = '';
|
||||
|
||||
const bugsUrl = extension?.bugs?.url;
|
||||
const extensionUrl = extension?.repository?.url;
|
||||
|
||||
// If given, try to match the extension's bug url
|
||||
if (bugsUrl && bugsUrl.match(/^https?:\/\/github\.com\/(.*)/)) {
|
||||
repositoryUrl = normalizeGitHubUrl(bugsUrl);
|
||||
} else if (extensionUrl && extensionUrl.match(/^https?:\/\/github\.com\/(.*)/)) {
|
||||
repositoryUrl = normalizeGitHubUrl(extensionUrl);
|
||||
}
|
||||
|
||||
return repositoryUrl;
|
||||
}
|
||||
|
||||
private getIssueUriFromStaticContent(baseUri: string, extension?: IExtensionDescription): string {
|
||||
const issueDescription = `ADD ISSUE DESCRIPTION HERE
|
||||
|
||||
Version: ${this.productService.version}
|
||||
Commit: ${this.productService.commit ?? 'unknown'}
|
||||
User Agent: ${userAgent ?? 'unknown'}
|
||||
Embedder: ${this.productService.embedderIdentifier ?? 'unknown'}
|
||||
${extension?.version ? `\nExtension version: ${extension.version}` : ''}
|
||||
<!-- generated by web issue reporter -->`;
|
||||
|
||||
return `${baseUri}?body=${encodeURIComponent(issueDescription)}&labels=web`;
|
||||
}
|
||||
}
|
||||
|
||||
export function getIssueReporterStyles(theme: IColorTheme): IssueReporterStyles {
|
||||
return {
|
||||
backgroundColor: getColor(theme, SIDE_BAR_BACKGROUND),
|
||||
color: getColor(theme, foreground),
|
||||
textLinkColor: getColor(theme, textLinkForeground),
|
||||
textLinkActiveForeground: getColor(theme, textLinkActiveForeground),
|
||||
inputBackground: getColor(theme, inputBackground),
|
||||
inputForeground: getColor(theme, inputForeground),
|
||||
inputBorder: getColor(theme, inputBorder),
|
||||
inputActiveBorder: getColor(theme, inputActiveOptionBorder),
|
||||
inputErrorBorder: getColor(theme, inputValidationErrorBorder),
|
||||
inputErrorBackground: getColor(theme, inputValidationErrorBackground),
|
||||
inputErrorForeground: getColor(theme, inputValidationErrorForeground),
|
||||
buttonBackground: getColor(theme, buttonBackground),
|
||||
buttonForeground: getColor(theme, buttonForeground),
|
||||
buttonHoverBackground: getColor(theme, buttonHoverBackground),
|
||||
sliderActiveColor: getColor(theme, scrollbarSliderActiveBackground),
|
||||
sliderBackgroundColor: getColor(theme, scrollbarSliderBackground),
|
||||
sliderHoverColor: getColor(theme, scrollbarSliderHoverBackground),
|
||||
};
|
||||
}
|
||||
|
||||
function getColor(theme: IColorTheme, key: string): string | undefined {
|
||||
const color = theme.getColor(key);
|
||||
return color ? color.toString() : undefined;
|
||||
}
|
||||
|
||||
registerSingleton(IWorkbenchIssueService, BrowserIssueService, InstantiationType.Delayed);
|
|
@ -7,7 +7,7 @@ import { localize, localize2 } from 'vs/nls';
|
|||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { IUserDataProfileImportExportService, IUserDataProfileManagementService, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
459
src/vs/workbench/contrib/issue/browser/media/issueReporter.css
Normal file
459
src/vs/workbench/contrib/issue/browser/media/issueReporter.css
Normal file
|
@ -0,0 +1,459 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
.mac.web.issue-reporter-body {
|
||||
position: absolute;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.web.issue-reporter-body .monaco-workbench select{
|
||||
-webkit-appearance: auto;
|
||||
appearance: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Table
|
||||
*/
|
||||
|
||||
.issue-reporter table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
background-color: transparent;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.issue-reporter th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 1px solid;
|
||||
padding: 5px;
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
.issue-reporter td {
|
||||
padding: 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.issue-reporter tr td:first-child {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.issue-reporter label {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.issue-reporter .block-settingsSearchResults-details {
|
||||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
.issue-reporter .block-settingsSearchResults-details > div {
|
||||
padding: .5rem .75rem;
|
||||
}
|
||||
|
||||
.issue-reporter .section {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forms
|
||||
*/
|
||||
.issue-reporter input[type="text"],
|
||||
.issue-reporter textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: .375rem .75rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ced4da;
|
||||
}
|
||||
|
||||
.issue-reporter textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Button
|
||||
*/
|
||||
|
||||
.issue-reporter .monaco-text-button {
|
||||
display: block;
|
||||
width: auto;
|
||||
padding: 4px 10px;
|
||||
align-self: flex-end;
|
||||
margin-bottom: 1em;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.issue-reporter select {
|
||||
height: calc(2.25rem + 2px);
|
||||
display: inline-block;
|
||||
padding: 3px 3px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.issue-reporter * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.issue-reporter textarea,
|
||||
.issue-reporter input,
|
||||
.issue-reporter select {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.issue-reporter html {
|
||||
color: #CCCCCC;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.issue-reporter .extension-caption .codicon-modifier-spin {
|
||||
padding-bottom: 3px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
/* Font Families (with CJK support) */
|
||||
|
||||
.issue-reporter .mac.web {
|
||||
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .mac.web:lang(zh-Hans) {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .mac.web:lang(zh-Hant) {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .mac.web:lang(ja) {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .mac.web:lang(ko) {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .windows.web {
|
||||
font-family: "Segoe WPC", "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .windows.web:lang(zh-Hans) {
|
||||
font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .windows.web:lang(zh-Hant) {
|
||||
font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .windows.web:lang(ja) {
|
||||
font-family: "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .windows.web:lang(ko) {
|
||||
font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .linux.web {
|
||||
font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .linux.web:lang(zh-Hans) {
|
||||
font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .linux.web:lang(zh-Hant) {
|
||||
font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .linux.web:lang(ja) {
|
||||
font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter .linux.web:lang(ko) {
|
||||
font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif;
|
||||
}
|
||||
|
||||
.issue-reporter body {
|
||||
margin: 0;
|
||||
overflow-y: scroll;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.issue-reporter .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.issue-reporter .block {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.issue-reporter .block .block-info {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
overflow: auto;
|
||||
overflow-wrap: break-word;
|
||||
margin: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.issue-reporter {
|
||||
max-width: 85vw;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-top: 2em;
|
||||
padding-bottom: 2em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.issue-reporter .description-section {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.issue-reporter textarea {
|
||||
flex-grow: 1;
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
.issue-reporter .block-info-text {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.issue-reporter #github-submit-btn {
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.issue-reporter .two-col {
|
||||
display: inline-block;
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
.issue-reporter #vscode-version {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.issue-reporter .input-group {
|
||||
margin-bottom: 1em;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.issue-reporter #extension-selection {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.issue-reporter select,
|
||||
.issue-reporter input,
|
||||
.issue-reporter textarea {
|
||||
border: 1px solid transparent;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.issue-reporter .validation-error {
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
border-top: 0px !important;
|
||||
}
|
||||
|
||||
.issue-reporter .system-info {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
.issue-reporter input[type="checkbox"] {
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
margin-top: 0;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.issue-reporter input:disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.issue-reporter .list-title {
|
||||
margin-top: 1em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.issue-reporter .instructions {
|
||||
font-size: 12px;
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.issue-reporter a,
|
||||
.issue-reporter .workbenchCommand {
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.issue-reporter .workbenchCommand:disabled {
|
||||
color: #868e96;
|
||||
cursor: default
|
||||
}
|
||||
|
||||
.issue-reporter .block-extensions .block-info {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
/* Default styles, overwritten if a theme is provided */
|
||||
.issue-reporter input,
|
||||
.issue-reporter select,
|
||||
.issue-reporter textarea {
|
||||
background-color: #3c3c3c;
|
||||
border: none;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.issue-reporter .section .input-group .validation-error {
|
||||
margin-left: 100px;
|
||||
}
|
||||
|
||||
.issue-reporter .section .inline-form-control,
|
||||
.issue-reporter .section .inline-label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.issue-reporter .section .inline-label {
|
||||
width: 95px;
|
||||
}
|
||||
|
||||
.issue-reporter .section .inline-form-control,
|
||||
.issue-reporter .section .input-group .validation-error {
|
||||
width: calc(100% - 100px);
|
||||
}
|
||||
|
||||
.issue-reporter #issue-type {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.issue-reporter #similar-issues {
|
||||
margin-left: 15%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.issue-reporter #problem-source-help-text {
|
||||
margin-left: calc(15% + 1em);
|
||||
}
|
||||
|
||||
@media (max-width: 950px) {
|
||||
.issue-reporter .section .inline-label {
|
||||
width: 15%;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.issue-reporter #problem-source-help-text {
|
||||
margin-left: calc(15% + 1em);
|
||||
}
|
||||
|
||||
.issue-reporter .section .inline-form-control,
|
||||
.issue-reporter .section .input-group .validation-error {
|
||||
width: calc(85% - 5px);
|
||||
}
|
||||
|
||||
.issue-reporter .section .input-group .validation-error {
|
||||
margin-left: calc(15% + 4px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.issue-reporter .section .inline-label {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.issue-reporter #problem-source-help-text {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.issue-reporter .section .inline-form-control,
|
||||
.issue-reporter .section .input-group .validation-error {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.issue-reporter #similar-issues,
|
||||
.issue-reporter .section .input-group .validation-error {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.issue-reporter ::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.issue-reporter ::-webkit-scrollbar-thumb {
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.issue-reporter ::-webkit-scrollbar-corner {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.issue-reporter .issues-container {
|
||||
margin-left: 1.5em;
|
||||
margin-top: .5em;
|
||||
max-height: 92px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.issue-reporter .issues-container > .issue {
|
||||
padding: 4px 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.issue-reporter .issues-container > .issue > .issue-link {
|
||||
width: calc(100% - 82px);
|
||||
overflow: hidden;
|
||||
padding-top: 3px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.issue-reporter .issues-container > .issue > .issue-state .codicon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.issue-reporter .issues-container > .issue > .issue-state {
|
||||
display: flex;
|
||||
width: 77px;
|
||||
padding: 3px 6px;
|
||||
margin-right: 5px;
|
||||
color: #CCCCCC;
|
||||
background-color: #3c3c3c;
|
||||
border-radius: .25rem;
|
||||
}
|
||||
|
||||
.issue-reporter .issues-container > .issue .label {
|
||||
padding-top: 2px;
|
||||
margin-left: 5px;
|
||||
width: 44px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.issue-reporter .issues-container > .issue .issue-icon {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.issue-reporter a {
|
||||
color: var(--vscode-textLink-foreground);
|
||||
}
|
|
@ -11,7 +11,7 @@ import { CommandsRegistry, ICommandMetadata } from 'vs/platform/commands/common/
|
|||
import { IssueReporterData } from 'vs/platform/issue/common/issue';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { localize, localize2 } from 'vs/nls';
|
||||
import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { BaseIssueContribution } from 'vs/workbench/contrib/issue/common/issue.contribution';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
@ -23,6 +23,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess';
|
||||
import { IssueQuickAccess } from 'vs/workbench/contrib/issue/browser/issueQuickAccess';
|
||||
import 'vs/workbench/contrib/issue/electron-sandbox/issueMainService';
|
||||
import 'vs/workbench/contrib/issue/electron-sandbox/issueService';
|
||||
import 'vs/workbench/contrib/issue/browser/issueTroubleshoot';
|
||||
|
||||
|
||||
//#region Issue Contribution
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
</body>
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
<script src="../../../../../bootstrap.js"></script>
|
||||
<script src="../../../../../vs/loader.js"></script>
|
||||
<script src="../../../../../bootstrap-window.js"></script>
|
||||
<script src="issueReporter.js"></script>
|
||||
</html>
|
|
@ -10,7 +10,7 @@
|
|||
const bootstrapWindow = bootstrapWindowLib();
|
||||
|
||||
// Load issue reporter into window
|
||||
bootstrapWindow.load(['vs/code/electron-sandbox/issue/issueReporterMain'], function (issueReporter, configuration) {
|
||||
bootstrapWindow.load(['vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'], function (issueReporter, configuration) {
|
||||
return issueReporter.startup(configuration);
|
||||
},
|
||||
{
|
||||
|
@ -24,7 +24,7 @@
|
|||
);
|
||||
|
||||
/**
|
||||
* @typedef {import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration} ISandboxConfiguration
|
||||
* @typedef {import('../../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration} ISandboxConfiguration
|
||||
*
|
||||
* @returns {{
|
||||
* load: (
|
|
@ -6,7 +6,7 @@
|
|||
import { safeInnerHtml } from 'vs/base/browser/dom';
|
||||
import 'vs/base/browser/ui/codicons/codiconStyles'; // make sure codicon css is loaded
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
import BaseHtml from 'vs/code/browser/issue/issueReporterPage';
|
||||
import BaseHtml from 'vs/workbench/contrib/issue/browser/issueReporterPage';
|
||||
import 'vs/css!./media/issueReporter';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions';
|
||||
|
@ -18,7 +18,7 @@ import { registerMainProcessRemoteService } from 'vs/platform/ipc/electron-sandb
|
|||
import { IIssueMainService, IssueReporterWindowConfiguration } from 'vs/platform/issue/common/issue';
|
||||
import { INativeHostService } from 'vs/platform/native/common/native';
|
||||
import { NativeHostService } from 'vs/platform/native/common/nativeHostService';
|
||||
import { IssueReporter2 } from 'vs/code/electron-sandbox/issue/issueReporterService2';
|
||||
import { IssueReporter2 } from 'vs/workbench/contrib/issue/electron-sandbox/issueReporterService2';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
|
||||
export function startup(configuration: IssueReporterWindowConfiguration) {
|
|
@ -16,7 +16,7 @@ import { isLinuxSnap, isMacintosh } from 'vs/base/common/platform';
|
|||
import { escape } from 'vs/base/common/strings';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/code/browser/issue/issueReporterModel';
|
||||
import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/workbench/contrib/issue/browser/issueReporterModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles, IssueReporterWindowConfiguration, IssueType } from 'vs/platform/issue/common/issue';
|
|
@ -10,13 +10,13 @@ import { CancellationError } from 'vs/base/common/errors';
|
|||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IssueReporterData as IssueReporterModelData } from 'vs/code/browser/issue/issueReporterModel';
|
||||
import { BaseIssueReporterService, hide, show } from 'vs/code/browser/issue/issue';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterWindowConfiguration, IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { INativeHostService } from 'vs/platform/native/common/native';
|
||||
import { applyZoom, zoomIn, zoomOut } from 'vs/platform/window/electron-sandbox/window';
|
||||
import { BaseIssueReporterService, hide, show } from 'vs/workbench/contrib/issue/browser/issue';
|
||||
import { IssueReporterData as IssueReporterModelData } from 'vs/workbench/contrib/issue/browser/issueReporterModel';
|
||||
|
||||
// GitHub has let us know that we could up our limit here to 8k. We chose 7500 to play it safe.
|
||||
// ref https://github.com/microsoft/vscode/issues/159191
|
|
@ -20,7 +20,7 @@ import { IAuthenticationService } from 'vs/workbench/services/authentication/com
|
|||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
|
||||
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import * as assert from 'assert';
|
||||
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
||||
import { IssueReporterModel } from 'vs/code/browser/issue/issueReporterModel';
|
||||
import { IssueReporterModel } from 'vs/workbench/contrib/issue/browser/issueReporterModel';
|
||||
import { IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
|
||||
|
|
@ -50,7 +50,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host';
|
|||
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ctxIsMergeResultEditor, ctxMergeBaseUri } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
import { ILocalizedString } from 'vs/platform/action/common/action';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
|
|
|
@ -20,7 +20,6 @@ import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common
|
|||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
|
||||
|
@ -271,7 +270,7 @@ registerAction2(class extends Action2 {
|
|||
const bisectService = accessor.get(IExtensionBisectService);
|
||||
const productService = accessor.get(IProductService);
|
||||
const extensionEnablementService = accessor.get(IGlobalExtensionEnablementService);
|
||||
const issueService = accessor.get(IWorkbenchIssueService);
|
||||
const commandService = accessor.get(ICommandService);
|
||||
|
||||
if (!bisectService.isActive) {
|
||||
return;
|
||||
|
@ -315,7 +314,7 @@ registerAction2(class extends Action2 {
|
|||
await extensionEnablementService.disableExtension({ id: done.id }, undefined);
|
||||
}
|
||||
if (res.confirmed) {
|
||||
await issueService.openReporter({ extensionId: done.id });
|
||||
await commandService.executeCommand('workbench.action.openIssueReporter', done.id);
|
||||
}
|
||||
}
|
||||
await bisectService.reset();
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { userAgent } from 'vs/base/common/platform';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IssueReporterData } from 'vs/platform/issue/common/issue';
|
||||
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
|
||||
|
||||
export class WebIssueService implements IWorkbenchIssueService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
) { }
|
||||
|
||||
//TODO @TylerLeonhardt @Tyriar to implement a process explorer for the web
|
||||
async openProcessExplorer(): Promise<void> {
|
||||
console.error('openProcessExplorer is not implemented in web');
|
||||
}
|
||||
|
||||
async openReporter(options: Partial<IssueReporterData>): Promise<void> {
|
||||
const extensionId = options.extensionId;
|
||||
// If we don't have a extensionId, treat this as a Core issue
|
||||
if (!extensionId) {
|
||||
if (this.productService.reportIssueUrl) {
|
||||
const uri = this.getIssueUriFromStaticContent(this.productService.reportIssueUrl);
|
||||
dom.windowOpenNoOpener(uri);
|
||||
return;
|
||||
}
|
||||
throw new Error(`No issue reporting URL configured for ${this.productService.nameLong}.`);
|
||||
}
|
||||
|
||||
const selectedExtension = this.extensionService.extensions.filter(ext => ext.identifier.value === options.extensionId)[0];
|
||||
const extensionGitHubUrl = this.getExtensionGitHubUrl(selectedExtension);
|
||||
if (!extensionGitHubUrl) {
|
||||
throw new Error(`Unable to find issue reporting url for ${extensionId}`);
|
||||
}
|
||||
|
||||
const uri = this.getIssueUriFromStaticContent(`${extensionGitHubUrl}/issues/new`, selectedExtension);
|
||||
dom.windowOpenNoOpener(uri);
|
||||
}
|
||||
|
||||
private getExtensionGitHubUrl(extension: IExtensionDescription): string {
|
||||
if (extension.isBuiltin && this.productService.reportIssueUrl) {
|
||||
return normalizeGitHubUrl(this.productService.reportIssueUrl);
|
||||
}
|
||||
|
||||
let repositoryUrl = '';
|
||||
|
||||
const bugsUrl = extension?.bugs?.url;
|
||||
const extensionUrl = extension?.repository?.url;
|
||||
|
||||
// If given, try to match the extension's bug url
|
||||
if (bugsUrl && bugsUrl.match(/^https?:\/\/github\.com\/(.*)/)) {
|
||||
repositoryUrl = normalizeGitHubUrl(bugsUrl);
|
||||
} else if (extensionUrl && extensionUrl.match(/^https?:\/\/github\.com\/(.*)/)) {
|
||||
repositoryUrl = normalizeGitHubUrl(extensionUrl);
|
||||
}
|
||||
|
||||
return repositoryUrl;
|
||||
}
|
||||
|
||||
private getIssueUriFromStaticContent(baseUri: string, extension?: IExtensionDescription): string {
|
||||
const issueDescription = `ADD ISSUE DESCRIPTION HERE
|
||||
|
||||
Version: ${this.productService.version}
|
||||
Commit: ${this.productService.commit ?? 'unknown'}
|
||||
User Agent: ${userAgent ?? 'unknown'}
|
||||
Embedder: ${this.productService.embedderIdentifier ?? 'unknown'}
|
||||
${extension?.version ? `\nExtension version: ${extension.version}` : ''}
|
||||
<!-- generated by web issue reporter -->`;
|
||||
|
||||
return `${baseUri}?body=${encodeURIComponent(issueDescription)}&labels=web`;
|
||||
}
|
||||
}
|
|
@ -117,7 +117,6 @@ import 'vs/editor/common/services/treeViewsDndService';
|
|||
import 'vs/workbench/services/textMate/browser/textMateTokenizationFeature.contribution';
|
||||
import 'vs/workbench/services/userActivity/common/userActivityService';
|
||||
import 'vs/workbench/services/userActivity/browser/userActivityBrowser';
|
||||
import 'vs/workbench/services/issue/browser/issueTroubleshoot';
|
||||
import 'vs/workbench/services/editor/browser/editorPaneService';
|
||||
import 'vs/workbench/services/editor/common/customEditorLabelService';
|
||||
|
||||
|
|
|
@ -38,8 +38,6 @@ import 'vs/workbench/services/textfile/electron-sandbox/nativeTextFileService';
|
|||
import 'vs/workbench/services/dialogs/electron-sandbox/fileDialogService';
|
||||
import 'vs/workbench/services/workspaces/electron-sandbox/workspacesService';
|
||||
import 'vs/workbench/services/menubar/electron-sandbox/menubarService';
|
||||
import 'vs/workbench/services/issue/electron-sandbox/issueMainService';
|
||||
import 'vs/workbench/services/issue/electron-sandbox/issueService';
|
||||
import 'vs/workbench/services/update/electron-sandbox/updateService';
|
||||
import 'vs/workbench/services/url/electron-sandbox/urlService';
|
||||
import 'vs/workbench/services/lifecycle/electron-sandbox/lifecycleService';
|
||||
|
|
Loading…
Reference in a new issue