@codingame/monaco-vscode-issue-service-override 33.0.7 → 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.
- package/index.js +10 -1
- package/package.json +3 -3
- package/vscode/src/vs/workbench/contrib/issue/browser/baseIssueReporterService.js +38 -38
- package/vscode/src/vs/workbench/contrib/issue/browser/githubUploadService.d.ts +14 -0
- package/vscode/src/vs/workbench/contrib/issue/browser/githubUploadService.js +12 -0
- package/vscode/src/vs/workbench/contrib/issue/browser/issue.contribution.js +2 -1
- package/vscode/src/vs/workbench/contrib/issue/browser/issueFormService.d.ts +32 -7
- package/vscode/src/vs/workbench/contrib/issue/browser/issueFormService.js +348 -11
- package/vscode/src/vs/workbench/contrib/issue/browser/issueReporterModel.d.ts +3 -2
- package/vscode/src/vs/workbench/contrib/issue/browser/issueReporterModel.js +28 -29
- package/vscode/src/vs/workbench/contrib/issue/browser/issueReporterPage.js +32 -32
- package/vscode/src/vs/workbench/contrib/issue/browser/issueReporterService.js +1 -1
- package/vscode/src/vs/workbench/contrib/issue/browser/issueService.js +3 -3
- package/vscode/src/vs/workbench/contrib/issue/browser/issueTroubleshoot.js +23 -23
- package/vscode/src/vs/workbench/contrib/issue/browser/screenshotService.d.ts +9 -0
- package/vscode/src/vs/workbench/contrib/issue/browser/screenshotService.js +9 -0
- package/vscode/src/vs/workbench/contrib/issue/common/issue.contribution.js +2 -2
- package/vscode/src/vs/workbench/contrib/issue/common/issue.d.ts +32 -2
- package/vscode/src/vs/workbench/contrib/issue/common/issue.js +1 -0
|
@@ -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
|
-
|
|
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` : `\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
|
-
|
|
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(
|
|
501
|
+
label: ( localize(10833, "&&Yes")),
|
|
165
502
|
run: () => {
|
|
166
503
|
this.closeReporter();
|
|
167
504
|
this.issueReporterWindow = null;
|
|
168
505
|
}
|
|
169
506
|
}, {
|
|
170
|
-
label: ( localize(
|
|
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
|
-
|
|
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(
|
|
521
|
+
label: ( localize(10836, "&&OK")),
|
|
185
522
|
run: () => {
|
|
186
523
|
result = true;
|
|
187
524
|
}
|
|
188
525
|
}, {
|
|
189
|
-
label: ( localize(
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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 (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
if (!this._data.enabledNonThemeExtesions || this._data.enabledNonThemeExtesions.length === 0) {
|
|
196
|
+
if (!this._data.numberOfThemeExtesions) {
|
|
197
|
+
return "Extensions: none";
|
|
198
|
+
}
|
|
203
199
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
|