feedback-vos 1.0.0 → 1.0.2
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/LICENSE +22 -22
- package/README.md +103 -309
- package/dist/index.d.mts +5 -9
- package/dist/index.d.ts +5 -9
- package/dist/index.js +342 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +342 -83
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +103 -98
- package/package.json +59 -59
package/dist/index.mjs
CHANGED
|
@@ -54,7 +54,7 @@ function ScreenshotButton({
|
|
|
54
54
|
"button",
|
|
55
55
|
{
|
|
56
56
|
type: "button",
|
|
57
|
-
className: "p-1 w-10 h-10 rounded-md border-transparent flex \
|
|
57
|
+
className: "p-1 w-10 h-10 rounded-md border-transparent flex \n justify-end items-end text-zinc-400 hover:text-zinc-100 transition-colors",
|
|
58
58
|
onClick: () => onScreenshotTook(null),
|
|
59
59
|
style: {
|
|
60
60
|
backgroundImage: `url(${screenshot})`,
|
|
@@ -69,119 +69,384 @@ function ScreenshotButton({
|
|
|
69
69
|
"button",
|
|
70
70
|
{
|
|
71
71
|
type: "button",
|
|
72
|
-
className: "p-2 bg-zinc-800 rounded-md border-transparent hover:bg-zinc-700\
|
|
72
|
+
className: "p-2 bg-zinc-800 rounded-md border-transparent hover:bg-zinc-700\n transitions-colors focus:outline-none focus:ring-2\n focus:ring-offset-2 focus:ring-offset-zinc-900 focus:ring-brand-500",
|
|
73
73
|
onClick: handleTakeScreenshot,
|
|
74
74
|
children: isTakenScreenshot ? /* @__PURE__ */ jsx(Loading, {}) : /* @__PURE__ */ jsx(Camera, { weight: "bold", className: "w-6 h-6" })
|
|
75
75
|
}
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
// src/lib/integrations/
|
|
80
|
-
async function
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
name: typeMap[type]
|
|
79
|
+
// src/lib/integrations/github.ts
|
|
80
|
+
async function uploadScreenshotToRepo(token, owner, repo, screenshot, screenshotPath) {
|
|
81
|
+
const compressedScreenshot = await compressScreenshot(screenshot, 1920, 0.7);
|
|
82
|
+
const base64Data = compressedScreenshot.split(",")[1];
|
|
83
|
+
const binaryData = Uint8Array.from(atob(base64Data), (c) => c.charCodeAt(0));
|
|
84
|
+
const repoResponse = await fetch(
|
|
85
|
+
`https://api.github.com/repos/${owner}/${repo}`,
|
|
86
|
+
{
|
|
87
|
+
headers: {
|
|
88
|
+
"Authorization": `Bearer ${token}`,
|
|
89
|
+
"Accept": "application/vnd.github.v3+json",
|
|
90
|
+
"User-Agent": "feedback-vos"
|
|
92
91
|
}
|
|
93
|
-
},
|
|
94
|
-
Comment: {
|
|
95
|
-
rich_text: [
|
|
96
|
-
{
|
|
97
|
-
text: {
|
|
98
|
-
content: comment
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
]
|
|
102
92
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
93
|
+
);
|
|
94
|
+
let defaultBranch = "main";
|
|
95
|
+
if (repoResponse.ok) {
|
|
96
|
+
const repoData = await repoResponse.json();
|
|
97
|
+
defaultBranch = repoData.default_branch || "main";
|
|
98
|
+
}
|
|
99
|
+
const folderPath = screenshotPath || ".feedback-vos";
|
|
100
|
+
const timestamp = Date.now();
|
|
101
|
+
const randomId = Math.random().toString(36).substring(2, 9);
|
|
102
|
+
const filename = `feedback-${timestamp}-${randomId}.jpg`;
|
|
103
|
+
const path = `${folderPath}/${filename}`;
|
|
104
|
+
const base64Content = btoa(String.fromCharCode(...binaryData));
|
|
105
|
+
const folderCheckUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${folderPath}`;
|
|
106
|
+
try {
|
|
107
|
+
const folderCheck = await fetch(folderCheckUrl, {
|
|
108
|
+
headers: {
|
|
109
|
+
"Authorization": `Bearer ${token}`,
|
|
110
|
+
"Accept": "application/vnd.github.v3+json",
|
|
111
|
+
"User-Agent": "feedback-vos"
|
|
117
112
|
}
|
|
118
113
|
});
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
if (folderCheck.status === 404) {
|
|
115
|
+
const readmeContent = btoa("# Feedback Screenshots\n\nThis folder contains screenshots from user feedback.\n");
|
|
116
|
+
try {
|
|
117
|
+
const folderCreateResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/contents/${folderPath}/README.md`, {
|
|
118
|
+
method: "PUT",
|
|
119
|
+
headers: {
|
|
120
|
+
"Authorization": `Bearer ${token}`,
|
|
121
|
+
"Accept": "application/vnd.github.v3+json",
|
|
122
|
+
"Content-Type": "application/json",
|
|
123
|
+
"User-Agent": "feedback-vos"
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify({
|
|
126
|
+
message: "Create feedback screenshots folder",
|
|
127
|
+
content: readmeContent,
|
|
128
|
+
branch: defaultBranch
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
if (!folderCreateResponse.ok) {
|
|
132
|
+
const folderError = await folderCreateResponse.json().catch(() => ({}));
|
|
133
|
+
console.warn("Could not create folder, proceeding with upload anyway:", folderError);
|
|
134
|
+
} else {
|
|
135
|
+
console.log(`Folder ${folderPath} created successfully`);
|
|
126
136
|
}
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
} catch (folderCreateError) {
|
|
138
|
+
console.warn("Could not create folder, proceeding with upload:", folderCreateError);
|
|
139
|
+
}
|
|
140
|
+
} else if (folderCheck.status === 200) {
|
|
141
|
+
const folderData = await folderCheck.json().catch(() => null);
|
|
142
|
+
if (folderData && !Array.isArray(folderData)) {
|
|
143
|
+
throw new Error(`Path "${folderPath}" exists as a file, not a folder. Please use a different path or remove the file.`);
|
|
144
|
+
}
|
|
145
|
+
console.log(`Folder ${folderPath} already exists`);
|
|
146
|
+
}
|
|
147
|
+
} catch (folderError) {
|
|
148
|
+
if (folderError instanceof Error && folderError.message.includes("exists as a file")) {
|
|
149
|
+
throw folderError;
|
|
150
|
+
}
|
|
151
|
+
console.warn("Could not verify/create screenshots folder:", folderError);
|
|
129
152
|
}
|
|
130
|
-
const
|
|
131
|
-
|
|
153
|
+
const uploadUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;
|
|
154
|
+
const response = await fetch(uploadUrl, {
|
|
155
|
+
method: "PUT",
|
|
132
156
|
headers: {
|
|
133
|
-
"Authorization": `Bearer ${
|
|
157
|
+
"Authorization": `Bearer ${token}`,
|
|
158
|
+
"Accept": "application/vnd.github.v3+json",
|
|
134
159
|
"Content-Type": "application/json",
|
|
135
|
-
"
|
|
160
|
+
"User-Agent": "feedback-vos"
|
|
136
161
|
},
|
|
137
162
|
body: JSON.stringify({
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
properties,
|
|
142
|
-
children
|
|
163
|
+
message: `Add feedback screenshot: ${filename}`,
|
|
164
|
+
content: base64Content,
|
|
165
|
+
branch: defaultBranch
|
|
143
166
|
})
|
|
144
167
|
});
|
|
145
168
|
if (!response.ok) {
|
|
146
|
-
const
|
|
147
|
-
|
|
169
|
+
const errorData = await response.json().catch(() => ({}));
|
|
170
|
+
const errorMessage = errorData.message || "Unknown error";
|
|
171
|
+
if (response.status === 409) {
|
|
172
|
+
throw new Error(`File already exists. This is unexpected - please try again.`);
|
|
173
|
+
} else if (response.status === 403) {
|
|
174
|
+
throw new Error(`Permission denied. Make sure your token has write access to the repository.`);
|
|
175
|
+
} else if (response.status === 422) {
|
|
176
|
+
throw new Error(`Validation failed: ${errorMessage}. The file might be too large.`);
|
|
177
|
+
}
|
|
178
|
+
throw new Error(`Failed to upload screenshot (${response.status}): ${errorMessage}`);
|
|
179
|
+
}
|
|
180
|
+
await response.json();
|
|
181
|
+
const rawUrl = `https://github.com/${owner}/${repo}/blob/${defaultBranch}/${path}?raw=true`;
|
|
182
|
+
console.log(`Screenshot uploaded successfully to: ${rawUrl}`);
|
|
183
|
+
return rawUrl;
|
|
184
|
+
}
|
|
185
|
+
function compressScreenshot(dataUrl, maxWidth = 1920, quality = 0.7) {
|
|
186
|
+
return new Promise((resolve, reject) => {
|
|
187
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
188
|
+
reject(new Error("Screenshot compression only works in browser environments"));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const img = new Image();
|
|
192
|
+
img.onload = () => {
|
|
193
|
+
const canvas = document.createElement("canvas");
|
|
194
|
+
let width = img.width;
|
|
195
|
+
let height = img.height;
|
|
196
|
+
if (width > maxWidth) {
|
|
197
|
+
height = height * maxWidth / width;
|
|
198
|
+
width = maxWidth;
|
|
199
|
+
}
|
|
200
|
+
canvas.width = width;
|
|
201
|
+
canvas.height = height;
|
|
202
|
+
const ctx = canvas.getContext("2d");
|
|
203
|
+
if (!ctx) {
|
|
204
|
+
reject(new Error("Could not get canvas context"));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
208
|
+
const compressedDataUrl = canvas.toDataURL("image/jpeg", quality);
|
|
209
|
+
resolve(compressedDataUrl);
|
|
210
|
+
};
|
|
211
|
+
img.onerror = () => reject(new Error("Failed to load image"));
|
|
212
|
+
img.src = dataUrl;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
async function verifyRepositoryAccess(token, owner, repo) {
|
|
216
|
+
try {
|
|
217
|
+
const response = await fetch(
|
|
218
|
+
`https://api.github.com/repos/${owner}/${repo}`,
|
|
219
|
+
{
|
|
220
|
+
headers: {
|
|
221
|
+
"Authorization": `Bearer ${token}`,
|
|
222
|
+
"Accept": "application/vnd.github.v3+json",
|
|
223
|
+
"User-Agent": "feedback-vos"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
if (response.status === 404) {
|
|
228
|
+
return { exists: false, hasIssues: false, error: "Repository not found" };
|
|
229
|
+
}
|
|
230
|
+
if (!response.ok) {
|
|
231
|
+
const errorData = await response.json().catch(() => ({}));
|
|
232
|
+
return {
|
|
233
|
+
exists: false,
|
|
234
|
+
hasIssues: false,
|
|
235
|
+
error: errorData.message || `HTTP ${response.status}`
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const repoData = await response.json();
|
|
239
|
+
return {
|
|
240
|
+
exists: true,
|
|
241
|
+
hasIssues: repoData.has_issues !== false
|
|
242
|
+
// Default is true if not specified
|
|
243
|
+
};
|
|
244
|
+
} catch (error) {
|
|
245
|
+
return {
|
|
246
|
+
exists: false,
|
|
247
|
+
hasIssues: false,
|
|
248
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
249
|
+
};
|
|
148
250
|
}
|
|
149
251
|
}
|
|
150
|
-
|
|
151
|
-
// src/lib/integrations/github.ts
|
|
152
252
|
async function sendToGitHub(config, data) {
|
|
153
|
-
const { token, owner, repo } = config;
|
|
253
|
+
const { token, owner, repo, screenshotPath } = config;
|
|
154
254
|
const { type, comment, screenshot } = data;
|
|
255
|
+
if (!token || !owner || !repo) {
|
|
256
|
+
throw new Error("GitHub configuration is incomplete. Please provide token, owner, and repo.");
|
|
257
|
+
}
|
|
258
|
+
const verification = await verifyRepositoryAccess(token, owner, repo);
|
|
259
|
+
if (!verification.exists) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`Repository "${owner}/${repo}" not found or not accessible.
|
|
262
|
+
Error: ${verification.error || "Unknown error"}
|
|
263
|
+
|
|
264
|
+
Please verify:
|
|
265
|
+
- Repository exists at https://github.com/${owner}/${repo}
|
|
266
|
+
- Your token has access to this repository
|
|
267
|
+
- Token has "repo" scope (for private) or "public_repo" scope (for public)`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
if (!verification.hasIssues) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
`Issues are disabled for repository "${owner}/${repo}".
|
|
273
|
+
|
|
274
|
+
Please enable Issues in repository Settings \u2192 General \u2192 Features \u2192 Issues`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
155
277
|
const title = `[${type}] Feedback`;
|
|
278
|
+
const ABSOLUTE_MAX_LENGTH = 65536;
|
|
279
|
+
const BASE_BODY_LENGTH = 50;
|
|
280
|
+
const SCREENSHOT_URL_LENGTH = 150;
|
|
281
|
+
const SAFETY_MARGIN = 1e3;
|
|
282
|
+
const MAX_COMMENT_LENGTH = ABSOLUTE_MAX_LENGTH - BASE_BODY_LENGTH - SCREENSHOT_URL_LENGTH - SAFETY_MARGIN;
|
|
283
|
+
const limitedComment = comment.length > MAX_COMMENT_LENGTH ? comment.substring(0, MAX_COMMENT_LENGTH) + "\n\n... (comment truncated)" : comment;
|
|
156
284
|
let body = `**Type:** ${type}
|
|
157
285
|
|
|
158
286
|
**Comment:**
|
|
159
|
-
${
|
|
287
|
+
${limitedComment}`;
|
|
160
288
|
if (screenshot) {
|
|
161
|
-
|
|
289
|
+
try {
|
|
290
|
+
console.log("Uploading screenshot to repository...");
|
|
291
|
+
console.log("Screenshot path:", screenshotPath || ".feedback-vos");
|
|
292
|
+
const screenshotUrl = await uploadScreenshotToRepo(token, owner, repo, screenshot, screenshotPath);
|
|
293
|
+
console.log("Screenshot uploaded successfully, URL:", screenshotUrl);
|
|
294
|
+
body += `
|
|
162
295
|
|
|
163
296
|
**Screenshot:**
|
|
164
|
-
`;
|
|
298
|
+
console.log("Body length after adding screenshot URL:", body.length);
|
|
299
|
+
} catch (error) {
|
|
300
|
+
console.error("Failed to upload screenshot to repository:", error);
|
|
301
|
+
body += `
|
|
302
|
+
|
|
303
|
+
**Screenshot:** Upload failed - screenshot not included.`;
|
|
304
|
+
console.log("Body length after upload failure:", body.length);
|
|
305
|
+
}
|
|
165
306
|
}
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
307
|
+
const SAFE_MAX_LENGTH = 65e3;
|
|
308
|
+
console.log(`Issue body length before final check: ${body.length} characters`);
|
|
309
|
+
if (body.length > SAFE_MAX_LENGTH) {
|
|
310
|
+
console.warn(`Body is too long (${body.length}), truncating...`);
|
|
311
|
+
const excess = body.length - SAFE_MAX_LENGTH;
|
|
312
|
+
const commentStartMarker = "\n\n**Comment:**\n";
|
|
313
|
+
const commentStart = body.indexOf(commentStartMarker);
|
|
314
|
+
const screenshotStart = body.indexOf("\n\n**Screenshot:**");
|
|
315
|
+
if (commentStart > 0) {
|
|
316
|
+
const commentStartPos = commentStart + commentStartMarker.length;
|
|
317
|
+
const commentEndPos = screenshotStart > 0 ? screenshotStart : body.length;
|
|
318
|
+
const currentComment = body.substring(commentStartPos, commentEndPos);
|
|
319
|
+
const newCommentLength = Math.max(100, currentComment.length - excess - 500);
|
|
320
|
+
const truncatedComment = currentComment.substring(0, newCommentLength) + "\n\n... (truncated due to size limit)";
|
|
321
|
+
const beforeComment = body.substring(0, commentStartPos);
|
|
322
|
+
const afterComment = screenshotStart > 0 ? body.substring(screenshotStart) : "";
|
|
323
|
+
body = beforeComment + truncatedComment + afterComment;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (body.length >= ABSOLUTE_MAX_LENGTH) {
|
|
327
|
+
console.error(`Body STILL too long after truncation: ${body.length} characters. Force truncating.`);
|
|
328
|
+
const baseText = `**Type:** ${type}
|
|
329
|
+
|
|
330
|
+
**Comment:**
|
|
331
|
+
`;
|
|
332
|
+
const maxCommentLength = ABSOLUTE_MAX_LENGTH - baseText.length - 1e3;
|
|
333
|
+
const safeComment = comment.substring(0, Math.max(100, maxCommentLength)) + "\n\n... (truncated due to size limit)";
|
|
334
|
+
body = baseText + safeComment;
|
|
335
|
+
const screenshotIndex = body.indexOf("\n\n**Screenshot:**");
|
|
336
|
+
if (screenshotIndex > 0) {
|
|
337
|
+
body = body.substring(0, screenshotIndex) + "\n\n**Screenshot:** Not included due to size limit.";
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (body.length >= ABSOLUTE_MAX_LENGTH) {
|
|
341
|
+
const minimalBase = `**Type:** ${type}
|
|
342
|
+
|
|
343
|
+
**Comment:**
|
|
344
|
+
`;
|
|
345
|
+
const maxSafeComment = ABSOLUTE_MAX_LENGTH - minimalBase.length - 100;
|
|
346
|
+
const minimalComment = comment.substring(0, Math.max(50, maxSafeComment)) + "\n\n... (truncated)";
|
|
347
|
+
body = minimalBase + minimalComment;
|
|
348
|
+
}
|
|
349
|
+
console.log(`Final issue body length: ${body.length} characters (limit: ${ABSOLUTE_MAX_LENGTH})`);
|
|
350
|
+
if (body.length >= ABSOLUTE_MAX_LENGTH) {
|
|
351
|
+
throw new Error(`CRITICAL: Cannot create issue - body is ${body.length} characters, exceeds GitHub limit of ${ABSOLUTE_MAX_LENGTH}.`);
|
|
352
|
+
}
|
|
353
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/issues`;
|
|
354
|
+
try {
|
|
355
|
+
const response = await fetch(url, {
|
|
169
356
|
method: "POST",
|
|
170
357
|
headers: {
|
|
171
|
-
"Authorization": `
|
|
358
|
+
"Authorization": `Bearer ${token}`,
|
|
172
359
|
"Accept": "application/vnd.github.v3+json",
|
|
173
|
-
"Content-Type": "application/json"
|
|
360
|
+
"Content-Type": "application/json",
|
|
361
|
+
"User-Agent": "feedback-vos"
|
|
174
362
|
},
|
|
175
363
|
body: JSON.stringify({
|
|
176
364
|
title,
|
|
177
365
|
body,
|
|
366
|
+
// Note: Labels must exist in the repository. If they don't exist, GitHub will ignore them.
|
|
367
|
+
// You can create these labels in your repository settings if needed.
|
|
178
368
|
labels: ["feedback", type.toLowerCase()]
|
|
179
369
|
})
|
|
370
|
+
});
|
|
371
|
+
if (!response.ok) {
|
|
372
|
+
let errorMessage = `GitHub API error (${response.status}): `;
|
|
373
|
+
try {
|
|
374
|
+
const errorData = await response.json();
|
|
375
|
+
errorMessage += errorData.message || JSON.stringify(errorData);
|
|
376
|
+
if (response.status === 404) {
|
|
377
|
+
errorMessage += `
|
|
378
|
+
|
|
379
|
+
Trying to access: ${url}`;
|
|
380
|
+
errorMessage += `
|
|
381
|
+
|
|
382
|
+
Possible causes:
|
|
383
|
+
`;
|
|
384
|
+
errorMessage += `- Repository "${owner}/${repo}" does not exist or is not accessible
|
|
385
|
+
`;
|
|
386
|
+
errorMessage += `- Token does not have access to this repository
|
|
387
|
+
`;
|
|
388
|
+
errorMessage += `- Check that owner and repo names are correct (case-sensitive)
|
|
389
|
+
`;
|
|
390
|
+
errorMessage += `- Verify the repository URL: https://github.com/${owner}/${repo}
|
|
391
|
+
`;
|
|
392
|
+
errorMessage += `- Make sure Issues are enabled in repository settings
|
|
393
|
+
`;
|
|
394
|
+
errorMessage += `
|
|
395
|
+
To debug:
|
|
396
|
+
`;
|
|
397
|
+
errorMessage += `1. Visit https://github.com/${owner}/${repo} to verify it exists
|
|
398
|
+
`;
|
|
399
|
+
errorMessage += `2. Check repository Settings \u2192 General \u2192 Features \u2192 Issues (must be enabled)
|
|
400
|
+
`;
|
|
401
|
+
errorMessage += `3. Verify your token has "repo" scope (for private) or "public_repo" scope (for public)
|
|
402
|
+
`;
|
|
403
|
+
errorMessage += `4. Test token access: curl -H "Authorization: Bearer YOUR_TOKEN" https://api.github.com/repos/${owner}/${repo}`;
|
|
404
|
+
} else if (response.status === 401) {
|
|
405
|
+
errorMessage += `
|
|
406
|
+
|
|
407
|
+
Possible causes:
|
|
408
|
+
`;
|
|
409
|
+
errorMessage += `- Invalid or expired GitHub token
|
|
410
|
+
`;
|
|
411
|
+
errorMessage += `- Token does not have the required "repo" or "public_repo" scope
|
|
412
|
+
`;
|
|
413
|
+
errorMessage += `- Generate a new token at https://github.com/settings/tokens`;
|
|
414
|
+
} else if (response.status === 422) {
|
|
415
|
+
errorMessage += `
|
|
416
|
+
|
|
417
|
+
Possible causes:
|
|
418
|
+
`;
|
|
419
|
+
errorMessage += `- Issue body is too long (maximum is 65536 characters)
|
|
420
|
+
`;
|
|
421
|
+
errorMessage += `- Screenshot is too large - it will be automatically compressed
|
|
422
|
+
`;
|
|
423
|
+
errorMessage += `- Try reducing the comment length or removing the screenshot
|
|
424
|
+
`;
|
|
425
|
+
errorMessage += `- Invalid label names (labels must exist in the repository)`;
|
|
426
|
+
} else if (response.status === 403) {
|
|
427
|
+
errorMessage += `
|
|
428
|
+
|
|
429
|
+
Possible causes:
|
|
430
|
+
`;
|
|
431
|
+
errorMessage += `- Token does not have permission to create issues
|
|
432
|
+
`;
|
|
433
|
+
errorMessage += `- Repository has issues disabled
|
|
434
|
+
`;
|
|
435
|
+
errorMessage += `- Rate limit exceeded (check GitHub API rate limits)
|
|
436
|
+
`;
|
|
437
|
+
errorMessage += `- Check repository Settings \u2192 General \u2192 Features \u2192 Issues`;
|
|
438
|
+
}
|
|
439
|
+
} catch (parseError) {
|
|
440
|
+
const errorText = await response.text();
|
|
441
|
+
errorMessage += errorText || "Unknown error";
|
|
442
|
+
}
|
|
443
|
+
throw new Error(errorMessage);
|
|
180
444
|
}
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
445
|
+
} catch (error) {
|
|
446
|
+
if (error instanceof Error) {
|
|
447
|
+
throw error;
|
|
448
|
+
}
|
|
449
|
+
throw new Error(`Failed to create GitHub issue: ${String(error)}`);
|
|
185
450
|
}
|
|
186
451
|
}
|
|
187
452
|
function FeedbackContentStep({
|
|
@@ -189,7 +454,6 @@ function FeedbackContentStep({
|
|
|
189
454
|
onFeedbackRestartRequest,
|
|
190
455
|
onFeedbackSent,
|
|
191
456
|
integration,
|
|
192
|
-
notionConfig,
|
|
193
457
|
githubConfig
|
|
194
458
|
}) {
|
|
195
459
|
const [screenshot, setScreenshot] = useState(null);
|
|
@@ -205,9 +469,7 @@ function FeedbackContentStep({
|
|
|
205
469
|
comment,
|
|
206
470
|
screenshot
|
|
207
471
|
};
|
|
208
|
-
if (integration === "
|
|
209
|
-
await sendToNotion(notionConfig, feedbackData);
|
|
210
|
-
} else if (integration === "github" && githubConfig) {
|
|
472
|
+
if (integration === "github") {
|
|
211
473
|
await sendToGitHub(githubConfig, feedbackData);
|
|
212
474
|
} else {
|
|
213
475
|
throw new Error("Invalid integration configuration");
|
|
@@ -248,7 +510,7 @@ function FeedbackContentStep({
|
|
|
248
510
|
/* @__PURE__ */ jsx(
|
|
249
511
|
"textarea",
|
|
250
512
|
{
|
|
251
|
-
className: "min-w-[384px] w-full min-h-[112px] text-sm \
|
|
513
|
+
className: "min-w-[384px] w-full min-h-[112px] text-sm \n placeholder-zinc-400 text-zinc-100 border-zinc-600 bg-transparent rounded-md \n focus:border-brand-500 focus:ring-brand-500 focus:ring-1 resize-none focus:outline-none\n scrollbar-thumb-zinc-700 scrollbar-track-transparent scrollbar-thin",
|
|
252
514
|
placeholder: "Tell in detail what is happening",
|
|
253
515
|
onChange: (e) => setComment(e.target.value)
|
|
254
516
|
}
|
|
@@ -266,7 +528,7 @@ function FeedbackContentStep({
|
|
|
266
528
|
{
|
|
267
529
|
type: "submit",
|
|
268
530
|
disabled: comment.length === 0 || isSendingFeedback,
|
|
269
|
-
className: "p-2 bg-brand-500 rounded-md border-transparent flex-1 justify-center\
|
|
531
|
+
className: "p-2 bg-brand-500 rounded-md border-transparent flex-1 justify-center\n items-center text-sm hover:bg-brand-300 focus:outline-none focus:ring-2\n focus:ring-offset-2 focus:ring-offset-zinc-900 focus:ring-brand-500\n transition-colors disabled:opacity-50 disabled:cursor-not-allowed\n disabled:hover:bg-brand-500",
|
|
270
532
|
children: isSendingFeedback ? /* @__PURE__ */ jsx(Loading, {}) : "Send feedback"
|
|
271
533
|
}
|
|
272
534
|
)
|
|
@@ -318,7 +580,7 @@ var feedbackTypes = {
|
|
|
318
580
|
}
|
|
319
581
|
}
|
|
320
582
|
};
|
|
321
|
-
function WidgetForm({ integration,
|
|
583
|
+
function WidgetForm({ integration, githubConfig }) {
|
|
322
584
|
const [feedbackType, setFeedbackType] = useState(null);
|
|
323
585
|
const [feedbackSent, setFeedbackSent] = useState(false);
|
|
324
586
|
function handleRestartFeedback() {
|
|
@@ -333,7 +595,6 @@ function WidgetForm({ integration, notionConfig, githubConfig }) {
|
|
|
333
595
|
onFeedbackRestartRequest: handleRestartFeedback,
|
|
334
596
|
onFeedbackSent: () => setFeedbackSent(true),
|
|
335
597
|
integration,
|
|
336
|
-
notionConfig,
|
|
337
598
|
githubConfig
|
|
338
599
|
}
|
|
339
600
|
) }),
|
|
@@ -353,7 +614,6 @@ function WidgetForm({ integration, notionConfig, githubConfig }) {
|
|
|
353
614
|
}
|
|
354
615
|
function Widget({
|
|
355
616
|
integration,
|
|
356
|
-
notionConfig,
|
|
357
617
|
githubConfig,
|
|
358
618
|
position = "bottom-right"
|
|
359
619
|
}) {
|
|
@@ -368,7 +628,6 @@ function Widget({
|
|
|
368
628
|
WidgetForm,
|
|
369
629
|
{
|
|
370
630
|
integration,
|
|
371
|
-
notionConfig,
|
|
372
631
|
githubConfig
|
|
373
632
|
}
|
|
374
633
|
) }),
|