diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index e1507e0424f8f..3b1aeafd080fb 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -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' } ] } diff --git a/src/buildfile.js b/src/buildfile.js index f03de33fb3db5..9898cd44d1fc4 100644 --- a/src/buildfile.js +++ b/src/buildfile.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') ]; diff --git a/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts index ee123897dd148..62e2d9ff34108 100644 --- a/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -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', () => { diff --git a/src/vs/workbench/contrib/extensions/common/reportExtensionIssueAction.ts b/src/vs/workbench/contrib/extensions/common/reportExtensionIssueAction.ts index 7530446037472..34a1b543b5bd9 100644 --- a/src/vs/workbench/contrib/extensions/common/reportExtensionIssueAction.ts +++ b/src/vs/workbench/contrib/extensions/common/reportExtensionIssueAction.ts @@ -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 { diff --git a/src/vs/workbench/contrib/issue/browser/issue.contribution.ts b/src/vs/workbench/contrib/issue/browser/issue.contribution.ts index 28751d1c2c892..601380c33e277 100644 --- a/src/vs/workbench/contrib/issue/browser/issue.contribution.ts +++ b/src/vs/workbench/contrib/issue/browser/issue.contribution.ts @@ -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(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(ConfigurationExtensions.Configuration) + .registerConfiguration({ + properties: { + 'issueReporter.experimental.webReporter': { + type: 'boolean', + default: true, + description: 'Enable experimental issue reporter for web.', + }, + } + }); diff --git a/src/vs/code/browser/issue/issue.ts b/src/vs/workbench/contrib/issue/browser/issue.ts similarity index 99% rename from src/vs/code/browser/issue/issue.ts rename to src/vs/workbench/contrib/issue/browser/issue.ts index 2205e8471347b..8247a81f739b3 100644 --- a/src/vs/code/browser/issue/issue.ts +++ b/src/vs/workbench/contrib/issue/browser/issue.ts @@ -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; } diff --git a/src/vs/workbench/contrib/issue/browser/issueFormService.ts b/src/vs/workbench/contrib/issue/browser/issueFormService.ts new file mode 100644 index 0000000000000..a880e006d07c5 --- /dev/null +++ b/src/vs/workbench/contrib/issue/browser/issueFormService.ts @@ -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 { + 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 { + throw new Error('Method not implemented.'); + } + + stopTracing(): Promise { + throw new Error('Method not implemented.'); + } + getSystemStatus(): Promise { + throw new Error('Method not implemented.'); + } + $getSystemInfo(): Promise { + throw new Error('Method not implemented.'); + } + $getPerformanceInfo(): Promise { + throw new Error('Method not implemented.'); + } + $reloadWithExtensionsDisabled(): Promise { + throw new Error('Method not implemented.'); + } + $showConfirmCloseDialog(): Promise { + throw new Error('Method not implemented.'); + } + $showClipboardDialog(): Promise { + throw new Error('Method not implemented.'); + } + $getIssueReporterUri(extensionId: string): Promise { + throw new Error('Method not implemented.'); + } + $getIssueReporterData(extensionId: string): Promise { + throw new Error('Method not implemented.'); + } + $getIssueReporterTemplate(extensionId: string): Promise { + throw new Error('Method not implemented.'); + } + $getReporterStatus(extensionId: string, extensionName: string): Promise { + throw new Error('Method not implemented.'); + } + + async $sendReporterMenu(extensionId: string, extensionName: string): Promise { + 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 { + this.issueReporterWindow?.close(); + } +} diff --git a/src/vs/code/browser/issue/issueReporterModel.ts b/src/vs/workbench/contrib/issue/browser/issueReporterModel.ts similarity index 98% rename from src/vs/code/browser/issue/issueReporterModel.ts rename to src/vs/workbench/contrib/issue/browser/issueReporterModel.ts index 1541f98c812c4..74f5e9859ea93 100644 --- a/src/vs/code/browser/issue/issueReporterModel.ts +++ b/src/vs/workbench/contrib/issue/browser/issueReporterModel.ts @@ -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) { diff --git a/src/vs/code/browser/issue/issueReporterPage.ts b/src/vs/workbench/contrib/issue/browser/issueReporterPage.ts similarity index 99% rename from src/vs/code/browser/issue/issueReporterPage.ts rename to src/vs/workbench/contrib/issue/browser/issueReporterPage.ts index 7cf33372a9724..195857e0d4bc1 100644 --- a/src/vs/code/browser/issue/issueReporterPage.ts +++ b/src/vs/workbench/contrib/issue/browser/issueReporterPage.ts @@ -24,7 +24,7 @@ const reviewGuidanceLabel = localize( // intentionally not escaped because of it ); export default (): string => ` -
+
${reviewGuidanceLabel}
diff --git a/src/vs/code/browser/issue/issueReporterService.ts b/src/vs/workbench/contrib/issue/browser/issueReporterService.ts similarity index 80% rename from src/vs/code/browser/issue/issueReporterService.ts rename to src/vs/workbench/contrib/issue/browser/issueReporterService.ts index d724e028e9493..b89619f91bcc7 100644 --- a/src/vs/code/browser/issue/issueReporterService.ts +++ b/src/vs/workbench/contrib/issue/browser/issueReporterService.ts @@ -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('.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(); diff --git a/src/vs/workbench/contrib/issue/browser/issueService.ts b/src/vs/workbench/contrib/issue/browser/issueService.ts new file mode 100644 index 0000000000000..b67e59d7cbb66 --- /dev/null +++ b/src/vs/workbench/contrib/issue/browser/issueService.ts @@ -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 { + console.error('openProcessExplorer is not implemented in web'); + } + + async openReporter(options: Partial): Promise { + if (!this.configurationService.getValue('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}` : ''} +`; + + 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); diff --git a/src/vs/workbench/services/issue/browser/issueTroubleshoot.ts b/src/vs/workbench/contrib/issue/browser/issueTroubleshoot.ts similarity index 99% rename from src/vs/workbench/services/issue/browser/issueTroubleshoot.ts rename to src/vs/workbench/contrib/issue/browser/issueTroubleshoot.ts index 86f84f2af228e..f9f3104f8b3b5 100644 --- a/src/vs/workbench/services/issue/browser/issueTroubleshoot.ts +++ b/src/vs/workbench/contrib/issue/browser/issueTroubleshoot.ts @@ -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'; diff --git a/src/vs/workbench/contrib/issue/browser/media/issueReporter.css b/src/vs/workbench/contrib/issue/browser/media/issueReporter.css new file mode 100644 index 0000000000000..ba6e7b1ea9bd4 --- /dev/null +++ b/src/vs/workbench/contrib/issue/browser/media/issueReporter.css @@ -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); +} diff --git a/src/vs/workbench/contrib/issue/common/issue.contribution.ts b/src/vs/workbench/contrib/issue/common/issue.contribution.ts index 9e6ee979ac925..8e4d779571031 100644 --- a/src/vs/workbench/contrib/issue/common/issue.contribution.ts +++ b/src/vs/workbench/contrib/issue/common/issue.contribution.ts @@ -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'; diff --git a/src/vs/workbench/services/issue/common/issue.ts b/src/vs/workbench/contrib/issue/common/issue.ts similarity index 100% rename from src/vs/workbench/services/issue/common/issue.ts rename to src/vs/workbench/contrib/issue/common/issue.ts diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts index d6c76d7fbd9be..3b86046d12f43 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts @@ -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 diff --git a/src/vs/workbench/services/issue/electron-sandbox/issueMainService.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueMainService.ts similarity index 100% rename from src/vs/workbench/services/issue/electron-sandbox/issueMainService.ts rename to src/vs/workbench/contrib/issue/electron-sandbox/issueMainService.ts diff --git a/src/vs/code/electron-sandbox/issue/issueReporter-dev.html b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.html similarity index 79% rename from src/vs/code/electron-sandbox/issue/issueReporter-dev.html rename to src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.html index a303a97d475a7..455e823692a94 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporter-dev.html +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter-dev.html @@ -39,8 +39,8 @@ - - - + + + diff --git a/src/vs/code/electron-sandbox/issue/issueReporter.html b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.html similarity index 100% rename from src/vs/code/electron-sandbox/issue/issueReporter.html rename to src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.html diff --git a/src/vs/code/electron-sandbox/issue/issueReporter.js b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.js similarity index 83% rename from src/vs/code/electron-sandbox/issue/issueReporter.js rename to src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.js index b486c703057b6..cad5ddba090d4 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporter.js +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporter.js @@ -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: ( diff --git a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterMain.ts similarity index 93% rename from src/vs/code/electron-sandbox/issue/issueReporterMain.ts rename to src/vs/workbench/contrib/issue/electron-sandbox/issueReporterMain.ts index c72367bff1a72..05f002de5320e 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterMain.ts @@ -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) { diff --git a/src/vs/code/electron-sandbox/issue/issueReporterService.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService.ts similarity index 99% rename from src/vs/code/electron-sandbox/issue/issueReporterService.ts rename to src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService.ts index a295a881487b9..873d3b92a3a1a 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterService.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService.ts @@ -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'; diff --git a/src/vs/code/electron-sandbox/issue/issueReporterService2.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService2.ts similarity index 99% rename from src/vs/code/electron-sandbox/issue/issueReporterService2.ts rename to src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService2.ts index 51bdfe923b813..0c6477b7bfec8 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterService2.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService2.ts @@ -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 diff --git a/src/vs/workbench/services/issue/electron-sandbox/issueService.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts similarity index 99% rename from src/vs/workbench/services/issue/electron-sandbox/issueService.ts rename to src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts index 410ea55fdfdcc..3b5c8d26ed6c7 100644 --- a/src/vs/workbench/services/issue/electron-sandbox/issueService.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts @@ -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'; diff --git a/src/vs/code/electron-sandbox/issue/media/issueReporter.css b/src/vs/workbench/contrib/issue/electron-sandbox/media/issueReporter.css similarity index 100% rename from src/vs/code/electron-sandbox/issue/media/issueReporter.css rename to src/vs/workbench/contrib/issue/electron-sandbox/media/issueReporter.css diff --git a/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts b/src/vs/workbench/contrib/issue/issue/testReporterModel.test.ts similarity index 98% rename from src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts rename to src/vs/workbench/contrib/issue/issue/testReporterModel.test.ts index 1708f3a07a1a6..d86022dec6a81 100644 --- a/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts +++ b/src/vs/workbench/contrib/issue/issue/testReporterModel.test.ts @@ -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'; diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 632ee6ad4e380..b5f25b45e63d4 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -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'; diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts index caf3def470043..d339e68cfe892 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts @@ -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(); diff --git a/src/vs/workbench/services/issue/browser/issueService.ts b/src/vs/workbench/services/issue/browser/issueService.ts deleted file mode 100644 index 81ddf091f652a..0000000000000 --- a/src/vs/workbench/services/issue/browser/issueService.ts +++ /dev/null @@ -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 { - console.error('openProcessExplorer is not implemented in web'); - } - - async openReporter(options: Partial): Promise { - 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}` : ''} -`; - - return `${baseUri}?body=${encodeURIComponent(issueDescription)}&labels=web`; - } -} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 351f7cc5cda1b..a4e3fa69d6ec5 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -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'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 3dd96d43b7b2d..c4b6e9c27d032 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -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';