@codingame/monaco-vscode-issue-service-override 33.0.9 → 34.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,27 +5,41 @@ import { createElement } from '@codingame/monaco-vscode-api/vscode/vs/base/brows
5
5
  import { safeSetInnerHtml } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/domSanitize';
6
6
  import { createStyleSheet } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/domStylesheets';
7
7
  import { Menu, getMenuWidgetCSS, unthemedMenuStyles } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/ui/menu/menu';
8
- import { DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
8
+ import { Disposable, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
9
9
  import { isWindows, isLinux } from '@codingame/monaco-vscode-api/vscode/vs/base/common/platform';
10
10
  import Severity from '@codingame/monaco-vscode-api/vscode/vs/base/common/severity';
11
11
  import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
12
12
  import { MenuId } from '@codingame/monaco-vscode-api/vscode/vs/platform/actions/common/actions';
13
13
  import { IMenuService } from '@codingame/monaco-vscode-api/vscode/vs/platform/actions/common/actions.service';
14
+ import { IClipboardService } from '@codingame/monaco-vscode-api/vscode/vs/platform/clipboard/common/clipboardService.service';
14
15
  import { IContextKeyService } from '@codingame/monaco-vscode-api/vscode/vs/platform/contextkey/common/contextkey.service';
15
16
  import { IDialogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/dialogs/common/dialogs.service';
16
17
  import { ExtensionIdentifierSet, ExtensionIdentifier } from '@codingame/monaco-vscode-api/vscode/vs/platform/extensions/common/extensions';
17
18
  import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
18
19
  import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service';
20
+ import { IOpenerService } from '@codingame/monaco-vscode-api/vscode/vs/platform/opener/common/opener.service';
19
21
  import product from '@codingame/monaco-vscode-api/vscode/vs/platform/product/common/product';
20
22
  import { AuxiliaryWindowMode } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService';
21
23
  import { IAuxiliaryWindowService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.service';
22
24
  import { IHostService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/host/browser/host.service';
25
+ import { IssueSource } from '../common/issue.js';
26
+ import { normalizeGitHubUrl } from '../common/issueReporterUtil.js';
23
27
  import BaseHtml from './issueReporterPage.js';
24
28
  import { IssueWebReporter } from './issueReporterService.js';
29
+ import { IGitHubUploadService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/issue/browser/githubUploadService.service';
30
+ import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service';
31
+ import { IEditorService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/editor/common/editorService.service';
32
+ import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
33
+ import { LRUCache } from '@codingame/monaco-vscode-api/vscode/vs/base/common/map';
34
+ import { hash } from '@codingame/monaco-vscode-api/vscode/vs/base/common/hash';
35
+ import { decodeBase64 } from '@codingame/monaco-vscode-api/vscode/vs/base/common/buffer';
25
36
  import * as issueReporter from './media/issueReporter.css';
26
37
 
27
38
  registerCss(issueReporter);
28
- let IssueFormService = class IssueFormService {
39
+ const MAX_URL_LENGTH = 7500;
40
+ const GENERATED_BY_ISSUE_REPORTER_MARKER = "<!-- generated by issue reporter -->";
41
+ const ISSUE_DATA_ATTACHMENT_NAME = "issue-data.md";
42
+ let IssueFormService = class IssueFormService extends Disposable {
29
43
  constructor(
30
44
  instantiationService,
31
45
  auxiliaryWindowService,
@@ -33,8 +47,14 @@ let IssueFormService = class IssueFormService {
33
47
  contextKeyService,
34
48
  logService,
35
49
  dialogService,
36
- hostService
50
+ hostService,
51
+ openerService,
52
+ fileService,
53
+ githubUploadService,
54
+ editorService,
55
+ clipboardService
37
56
  ) {
57
+ super();
38
58
  this.instantiationService = instantiationService;
39
59
  this.auxiliaryWindowService = auxiliaryWindowService;
40
60
  this.menuService = menuService;
@@ -42,16 +62,333 @@ let IssueFormService = class IssueFormService {
42
62
  this.logService = logService;
43
63
  this.dialogService = dialogService;
44
64
  this.hostService = hostService;
65
+ this.openerService = openerService;
66
+ this.fileService = fileService;
67
+ this.githubUploadService = githubUploadService;
68
+ this.editorService = editorService;
69
+ this.clipboardService = clipboardService;
45
70
  this.issueReporterWindow = null;
46
71
  this.extensionIdentifierSet = ( new ExtensionIdentifierSet());
47
72
  this.arch = "";
48
73
  this.release = "";
49
74
  this.type = "";
75
+ this.uploadCache = ( new LRUCache(32));
50
76
  }
51
77
  async openReporter(data) {
52
78
  if (this.hasToReload(data)) {
53
79
  return;
54
80
  }
81
+ return this.openAuxIssueReporterLegacy(data);
82
+ }
83
+ async submitIssue(host, data, title, body) {
84
+ const screenshots = host.getScreenshots();
85
+ const recordings = host.getRecordings();
86
+ const issueTarget = this.getIssueTarget(data);
87
+ if (!issueTarget?.url) {
88
+ return false;
89
+ }
90
+ if (issueTarget.external) {
91
+ return this.openerService.open(issueTarget.url, {
92
+ openExternal: true
93
+ });
94
+ }
95
+ const gitHubDetails = this.parseGitHubUrl(issueTarget.url);
96
+ let repoId;
97
+ const resolveRepoId = async () => {
98
+ if (!gitHubDetails) {
99
+ return undefined;
100
+ }
101
+ repoId ??= await this.githubUploadService.resolveRepositoryId(gitHubDetails.owner, gitHubDetails.repositoryName, data.githubAccessToken);
102
+ return repoId;
103
+ };
104
+ let mediaMarkdown = "";
105
+ const hasAttachments = screenshots.length > 0 || recordings.length > 0;
106
+ if (hasAttachments && data.githubAccessToken && gitHubDetails) {
107
+ host.setUploading(true);
108
+ try {
109
+ const filesToProcess = [];
110
+ for (let i = 0; i < screenshots.length; i++) {
111
+ const dataUrl = screenshots[i].annotatedDataUrl ?? screenshots[i].dataUrl;
112
+ const bytes = this.dataUrlToBytes(dataUrl);
113
+ if (bytes) {
114
+ const isJpeg = dataUrl.startsWith("data:image/jpeg");
115
+ const extension = isJpeg ? "jpg" : "png";
116
+ const contentType = isJpeg ? "image/jpeg" : "image/png";
117
+ filesToProcess.push({
118
+ key: `screenshot:${hash(dataUrl)}`,
119
+ name: `screenshot-${i + 1}.${extension}`,
120
+ bytes,
121
+ contentType
122
+ });
123
+ }
124
+ }
125
+ for (let i = 0; i < recordings.length; i++) {
126
+ const rec = recordings[i];
127
+ const fileContent = await this.fileService.readFile(URI.file(rec.filePath));
128
+ const ext = rec.filePath.endsWith(".mp4") ? "mp4" : "webm";
129
+ const contentType = ext === "mp4" ? "video/mp4" : "video/webm";
130
+ filesToProcess.push({
131
+ key: `recording:${rec.filePath}`,
132
+ name: `recording-${i + 1}.${ext}`,
133
+ bytes: fileContent.value.buffer,
134
+ contentType
135
+ });
136
+ }
137
+ if (filesToProcess.length > 0) {
138
+ for (let i = 0; i < filesToProcess.length; i++) {
139
+ host.setAttachmentUploadState(i, "pending");
140
+ }
141
+ const uploadResults = [];
142
+ for (let i = 0; i < filesToProcess.length; i++) {
143
+ const file = filesToProcess[i];
144
+ const cached = this.uploadCache.get(file.key);
145
+ if (cached) {
146
+ uploadResults.push(cached);
147
+ host.setAttachmentUploadState(i, "done");
148
+ continue;
149
+ }
150
+ const resolvedRepoId = await resolveRepoId();
151
+ if (!resolvedRepoId) {
152
+ throw ( new Error("No GitHub repository resolved for attachment upload."));
153
+ }
154
+ host.setAttachmentUploadState(i, "uploading");
155
+ const [result] = await this.githubUploadService.uploadViaMobileApi(data.githubAccessToken, resolvedRepoId, [file]);
156
+ if (!result) {
157
+ throw ( new Error(`Upload returned no result for ${file.name}.`));
158
+ }
159
+ this.uploadCache.set(file.key, result);
160
+ uploadResults.push(result);
161
+ host.setAttachmentUploadState(i, "done");
162
+ }
163
+ mediaMarkdown = `\n\n### ${( localize(10827, "Attachments"))}\n\n`;
164
+ for (const r of uploadResults) {
165
+ mediaMarkdown += r.contentType.startsWith("video/") ? `${r.assetUrl}\n\n` : `![${r.fileName}](${r.assetUrl})\n\n`;
166
+ }
167
+ }
168
+ } catch (err) {
169
+ this.logService.error("[IssueFormService] Upload failed:", err);
170
+ mediaMarkdown = `\n\n### ${( localize(10827, "Attachments"))}\n\n> ${( localize(10828, "Upload failed. Please drag and drop attachments manually."))}\n\n`;
171
+ } finally {
172
+ host.setUploading(false);
173
+ }
174
+ }
175
+ const issueBody = body + mediaMarkdown;
176
+ const baseUrl = this.getIssueUrlWithTitle(title, issueTarget.url);
177
+ let previewBody = issueBody;
178
+ let url = this.createIssuePreviewUrl(baseUrl, previewBody, gitHubDetails, data.issueSource);
179
+ if (url.length > MAX_URL_LENGTH && data.githubAccessToken && gitHubDetails) {
180
+ const shortenedBody = await this.tryCreateBodyWithIssueDataAttachment(
181
+ host,
182
+ issueBody,
183
+ baseUrl,
184
+ gitHubDetails,
185
+ data.issueSource,
186
+ data.githubAccessToken,
187
+ resolveRepoId
188
+ );
189
+ if (shortenedBody) {
190
+ previewBody = shortenedBody;
191
+ url = this.createIssuePreviewUrl(baseUrl, previewBody, gitHubDetails, data.issueSource);
192
+ }
193
+ }
194
+ if (url.length > MAX_URL_LENGTH) {
195
+ const shouldWrite = await this.showClipboardDialog();
196
+ if (!shouldWrite) {
197
+ return false;
198
+ }
199
+ try {
200
+ await this.clipboardService.writeText(issueBody);
201
+ } catch (error) {
202
+ this.logService.error("Writing issue data to clipboard failed", error);
203
+ return false;
204
+ }
205
+ url = this.createIssuePreviewUrl(baseUrl, ( localize(
206
+ 10829,
207
+ "We have written the needed data into your clipboard because it was too large to send. Please paste."
208
+ )), gitHubDetails, data.issueSource);
209
+ }
210
+ const uri = ( URI.parse(url));
211
+ const skipValidation = uri.scheme === "https" && uri.authority === "github.com";
212
+ return this.openerService.open(url, {
213
+ openExternal: true,
214
+ skipValidation
215
+ });
216
+ }
217
+ async tryCreateBodyWithIssueDataAttachment(
218
+ host,
219
+ issueBody,
220
+ baseUrl,
221
+ gitHubDetails,
222
+ issueSource,
223
+ githubAccessToken,
224
+ resolveRepoId
225
+ ) {
226
+ const extracted = this.extractIssueData(issueBody);
227
+ if (!extracted) {
228
+ return undefined;
229
+ }
230
+ host.setUploading(true);
231
+ try {
232
+ const repoId = await resolveRepoId();
233
+ if (!repoId) {
234
+ return undefined;
235
+ }
236
+ const result = await this.uploadIssueDataFile(githubAccessToken, repoId, extracted.fileContent);
237
+ const bodyWithLink = this.createBodyWithIssueDataLink(extracted.body, result.assetUrl);
238
+ if (this.createIssuePreviewUrl(baseUrl, bodyWithLink, gitHubDetails, issueSource).length > MAX_URL_LENGTH) {
239
+ return undefined;
240
+ }
241
+ return bodyWithLink;
242
+ } catch (error) {
243
+ this.logService.error("Uploading issue data attachment failed", error);
244
+ return undefined;
245
+ } finally {
246
+ host.setUploading(false);
247
+ }
248
+ }
249
+ async uploadIssueDataFile(githubAccessToken, repoId, fileContent) {
250
+ const key = `${ISSUE_DATA_ATTACHMENT_NAME}:${hash(fileContent)}`;
251
+ const cached = this.uploadCache.get(key);
252
+ if (cached) {
253
+ return cached;
254
+ }
255
+ const file = {
256
+ key,
257
+ name: ISSUE_DATA_ATTACHMENT_NAME,
258
+ bytes: ( new TextEncoder()).encode(fileContent),
259
+ contentType: "text/plain"
260
+ };
261
+ const [result] = await this.githubUploadService.uploadViaMobileApi(githubAccessToken, repoId, [file]);
262
+ if (!result) {
263
+ throw ( new Error("Issue data upload did not return a result."));
264
+ }
265
+ this.uploadCache.set(key, result);
266
+ return result;
267
+ }
268
+ extractIssueData(issueBody) {
269
+ const detailsBlocks = [];
270
+ const body = issueBody.replace(/\n*<details\b[\s\S]*?<\/details>\n*/gi, match => {
271
+ detailsBlocks.push(match.trim());
272
+ return "\n\n";
273
+ }).replace(/\n{3,}/g, "\n\n").trimEnd();
274
+ if (!detailsBlocks.length) {
275
+ return undefined;
276
+ }
277
+ return {
278
+ body,
279
+ fileContent: `# ${( localize(10830, "Issue Data"))}\n\n${detailsBlocks.join("\n\n")}\n`
280
+ };
281
+ }
282
+ createBodyWithIssueDataLink(body, issueDataUrl) {
283
+ const attachmentMarkdown = `\n\n### ${( localize(10831, "Additional Issue Data"))}\n\n[${ISSUE_DATA_ATTACHMENT_NAME}](${issueDataUrl})`;
284
+ const markerIndex = body.indexOf(GENERATED_BY_ISSUE_REPORTER_MARKER);
285
+ if (markerIndex === -1) {
286
+ return `${body.trimEnd()}${attachmentMarkdown}\n`;
287
+ }
288
+ return `${body.slice(0, markerIndex).trimEnd()}${attachmentMarkdown}\n\n${body.slice(markerIndex).trimStart()}`;
289
+ }
290
+ createIssuePreviewUrl(baseUrl, body, gitHubDetails, issueSource) {
291
+ const url = `${baseUrl}&body=${encodeURIComponent(body)}`;
292
+ return this.addTemplateToUrl(url, gitHubDetails?.owner, gitHubDetails?.repositoryName, issueSource);
293
+ }
294
+ getIssueTarget(data) {
295
+ const selectedExtension = this.getSelectedExtension(data);
296
+ if (data.issueSource === IssueSource.Extension && selectedExtension) {
297
+ const extensionUrl = this.getExtensionIssueUrl(selectedExtension);
298
+ if (!extensionUrl) {
299
+ return undefined;
300
+ }
301
+ return {
302
+ url: extensionUrl,
303
+ external: !this.isGitHubUrl(extensionUrl)
304
+ };
305
+ }
306
+ if (data.issueSource === IssueSource.Marketplace) {
307
+ const marketplaceIssueUrl = product.reportMarketplaceIssueUrl ?? product.reportIssueUrl;
308
+ return marketplaceIssueUrl ? {
309
+ url: marketplaceIssueUrl,
310
+ external: false
311
+ } : undefined;
312
+ }
313
+ if (data.uri) {
314
+ const url = ( URI.revive(data.uri).toString());
315
+ return {
316
+ url,
317
+ external: !this.isGitHubUrl(url)
318
+ };
319
+ }
320
+ if (data.privateUri) {
321
+ const url = ( URI.revive(data.privateUri).toString());
322
+ return {
323
+ url,
324
+ external: !this.isGitHubUrl(url)
325
+ };
326
+ }
327
+ return product.reportIssueUrl ? {
328
+ url: product.reportIssueUrl,
329
+ external: false
330
+ } : undefined;
331
+ }
332
+ getSelectedExtension(data) {
333
+ return data.extensionId ? data.enabledExtensions.find(ext => ext.id.toLowerCase() === data.extensionId?.toLowerCase()) : undefined;
334
+ }
335
+ getExtensionIssueUrl(extension) {
336
+ if (extension.uri) {
337
+ return ( URI.revive(extension.uri).toString());
338
+ }
339
+ if (extension.bugsUrl && /^https?:\/\/github\.com\/([^\/]*)\/([^\/]*)\/?(\/issues)?\/?$/.test(extension.bugsUrl)) {
340
+ return `${normalizeGitHubUrl(extension.bugsUrl)}/issues/new`;
341
+ }
342
+ if (extension.repositoryUrl && /^https?:\/\/github\.com\/([^\/]*)\/([^\/]*)\/?$/.test(extension.repositoryUrl)) {
343
+ return `${normalizeGitHubUrl(extension.repositoryUrl)}/issues/new`;
344
+ }
345
+ return extension.bugsUrl || extension.repositoryUrl;
346
+ }
347
+ isGitHubUrl(url) {
348
+ return /^https?:\/\/github\.com\//i.test(url);
349
+ }
350
+ parseGitHubUrl(url) {
351
+ const match = /^https?:\/\/github\.com\/([^\/?#]+)\/([^\/?#]+).*/i.exec(url);
352
+ if (!match) {
353
+ return undefined;
354
+ }
355
+ return {
356
+ owner: match[1],
357
+ repositoryName: match[2]
358
+ };
359
+ }
360
+ getIssueUrlWithTitle(issueTitle, issueUrl) {
361
+ if (this.isGitHubUrl(issueUrl) && !/\/issues\/new(?:[?#].*)?$/i.test(issueUrl)) {
362
+ issueUrl = `${normalizeGitHubUrl(issueUrl)}/issues/new`;
363
+ }
364
+ const queryStringPrefix = issueUrl.indexOf("?") === -1 ? "?" : "&";
365
+ return `${issueUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
366
+ }
367
+ addTemplateToUrl(baseUrl, owner, repositoryName, issueSource) {
368
+ const needsTemplate = issueSource === IssueSource.VSCode || (owner?.toLowerCase() === "microsoft" && repositoryName?.toLowerCase() === "vscode");
369
+ if (!needsTemplate) {
370
+ return baseUrl;
371
+ }
372
+ try {
373
+ const url = ( new URL(baseUrl));
374
+ url.searchParams.set("template", "bug_report.md");
375
+ return ( url.toString());
376
+ } catch {
377
+ return `${baseUrl}&template=bug_report.md`;
378
+ }
379
+ }
380
+ dataUrlToBytes(dataUrl) {
381
+ const commaIndex = dataUrl.indexOf(",");
382
+ if (commaIndex === -1) {
383
+ return undefined;
384
+ }
385
+ try {
386
+ return decodeBase64(dataUrl.substring(commaIndex + 1)).buffer;
387
+ } catch {
388
+ return undefined;
389
+ }
390
+ }
391
+ async openAuxIssueReporterLegacy(data) {
55
392
  await this.openAuxIssueReporter(data);
56
393
  if (this.issueReporterWindow) {
57
394
  const issueReporter = this.instantiationService.createInstance(IssueWebReporter, false, data, {
@@ -67,7 +404,7 @@ let IssueFormService = class IssueFormService {
67
404
  width: 700,
68
405
  height: 800
69
406
  };
70
- if (bounds && bounds.x && bounds.y) {
407
+ if (bounds && typeof bounds.x === "number" && typeof bounds.y === "number") {
71
408
  const centerX = bounds.x + bounds.width / 2;
72
409
  const centerY = bounds.y + bounds.height / 2;
73
410
  issueReporterBounds = {
@@ -157,17 +494,17 @@ let IssueFormService = class IssueFormService {
157
494
  await this.dialogService.prompt({
158
495
  type: Severity.Warning,
159
496
  message: ( localize(
160
- 10663,
497
+ 10832,
161
498
  "Your input will not be saved. Are you sure you want to close this window?"
162
499
  )),
163
500
  buttons: [{
164
- label: ( localize(10664, "&&Yes")),
501
+ label: ( localize(10833, "&&Yes")),
165
502
  run: () => {
166
503
  this.closeReporter();
167
504
  this.issueReporterWindow = null;
168
505
  }
169
506
  }, {
170
- label: ( localize(10665, "Cancel")),
507
+ label: ( localize(10834, "Cancel")),
171
508
  run: () => {}
172
509
  }]
173
510
  });
@@ -177,16 +514,16 @@ let IssueFormService = class IssueFormService {
177
514
  await this.dialogService.prompt({
178
515
  type: Severity.Warning,
179
516
  message: ( localize(
180
- 10666,
517
+ 10835,
181
518
  "There is too much data to send to GitHub directly. The data will be copied to the clipboard, please paste it into the GitHub issue page that is opened."
182
519
  )),
183
520
  buttons: [{
184
- label: ( localize(10667, "&&OK")),
521
+ label: ( localize(10836, "&&OK")),
185
522
  run: () => {
186
523
  result = true;
187
524
  }
188
525
  }, {
189
- label: ( localize(10665, "Cancel")),
526
+ label: ( localize(10834, "Cancel")),
190
527
  run: () => {
191
528
  result = false;
192
529
  }
@@ -207,6 +544,6 @@ let IssueFormService = class IssueFormService {
207
544
  return false;
208
545
  }
209
546
  };
210
- IssueFormService = ( __decorate([( __param(0, IInstantiationService)), ( __param(1, IAuxiliaryWindowService)), ( __param(2, IMenuService)), ( __param(3, IContextKeyService)), ( __param(4, ILogService)), ( __param(5, IDialogService)), ( __param(6, IHostService))], IssueFormService));
547
+ IssueFormService = ( __decorate([( __param(0, IInstantiationService)), ( __param(1, IAuxiliaryWindowService)), ( __param(2, IMenuService)), ( __param(3, IContextKeyService)), ( __param(4, ILogService)), ( __param(5, IDialogService)), ( __param(6, IHostService)), ( __param(7, IOpenerService)), ( __param(8, IFileService)), ( __param(9, IGitHubUploadService)), ( __param(10, IEditorService)), ( __param(11, IClipboardService))], IssueFormService));
211
548
 
212
549
  export { IssueFormService };
@@ -1,11 +1,12 @@
1
1
  import { SystemInfo } from "@codingame/monaco-vscode-api/vscode/vs/platform/diagnostics/common/diagnostics";
2
- import { ISettingSearchResult, IssueReporterExtensionData, IssueType } from "../common/issue.js";
2
+ import { ISettingSearchResult, IssueReporterExtensionData, IssueSource, IssueType } from "../common/issue.js";
3
3
  interface VersionInfo {
4
4
  vscodeVersion: string;
5
5
  os: string;
6
6
  }
7
7
  export interface IssueReporterData {
8
8
  issueType: IssueType;
9
+ issueSource?: IssueSource;
9
10
  issueDescription?: string;
10
11
  issueTitle?: string;
11
12
  extensionData?: string;
@@ -33,7 +34,7 @@ export interface IssueReporterData {
33
34
  filterResultCount?: number;
34
35
  experimentInfo?: string;
35
36
  restrictedMode?: boolean;
36
- isUnsupported?: boolean;
37
+ isInstallationPure?: boolean;
37
38
  isSessionsWindow?: boolean;
38
39
  }
39
40
  export declare class IssueReporterModel {
@@ -39,7 +39,7 @@ class IssueReporterModel {
39
39
  if (this._data.restrictedMode) {
40
40
  modes.push("Restricted");
41
41
  }
42
- if (this._data.isUnsupported) {
42
+ if (this._data.isInstallationPure === false) {
43
43
  modes.push("Unsupported");
44
44
  }
45
45
  return `
@@ -87,17 +87,11 @@ ${this.getInfos()}
87
87
  if (this._data.fileOnMarketplace) {
88
88
  return info;
89
89
  }
90
- const isBugOrPerformanceIssue = this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue;
91
- if (isBugOrPerformanceIssue) {
92
- if (this._data.includeExtensionData && this._data.extensionData) {
93
- info += this.getExtensionData();
94
- }
95
- if (this._data.includeSystemInfo && this._data.systemInfo) {
96
- info += this.generateSystemInfoMd();
97
- }
98
- if (this._data.includeSystemInfo && this._data.systemInfoWeb) {
99
- info += "System Info: " + this._data.systemInfoWeb;
100
- }
90
+ if (this._data.includeExtensionData && this._data.extensionData) {
91
+ info += this.getExtensionData();
92
+ }
93
+ if (this._data.includeSystemInfo && this._data.systemInfo) {
94
+ info += this.generateSystemInfoMd();
101
95
  }
102
96
  if (this._data.issueType === IssueType.PerformanceIssue) {
103
97
  if (this._data.includeProcessInfo) {
@@ -107,13 +101,11 @@ ${this.getInfos()}
107
101
  info += this.generateWorkspaceInfoMd();
108
102
  }
109
103
  }
110
- if (isBugOrPerformanceIssue) {
111
- if (!this._data.fileOnExtension && this._data.includeExtensions) {
112
- info += this.generateExtensionsMd();
113
- }
114
- if (this._data.includeExperiments && this._data.experimentInfo) {
115
- info += this.generateExperimentsInfoMd();
116
- }
104
+ if (!this._data.fileOnExtension && this._data.includeExtensions) {
105
+ info += this.generateExtensionsMd();
106
+ }
107
+ if (this._data.includeExperiments && this._data.experimentInfo) {
108
+ info += this.generateExperimentsInfoMd();
117
109
  }
118
110
  return info;
119
111
  }
@@ -135,6 +127,9 @@ ${this.getInfos()}
135
127
  |Process Argv|${this._data.systemInfo.processArgs.replace(/\\/g, "\\\\")}|
136
128
  |Screen Reader|${this._data.systemInfo.screenReader}|
137
129
  |VM|${this._data.systemInfo.vmHint}|`;
130
+ if (this._data.systemInfoWeb) {
131
+ md += `\n|User Agent|${this._data.systemInfoWeb}|`;
132
+ }
138
133
  if (this._data.systemInfo.linuxEnv) {
139
134
  md += `\n|DESKTOP_SESSION|${this._data.systemInfo.linuxEnv.desktopSession}|
140
135
  |XDG_CURRENT_DESKTOP|${this._data.systemInfo.linuxEnv.xdgCurrentDesktop}|
@@ -197,22 +192,26 @@ ${this._data.experimentInfo}
197
192
  if (this._data.extensionsDisabled) {
198
193
  return "Extensions disabled";
199
194
  }
200
- const themeExclusionStr = this._data.numberOfThemeExtesions ? `\n(${this._data.numberOfThemeExtesions} theme extensions excluded)` : "";
201
- if (!this._data.enabledNonThemeExtesions) {
202
- return "Extensions: none" + themeExclusionStr;
195
+ if (!this._data.enabledNonThemeExtesions || this._data.enabledNonThemeExtesions.length === 0) {
196
+ if (!this._data.numberOfThemeExtesions) {
197
+ return "Extensions: none";
198
+ }
203
199
  }
204
- const tableHeader = `Extension|Author (truncated)|Version
205
- ---|---|---`;
206
- const table = ( this._data.enabledNonThemeExtesions.map(e => {
207
- return `${e.name}|${e.publisher?.substr(0, 3) ?? "N/A"}|${e.version}`;
208
- })).join("\n");
209
- return `<details><summary>Extensions (${this._data.enabledNonThemeExtesions.length})</summary>
200
+ let md = "";
201
+ const tableHeader = `Name|Identifier|Author|Version
202
+ ---|---|---|---`;
203
+ if (this._data.enabledNonThemeExtesions && this._data.enabledNonThemeExtesions.length > 0) {
204
+ const table = ( this._data.enabledNonThemeExtesions.map(e => {
205
+ return `${e.displayName || e.name}|${e.id}|${e.publisher ?? "N/A"}|${e.version}`;
206
+ })).join("\n");
207
+ md += `<details><summary>Extensions (${this._data.enabledNonThemeExtesions.length})</summary>
210
208
 
211
209
  ${tableHeader}
212
210
  ${table}
213
- ${themeExclusionStr}
214
211
 
215
212
  </details>`;
213
+ }
214
+ return md;
216
215
  }
217
216
  }
218
217