glitchgrab 1.58.1 → 1.58.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/README.md +28 -0
- package/dist/index.d.mts +21 -3
- package/dist/index.d.ts +21 -3
- package/dist/index.js +730 -569
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +729 -569
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +30 -3
- package/dist/server.d.ts +30 -3
- package/dist/server.js +42 -13
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +40 -13
- package/dist/server.mjs.map +1 -1
- package/dist/{types-DfVtKZcp.d.mts → types-BpTLWJ1y.d.mts} +8 -0
- package/dist/{types-DfVtKZcp.d.ts → types-BpTLWJ1y.d.ts} +8 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -587,6 +587,9 @@ function contextMetadata(context) {
|
|
|
587
587
|
var DEFAULT_BASE_URL = "https://glitchgrab.dev";
|
|
588
588
|
var MAX_RETRIES = 3;
|
|
589
589
|
var RETRY_BASE_MS = 500;
|
|
590
|
+
function reportAttemptTimeoutMs(bodyLength) {
|
|
591
|
+
return 1e4 + Math.ceil(bodyLength / 1e5) * 1e3;
|
|
592
|
+
}
|
|
590
593
|
async function sendReport(payload, baseUrl) {
|
|
591
594
|
var _a;
|
|
592
595
|
try {
|
|
@@ -597,13 +600,18 @@ async function sendReport(payload, baseUrl) {
|
|
|
597
600
|
Authorization: `Bearer ${payload.token}`
|
|
598
601
|
};
|
|
599
602
|
const useKeepalive = body.length < 6e4;
|
|
603
|
+
const timeoutMs = reportAttemptTimeoutMs(body.length);
|
|
600
604
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
605
|
+
const isLast = attempt === MAX_RETRIES - 1;
|
|
606
|
+
const controller = !isLast && typeof AbortController === "function" ? new AbortController() : null;
|
|
607
|
+
const timer = controller ? setTimeout(() => controller.abort(), timeoutMs) : null;
|
|
601
608
|
try {
|
|
602
609
|
const response = await fetch(url, {
|
|
603
610
|
method: "POST",
|
|
604
611
|
headers,
|
|
605
612
|
body,
|
|
606
|
-
...useKeepalive ? { keepalive: true } : {}
|
|
613
|
+
...useKeepalive ? { keepalive: true } : {},
|
|
614
|
+
...controller ? { signal: controller.signal } : {}
|
|
607
615
|
});
|
|
608
616
|
if (response.ok) {
|
|
609
617
|
const envelope = await response.json();
|
|
@@ -613,6 +621,8 @@ async function sendReport(payload, baseUrl) {
|
|
|
613
621
|
return null;
|
|
614
622
|
}
|
|
615
623
|
} catch (e) {
|
|
624
|
+
} finally {
|
|
625
|
+
if (timer) clearTimeout(timer);
|
|
616
626
|
}
|
|
617
627
|
if (attempt < MAX_RETRIES - 1) {
|
|
618
628
|
await new Promise(
|
|
@@ -729,7 +739,7 @@ async function enhanceText(text, token, baseUrl, screenshot, context, identity)
|
|
|
729
739
|
return text;
|
|
730
740
|
}
|
|
731
741
|
}
|
|
732
|
-
async function findSimilarIssues(description, token, baseUrl, identity) {
|
|
742
|
+
async function findSimilarIssues(description, token, baseUrl, identity, files) {
|
|
733
743
|
var _a;
|
|
734
744
|
try {
|
|
735
745
|
const url = `${baseUrl != null ? baseUrl : DEFAULT_BASE_URL}/api/v1/reports/similar`;
|
|
@@ -739,7 +749,11 @@ async function findSimilarIssues(description, token, baseUrl, identity) {
|
|
|
739
749
|
"Content-Type": "application/json",
|
|
740
750
|
Authorization: `Bearer ${token}`
|
|
741
751
|
},
|
|
742
|
-
body: JSON.stringify({
|
|
752
|
+
body: JSON.stringify({
|
|
753
|
+
text: description,
|
|
754
|
+
...(files == null ? void 0 : files.length) ? { files } : {},
|
|
755
|
+
...signedFields(identity)
|
|
756
|
+
})
|
|
743
757
|
});
|
|
744
758
|
const envelope = await response.json().catch(() => null);
|
|
745
759
|
if (!response.ok || !(envelope == null ? void 0 : envelope.success)) return null;
|
|
@@ -749,6 +763,25 @@ async function findSimilarIssues(description, token, baseUrl, identity) {
|
|
|
749
763
|
return null;
|
|
750
764
|
}
|
|
751
765
|
}
|
|
766
|
+
async function readAttachment(file, token, baseUrl, identity) {
|
|
767
|
+
var _a;
|
|
768
|
+
try {
|
|
769
|
+
const url = `${baseUrl != null ? baseUrl : DEFAULT_BASE_URL}/api/v1/ai/read-file`;
|
|
770
|
+
const response = await fetch(url, {
|
|
771
|
+
method: "POST",
|
|
772
|
+
headers: {
|
|
773
|
+
"Content-Type": "application/json",
|
|
774
|
+
Authorization: `Bearer ${token}`
|
|
775
|
+
},
|
|
776
|
+
body: JSON.stringify({ name: file.name, data: file.dataUrl, ...signedFields(identity) })
|
|
777
|
+
});
|
|
778
|
+
const envelope = await response.json().catch(() => null);
|
|
779
|
+
if (!response.ok || !(envelope == null ? void 0 : envelope.success) || !((_a = envelope.data) == null ? void 0 : _a.enabled)) return null;
|
|
780
|
+
return typeof envelope.data.text === "string" ? envelope.data.text : null;
|
|
781
|
+
} catch (e) {
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
752
785
|
async function assistTurn(params, token, baseUrl) {
|
|
753
786
|
const offline = assistOffline();
|
|
754
787
|
try {
|
|
@@ -1355,6 +1388,9 @@ var MAX_ASSIST_IMAGE_CHARS = 35e5;
|
|
|
1355
1388
|
var MAX_ASSIST_FILES = 3;
|
|
1356
1389
|
var MAX_ASSIST_FILE_CHARS = 3e5;
|
|
1357
1390
|
var MAX_ASSIST_FILE_CHARS_EACH = 2e5;
|
|
1391
|
+
var MAX_SIMILAR_FILE_CHARS = 2e4;
|
|
1392
|
+
var MAX_SIMILAR_FILES_TOTAL_CHARS = 4e4;
|
|
1393
|
+
var MAX_READABLE_PDF_BYTES = 3 * 1024 * 1024;
|
|
1358
1394
|
var TEXT_ATTACHMENT_EXTENSIONS = [
|
|
1359
1395
|
".html",
|
|
1360
1396
|
".htm",
|
|
@@ -1385,6 +1421,10 @@ var ATTACHMENT_ACCEPT = [
|
|
|
1385
1421
|
...BINARY_ATTACHMENT_EXTENSIONS
|
|
1386
1422
|
].join(",");
|
|
1387
1423
|
var ASSIST_ATTACHMENT_ACCEPT = ["image/*", ...TEXT_ATTACHMENT_EXTENSIONS].join(",");
|
|
1424
|
+
var ASSIST_ATTACHMENT_ACCEPT_WITH_PDF = [ASSIST_ATTACHMENT_ACCEPT, ".pdf"].join(",");
|
|
1425
|
+
function isPdfFile(name) {
|
|
1426
|
+
return name.toLowerCase().endsWith(".pdf");
|
|
1427
|
+
}
|
|
1388
1428
|
function isAssistReadableFile(name) {
|
|
1389
1429
|
const lower = name.toLowerCase();
|
|
1390
1430
|
return TEXT_ATTACHMENT_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
@@ -1405,6 +1445,27 @@ function decodeTextDataUrl(dataUrl) {
|
|
|
1405
1445
|
return null;
|
|
1406
1446
|
}
|
|
1407
1447
|
}
|
|
1448
|
+
function heldFileKey(file) {
|
|
1449
|
+
return `${file.name}:${file.size}`;
|
|
1450
|
+
}
|
|
1451
|
+
function heldFileText(file) {
|
|
1452
|
+
if (isPdfFile(file.name)) return typeof file.text === "string" && file.text.trim() ? file.text : null;
|
|
1453
|
+
if (!isAssistReadableFile(file.name)) return null;
|
|
1454
|
+
const text = decodeTextDataUrl(file.dataUrl);
|
|
1455
|
+
return text && text.trim() ? text : null;
|
|
1456
|
+
}
|
|
1457
|
+
function filesForSimilar(files, each, total) {
|
|
1458
|
+
const picked = [];
|
|
1459
|
+
let used = 0;
|
|
1460
|
+
for (let i = files.length - 1; i >= 0 && used < total; i--) {
|
|
1461
|
+
const text = heldFileText(files[i]);
|
|
1462
|
+
if (!text) continue;
|
|
1463
|
+
const content = text.slice(0, Math.min(each, total - used));
|
|
1464
|
+
picked.unshift({ name: files[i].name, content });
|
|
1465
|
+
used += content.length;
|
|
1466
|
+
}
|
|
1467
|
+
return picked;
|
|
1468
|
+
}
|
|
1408
1469
|
function getTypeLabel(type) {
|
|
1409
1470
|
switch (type) {
|
|
1410
1471
|
case "RATING":
|
|
@@ -1848,9 +1909,8 @@ function pickAssistFiles(files) {
|
|
|
1848
1909
|
let total = 0;
|
|
1849
1910
|
for (let i = files.length - 1; i >= 0 && picked.length < MAX_ASSIST_FILES; i--) {
|
|
1850
1911
|
const attached = files[i];
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
if (!text || !text.trim()) continue;
|
|
1912
|
+
const text = heldFileText(attached);
|
|
1913
|
+
if (!text) continue;
|
|
1854
1914
|
const content = text.slice(0, MAX_ASSIST_FILE_CHARS_EACH);
|
|
1855
1915
|
if (total + content.length > MAX_ASSIST_FILE_CHARS) continue;
|
|
1856
1916
|
picked.unshift({ index: i, file: { name: attached.name, content } });
|
|
@@ -1947,6 +2007,7 @@ function AssistSheet({
|
|
|
1947
2007
|
pageShot = null,
|
|
1948
2008
|
onAddFiles,
|
|
1949
2009
|
files = NO_FILES,
|
|
2010
|
+
canReadPdf = false,
|
|
1950
2011
|
onRemoveFile,
|
|
1951
2012
|
onRemoveImage,
|
|
1952
2013
|
attachmentCount,
|
|
@@ -1974,6 +2035,8 @@ function AssistSheet({
|
|
|
1974
2035
|
isSubmitting,
|
|
1975
2036
|
submitted,
|
|
1976
2037
|
onSend,
|
|
2038
|
+
similarSlot,
|
|
2039
|
+
submittedText,
|
|
1977
2040
|
onDegrade,
|
|
1978
2041
|
onClose,
|
|
1979
2042
|
onFinish,
|
|
@@ -1997,6 +2060,7 @@ function AssistSheet({
|
|
|
1997
2060
|
const [autoFileLeft, setAutoFileLeft] = useState2(null);
|
|
1998
2061
|
const scrollRef = useRef2(null);
|
|
1999
2062
|
const draftRef = useRef2(null);
|
|
2063
|
+
const composerRef = useRef2(null);
|
|
2000
2064
|
const seededRef = useRef2(false);
|
|
2001
2065
|
const seedPendingRef = useRef2(false);
|
|
2002
2066
|
const eventsRef = useRef2([]);
|
|
@@ -2038,6 +2102,12 @@ function AssistSheet({
|
|
|
2038
2102
|
var _a;
|
|
2039
2103
|
if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
|
|
2040
2104
|
}, [phase]);
|
|
2105
|
+
useEffect2(() => {
|
|
2106
|
+
const el = composerRef.current;
|
|
2107
|
+
if (!el) return;
|
|
2108
|
+
el.style.height = "auto";
|
|
2109
|
+
el.style.height = `${el.scrollHeight + 2}px`;
|
|
2110
|
+
}, [input]);
|
|
2041
2111
|
useEffect2(() => {
|
|
2042
2112
|
if (autoFileLeft === null) return;
|
|
2043
2113
|
if (isSubmitting || submitted || phase !== "draft") {
|
|
@@ -2264,6 +2334,7 @@ function AssistSheet({
|
|
|
2264
2334
|
@keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}
|
|
2265
2335
|
@keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}
|
|
2266
2336
|
@keyframes gg-autofile{from{transform:scaleX(0)}to{transform:scaleX(1)}}
|
|
2337
|
+
@keyframes gg-spin{to{transform:rotate(360deg)}}
|
|
2267
2338
|
@keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}
|
|
2268
2339
|
[data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible,[data-gg-assist-remove]:focus-visible,[data-gg-stop-auto-file]:focus-visible{outline:2px solid currentColor;outline-offset:2px}
|
|
2269
2340
|
` }),
|
|
@@ -3138,7 +3209,7 @@ function AssistSheet({
|
|
|
3138
3209
|
}
|
|
3139
3210
|
)
|
|
3140
3211
|
] }),
|
|
3141
|
-
submitted && /* @__PURE__ */
|
|
3212
|
+
submitted && /* @__PURE__ */ jsx3(
|
|
3142
3213
|
"div",
|
|
3143
3214
|
{
|
|
3144
3215
|
style: {
|
|
@@ -3148,10 +3219,7 @@ function AssistSheet({
|
|
|
3148
3219
|
fontSize: "14px",
|
|
3149
3220
|
fontWeight: 600
|
|
3150
3221
|
},
|
|
3151
|
-
children:
|
|
3152
|
-
reportTypeLabel,
|
|
3153
|
-
" sent. Thank you!"
|
|
3154
|
-
]
|
|
3222
|
+
children: submittedText != null ? submittedText : `${reportTypeLabel} sent. Thank you!`
|
|
3155
3223
|
}
|
|
3156
3224
|
)
|
|
3157
3225
|
]
|
|
@@ -3217,342 +3285,363 @@ function AssistSheet({
|
|
|
3217
3285
|
// instead of remounting, and a draft is something you can
|
|
3218
3286
|
// still reply to (#360), not a form that replaced the chat.
|
|
3219
3287
|
/* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
3220
|
-
(
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3288
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: similarSlot ? "none" : "contents" }, children: [
|
|
3289
|
+
(screenshots.length > 0 || files.length > 0 || onAddFiles) && /* @__PURE__ */ jsxs3(
|
|
3290
|
+
"div",
|
|
3291
|
+
{
|
|
3292
|
+
style: {
|
|
3293
|
+
display: "flex",
|
|
3294
|
+
gap: "8px",
|
|
3295
|
+
alignItems: "center",
|
|
3296
|
+
flexWrap: "wrap",
|
|
3297
|
+
marginBottom: "8px"
|
|
3298
|
+
},
|
|
3299
|
+
children: [
|
|
3300
|
+
screenshots.map((shot, i) => {
|
|
3301
|
+
const read = readShots.has(shot);
|
|
3302
|
+
return /* @__PURE__ */ jsxs3(
|
|
3303
|
+
"div",
|
|
3304
|
+
{
|
|
3305
|
+
style: {
|
|
3306
|
+
position: "relative",
|
|
3307
|
+
width: "40px",
|
|
3308
|
+
height: "40px",
|
|
3309
|
+
flexShrink: 0
|
|
3310
|
+
},
|
|
3311
|
+
children: [
|
|
3312
|
+
/* @__PURE__ */ jsx3(
|
|
3313
|
+
"img",
|
|
3314
|
+
{
|
|
3315
|
+
src: shot,
|
|
3316
|
+
alt: read ? "Attached image the assistant reads" : "Attached image",
|
|
3317
|
+
"data-gg-assist-thumb": "",
|
|
3318
|
+
style: {
|
|
3319
|
+
display: "block",
|
|
3320
|
+
width: "100%",
|
|
3321
|
+
height: "100%",
|
|
3322
|
+
objectFit: "cover",
|
|
3323
|
+
borderRadius: "8px",
|
|
3324
|
+
border: `1px solid ${read ? t.accent : t.inputBorder}`,
|
|
3325
|
+
opacity: read ? 1 : 0.45,
|
|
3326
|
+
boxSizing: "border-box"
|
|
3327
|
+
}
|
|
3258
3328
|
}
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
}
|
|
3315
|
-
|
|
3329
|
+
),
|
|
3330
|
+
onRemoveImage && /* @__PURE__ */ jsx3(
|
|
3331
|
+
"button",
|
|
3332
|
+
{
|
|
3333
|
+
type: "button",
|
|
3334
|
+
"data-gg-assist-remove": "",
|
|
3335
|
+
"aria-label": `Remove image ${i + 1}`,
|
|
3336
|
+
title: "Remove this image",
|
|
3337
|
+
onClick: () => {
|
|
3338
|
+
stopAutoFile("changed attachments");
|
|
3339
|
+
logEvent(
|
|
3340
|
+
"image_removed",
|
|
3341
|
+
pageShot && shot === pageShot ? "page capture" : "attached"
|
|
3342
|
+
);
|
|
3343
|
+
onRemoveImage(i);
|
|
3344
|
+
},
|
|
3345
|
+
style: {
|
|
3346
|
+
position: "absolute",
|
|
3347
|
+
top: "-13px",
|
|
3348
|
+
right: "-13px",
|
|
3349
|
+
width: "32px",
|
|
3350
|
+
height: "32px",
|
|
3351
|
+
border: "none",
|
|
3352
|
+
background: "transparent",
|
|
3353
|
+
padding: 0,
|
|
3354
|
+
cursor: "pointer",
|
|
3355
|
+
display: "flex",
|
|
3356
|
+
alignItems: "center",
|
|
3357
|
+
justifyContent: "center",
|
|
3358
|
+
borderRadius: "50%"
|
|
3359
|
+
},
|
|
3360
|
+
children: /* @__PURE__ */ jsx3(
|
|
3361
|
+
"span",
|
|
3362
|
+
{
|
|
3363
|
+
"aria-hidden": "true",
|
|
3364
|
+
style: {
|
|
3365
|
+
width: "20px",
|
|
3366
|
+
height: "20px",
|
|
3367
|
+
boxSizing: "border-box",
|
|
3368
|
+
borderRadius: "50%",
|
|
3369
|
+
border: `2px solid ${t.bg}`,
|
|
3370
|
+
background: "#ef4444",
|
|
3371
|
+
color: "#fff",
|
|
3372
|
+
display: "flex",
|
|
3373
|
+
alignItems: "center",
|
|
3374
|
+
justifyContent: "center"
|
|
3375
|
+
},
|
|
3376
|
+
children: /* @__PURE__ */ jsx3("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx3(
|
|
3377
|
+
"path",
|
|
3378
|
+
{
|
|
3379
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
3380
|
+
stroke: "currentColor",
|
|
3381
|
+
strokeWidth: "1.6",
|
|
3382
|
+
strokeLinecap: "round"
|
|
3383
|
+
}
|
|
3384
|
+
) })
|
|
3385
|
+
}
|
|
3386
|
+
)
|
|
3387
|
+
}
|
|
3388
|
+
)
|
|
3389
|
+
]
|
|
3390
|
+
},
|
|
3391
|
+
`${i}-${shot.slice(-16)}`
|
|
3392
|
+
);
|
|
3393
|
+
}),
|
|
3394
|
+
files.map((file, i) => {
|
|
3395
|
+
const read = readFiles.has(i);
|
|
3396
|
+
const pdf = isPdfFile(file.name);
|
|
3397
|
+
const why = read ? "the assistant reads this file" : pdf && file.reading ? "reading the text in this PDF\u2026" : pdf && file.text !== void 0 ? file.text === null ? file.tooLarge ? "attached to the report \u2014 too large for the assistant to read (over 3 MB)" : "attached to the report \u2014 couldn't read this PDF" : file.text.trim() ? "attached, but more than one message can carry, so the assistant is not reading it" : "attached to the report \u2014 this PDF has no text to read (a scan?)" : isAssistReadableFile(file.name) ? "attached, but more than one message can carry, so the assistant is not reading it" : "attached to the report \u2014 the assistant can't read this kind of file";
|
|
3398
|
+
return /* @__PURE__ */ jsxs3(
|
|
3399
|
+
"div",
|
|
3400
|
+
{
|
|
3401
|
+
"data-gg-assist-file": "",
|
|
3402
|
+
"data-gg-assist-file-read": read ? "" : void 0,
|
|
3403
|
+
"data-gg-assist-file-reading": pdf && file.reading ? "" : void 0,
|
|
3404
|
+
title: `${file.name} \u2014 ${why}`,
|
|
3405
|
+
style: {
|
|
3406
|
+
position: "relative",
|
|
3407
|
+
height: "40px",
|
|
3408
|
+
maxWidth: "170px",
|
|
3409
|
+
display: "flex",
|
|
3410
|
+
alignItems: "center",
|
|
3411
|
+
gap: "6px",
|
|
3412
|
+
padding: "0 10px",
|
|
3413
|
+
borderRadius: "8px",
|
|
3414
|
+
border: `1px solid ${read ? t.accent : t.inputBorder}`,
|
|
3415
|
+
opacity: read || pdf && file.reading ? 1 : 0.55,
|
|
3416
|
+
boxSizing: "border-box",
|
|
3417
|
+
flexShrink: 0
|
|
3418
|
+
},
|
|
3419
|
+
children: [
|
|
3420
|
+
pdf && file.reading ? /* @__PURE__ */ jsx3(
|
|
3421
|
+
"span",
|
|
3422
|
+
{
|
|
3423
|
+
role: "status",
|
|
3424
|
+
"aria-label": "Reading this PDF",
|
|
3425
|
+
style: {
|
|
3426
|
+
width: "12px",
|
|
3427
|
+
height: "12px",
|
|
3428
|
+
flexShrink: 0,
|
|
3429
|
+
borderRadius: "50%",
|
|
3430
|
+
border: `1.5px solid ${t.inputBorder}`,
|
|
3431
|
+
borderTopColor: t.accent,
|
|
3432
|
+
boxSizing: "border-box",
|
|
3433
|
+
animation: "gg-spin .8s linear infinite"
|
|
3316
3434
|
}
|
|
3317
|
-
|
|
3318
|
-
}
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3435
|
+
}
|
|
3436
|
+
) : /* @__PURE__ */ jsx3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx3(
|
|
3437
|
+
"path",
|
|
3438
|
+
{
|
|
3439
|
+
d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6",
|
|
3440
|
+
stroke: t.textMuted,
|
|
3441
|
+
strokeWidth: "1.5",
|
|
3442
|
+
strokeLinecap: "round",
|
|
3443
|
+
strokeLinejoin: "round"
|
|
3444
|
+
}
|
|
3445
|
+
) }),
|
|
3446
|
+
/* @__PURE__ */ jsx3(
|
|
3447
|
+
"span",
|
|
3448
|
+
{
|
|
3449
|
+
style: {
|
|
3450
|
+
fontSize: "11.5px",
|
|
3451
|
+
color: t.text,
|
|
3452
|
+
overflow: "hidden",
|
|
3453
|
+
textOverflow: "ellipsis",
|
|
3454
|
+
whiteSpace: "nowrap"
|
|
3455
|
+
},
|
|
3456
|
+
children: file.name
|
|
3457
|
+
}
|
|
3458
|
+
),
|
|
3459
|
+
onRemoveFile && /* @__PURE__ */ jsx3(
|
|
3460
|
+
"button",
|
|
3461
|
+
{
|
|
3462
|
+
type: "button",
|
|
3463
|
+
"data-gg-assist-remove-file": "",
|
|
3464
|
+
"aria-label": `Remove file ${file.name}`,
|
|
3465
|
+
title: "Remove this file",
|
|
3466
|
+
onClick: () => {
|
|
3467
|
+
stopAutoFile("changed attachments");
|
|
3468
|
+
logEvent("file_removed", read ? "read" : "not read");
|
|
3469
|
+
onRemoveFile(i);
|
|
3470
|
+
},
|
|
3471
|
+
style: {
|
|
3472
|
+
position: "absolute",
|
|
3473
|
+
top: "-13px",
|
|
3474
|
+
right: "-13px",
|
|
3475
|
+
width: "32px",
|
|
3476
|
+
height: "32px",
|
|
3477
|
+
border: "none",
|
|
3478
|
+
background: "transparent",
|
|
3479
|
+
padding: 0,
|
|
3480
|
+
cursor: "pointer",
|
|
3481
|
+
display: "flex",
|
|
3482
|
+
alignItems: "center",
|
|
3483
|
+
justifyContent: "center",
|
|
3484
|
+
borderRadius: "50%"
|
|
3485
|
+
},
|
|
3486
|
+
children: /* @__PURE__ */ jsx3(
|
|
3487
|
+
"span",
|
|
3488
|
+
{
|
|
3489
|
+
"aria-hidden": "true",
|
|
3490
|
+
style: {
|
|
3491
|
+
width: "20px",
|
|
3492
|
+
height: "20px",
|
|
3493
|
+
boxSizing: "border-box",
|
|
3494
|
+
borderRadius: "50%",
|
|
3495
|
+
border: `2px solid ${t.bg}`,
|
|
3496
|
+
background: "#ef4444",
|
|
3497
|
+
color: "#fff",
|
|
3498
|
+
display: "flex",
|
|
3499
|
+
alignItems: "center",
|
|
3500
|
+
justifyContent: "center"
|
|
3501
|
+
},
|
|
3502
|
+
children: /* @__PURE__ */ jsx3("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx3(
|
|
3503
|
+
"path",
|
|
3504
|
+
{
|
|
3505
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
3506
|
+
stroke: "currentColor",
|
|
3507
|
+
strokeWidth: "1.6",
|
|
3508
|
+
strokeLinecap: "round"
|
|
3509
|
+
}
|
|
3510
|
+
) })
|
|
3511
|
+
}
|
|
3512
|
+
)
|
|
3513
|
+
}
|
|
3514
|
+
)
|
|
3515
|
+
]
|
|
3516
|
+
},
|
|
3517
|
+
`file-${i}-${file.name}`
|
|
3518
|
+
);
|
|
3519
|
+
}),
|
|
3520
|
+
onAddFiles && /* @__PURE__ */ jsxs3(
|
|
3521
|
+
"label",
|
|
3330
3522
|
{
|
|
3331
|
-
"data-gg-assist-
|
|
3332
|
-
"
|
|
3333
|
-
title: `${file.name} \u2014 ${why}`,
|
|
3523
|
+
"data-gg-assist-attach": "",
|
|
3524
|
+
title: "Attach an image or a file (html, json, log\u2026) \u2014 or paste one",
|
|
3334
3525
|
style: {
|
|
3335
|
-
|
|
3526
|
+
width: "40px",
|
|
3336
3527
|
height: "40px",
|
|
3337
|
-
maxWidth: "170px",
|
|
3338
|
-
display: "flex",
|
|
3339
|
-
alignItems: "center",
|
|
3340
|
-
gap: "6px",
|
|
3341
|
-
padding: "0 10px",
|
|
3342
3528
|
borderRadius: "8px",
|
|
3343
|
-
border: `1px
|
|
3344
|
-
|
|
3345
|
-
|
|
3529
|
+
border: `1px dashed ${t.inputBorder}`,
|
|
3530
|
+
display: "inline-flex",
|
|
3531
|
+
alignItems: "center",
|
|
3532
|
+
justifyContent: "center",
|
|
3533
|
+
color: t.textMuted,
|
|
3534
|
+
fontSize: "18px",
|
|
3535
|
+
cursor: "pointer",
|
|
3346
3536
|
flexShrink: 0
|
|
3347
3537
|
},
|
|
3348
3538
|
children: [
|
|
3349
|
-
|
|
3350
|
-
"path",
|
|
3351
|
-
{
|
|
3352
|
-
d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6",
|
|
3353
|
-
stroke: t.textMuted,
|
|
3354
|
-
strokeWidth: "1.5",
|
|
3355
|
-
strokeLinecap: "round",
|
|
3356
|
-
strokeLinejoin: "round"
|
|
3357
|
-
}
|
|
3358
|
-
) }),
|
|
3539
|
+
"+",
|
|
3359
3540
|
/* @__PURE__ */ jsx3(
|
|
3360
|
-
"
|
|
3361
|
-
{
|
|
3362
|
-
style: {
|
|
3363
|
-
fontSize: "11.5px",
|
|
3364
|
-
color: t.text,
|
|
3365
|
-
overflow: "hidden",
|
|
3366
|
-
textOverflow: "ellipsis",
|
|
3367
|
-
whiteSpace: "nowrap"
|
|
3368
|
-
},
|
|
3369
|
-
children: file.name
|
|
3370
|
-
}
|
|
3371
|
-
),
|
|
3372
|
-
onRemoveFile && /* @__PURE__ */ jsx3(
|
|
3373
|
-
"button",
|
|
3541
|
+
"input",
|
|
3374
3542
|
{
|
|
3375
|
-
type: "
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
height: "32px",
|
|
3390
|
-
border: "none",
|
|
3391
|
-
background: "transparent",
|
|
3392
|
-
padding: 0,
|
|
3393
|
-
cursor: "pointer",
|
|
3394
|
-
display: "flex",
|
|
3395
|
-
alignItems: "center",
|
|
3396
|
-
justifyContent: "center",
|
|
3397
|
-
borderRadius: "50%"
|
|
3398
|
-
},
|
|
3399
|
-
children: /* @__PURE__ */ jsx3(
|
|
3400
|
-
"span",
|
|
3401
|
-
{
|
|
3402
|
-
"aria-hidden": "true",
|
|
3403
|
-
style: {
|
|
3404
|
-
width: "20px",
|
|
3405
|
-
height: "20px",
|
|
3406
|
-
boxSizing: "border-box",
|
|
3407
|
-
borderRadius: "50%",
|
|
3408
|
-
border: `2px solid ${t.bg}`,
|
|
3409
|
-
background: "#ef4444",
|
|
3410
|
-
color: "#fff",
|
|
3411
|
-
display: "flex",
|
|
3412
|
-
alignItems: "center",
|
|
3413
|
-
justifyContent: "center"
|
|
3414
|
-
},
|
|
3415
|
-
children: /* @__PURE__ */ jsx3("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx3(
|
|
3416
|
-
"path",
|
|
3417
|
-
{
|
|
3418
|
-
d: "M1 1L9 9M9 1L1 9",
|
|
3419
|
-
stroke: "currentColor",
|
|
3420
|
-
strokeWidth: "1.6",
|
|
3421
|
-
strokeLinecap: "round"
|
|
3422
|
-
}
|
|
3423
|
-
) })
|
|
3543
|
+
type: "file",
|
|
3544
|
+
accept: canReadPdf ? ASSIST_ATTACHMENT_ACCEPT_WITH_PDF : ASSIST_ATTACHMENT_ACCEPT,
|
|
3545
|
+
multiple: true,
|
|
3546
|
+
onChange: (e) => {
|
|
3547
|
+
var _a;
|
|
3548
|
+
const picked = Array.from((_a = e.target.files) != null ? _a : []);
|
|
3549
|
+
if (picked.length) {
|
|
3550
|
+
stopAutoFile("changed attachments");
|
|
3551
|
+
const images = picked.filter((f) => f.type.startsWith("image/")).length;
|
|
3552
|
+
if (images) logEvent("image_added", String(images));
|
|
3553
|
+
if (picked.length > images) {
|
|
3554
|
+
logEvent("file_added", String(picked.length - images));
|
|
3555
|
+
}
|
|
3556
|
+
onAddFiles(picked);
|
|
3424
3557
|
}
|
|
3425
|
-
|
|
3558
|
+
e.target.value = "";
|
|
3559
|
+
},
|
|
3560
|
+
style: { display: "none" }
|
|
3426
3561
|
}
|
|
3427
3562
|
)
|
|
3428
3563
|
]
|
|
3429
|
-
}
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
style: {
|
|
3439
|
-
width: "40px",
|
|
3440
|
-
height: "40px",
|
|
3441
|
-
borderRadius: "8px",
|
|
3442
|
-
border: `1px dashed ${t.inputBorder}`,
|
|
3443
|
-
display: "inline-flex",
|
|
3444
|
-
alignItems: "center",
|
|
3445
|
-
justifyContent: "center",
|
|
3446
|
-
color: t.textMuted,
|
|
3447
|
-
fontSize: "18px",
|
|
3448
|
-
cursor: "pointer",
|
|
3449
|
-
flexShrink: 0
|
|
3450
|
-
},
|
|
3451
|
-
children: [
|
|
3452
|
-
"+",
|
|
3453
|
-
/* @__PURE__ */ jsx3(
|
|
3454
|
-
"input",
|
|
3455
|
-
{
|
|
3456
|
-
type: "file",
|
|
3457
|
-
accept: ASSIST_ATTACHMENT_ACCEPT,
|
|
3458
|
-
multiple: true,
|
|
3459
|
-
onChange: (e) => {
|
|
3460
|
-
var _a;
|
|
3461
|
-
const picked = Array.from((_a = e.target.files) != null ? _a : []);
|
|
3462
|
-
if (picked.length) {
|
|
3463
|
-
stopAutoFile("changed attachments");
|
|
3464
|
-
const images = picked.filter((f) => f.type.startsWith("image/")).length;
|
|
3465
|
-
if (images) logEvent("image_added", String(images));
|
|
3466
|
-
if (picked.length > images) {
|
|
3467
|
-
logEvent("file_added", String(picked.length - images));
|
|
3468
|
-
}
|
|
3469
|
-
onAddFiles(picked);
|
|
3470
|
-
}
|
|
3471
|
-
e.target.value = "";
|
|
3472
|
-
},
|
|
3473
|
-
style: { display: "none" }
|
|
3474
|
-
}
|
|
3475
|
-
)
|
|
3476
|
-
]
|
|
3477
|
-
}
|
|
3478
|
-
),
|
|
3479
|
-
readShots.size < screenshots.length && /* @__PURE__ */ jsxs3("span", { style: { color: t.textMuted, fontSize: "11px" }, children: [
|
|
3480
|
-
readShots.size,
|
|
3481
|
-
" of ",
|
|
3482
|
-
screenshots.length,
|
|
3483
|
-
" read"
|
|
3484
|
-
] })
|
|
3485
|
-
]
|
|
3486
|
-
}
|
|
3487
|
-
),
|
|
3488
|
-
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
3489
|
-
/* @__PURE__ */ jsx3(
|
|
3490
|
-
"textarea",
|
|
3491
|
-
{
|
|
3492
|
-
value: input,
|
|
3493
|
-
onChange: (e) => {
|
|
3494
|
-
stopAutoFile("typing a change");
|
|
3495
|
-
setInput(e.target.value);
|
|
3496
|
-
},
|
|
3497
|
-
onKeyDown: (e) => {
|
|
3498
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
3499
|
-
e.preventDefault();
|
|
3500
|
-
sendTyped(input);
|
|
3501
|
-
}
|
|
3502
|
-
},
|
|
3503
|
-
placeholder: phase === "draft" ? "Anything to change? Tell me here\u2026" : "Type your answer\u2026",
|
|
3504
|
-
rows: 1,
|
|
3505
|
-
disabled: busy,
|
|
3506
|
-
autoFocus: true,
|
|
3507
|
-
style: {
|
|
3508
|
-
flex: 1,
|
|
3509
|
-
minHeight: "42px",
|
|
3510
|
-
maxHeight: "120px",
|
|
3511
|
-
padding: "11px 12px",
|
|
3512
|
-
borderRadius: "10px",
|
|
3513
|
-
border: `1px solid ${t.inputBorder}`,
|
|
3514
|
-
backgroundColor: t.inputBg,
|
|
3515
|
-
color: t.text,
|
|
3516
|
-
fontSize: "13px",
|
|
3517
|
-
lineHeight: 1.4,
|
|
3518
|
-
fontFamily: "inherit",
|
|
3519
|
-
resize: "none",
|
|
3520
|
-
outline: "none",
|
|
3521
|
-
boxSizing: "border-box"
|
|
3522
|
-
}
|
|
3564
|
+
}
|
|
3565
|
+
),
|
|
3566
|
+
readShots.size < screenshots.length && /* @__PURE__ */ jsxs3("span", { style: { color: t.textMuted, fontSize: "11px" }, children: [
|
|
3567
|
+
readShots.size,
|
|
3568
|
+
" of ",
|
|
3569
|
+
screenshots.length,
|
|
3570
|
+
" read"
|
|
3571
|
+
] })
|
|
3572
|
+
]
|
|
3523
3573
|
}
|
|
3524
3574
|
),
|
|
3525
|
-
/* @__PURE__ */
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3575
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
3576
|
+
/* @__PURE__ */ jsx3(
|
|
3577
|
+
"textarea",
|
|
3578
|
+
{
|
|
3579
|
+
ref: composerRef,
|
|
3580
|
+
value: input,
|
|
3581
|
+
onChange: (e) => {
|
|
3582
|
+
stopAutoFile("typing a change");
|
|
3583
|
+
setInput(e.target.value);
|
|
3584
|
+
},
|
|
3585
|
+
onKeyDown: (e) => {
|
|
3586
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
3587
|
+
e.preventDefault();
|
|
3588
|
+
sendTyped(input);
|
|
3589
|
+
}
|
|
3590
|
+
},
|
|
3591
|
+
placeholder: phase === "draft" ? "Anything to change? Tell me here\u2026" : "Type your answer\u2026",
|
|
3592
|
+
rows: 3,
|
|
3593
|
+
disabled: busy,
|
|
3594
|
+
autoFocus: true,
|
|
3595
|
+
style: {
|
|
3596
|
+
flex: 1,
|
|
3597
|
+
minHeight: "72px",
|
|
3598
|
+
maxHeight: "220px",
|
|
3599
|
+
padding: "11px 12px",
|
|
3600
|
+
borderRadius: "10px",
|
|
3601
|
+
border: `1px solid ${t.inputBorder}`,
|
|
3602
|
+
backgroundColor: t.inputBg,
|
|
3603
|
+
color: t.text,
|
|
3604
|
+
fontSize: "13px",
|
|
3605
|
+
lineHeight: 1.4,
|
|
3606
|
+
fontFamily: "inherit",
|
|
3607
|
+
resize: "none",
|
|
3608
|
+
outline: "none",
|
|
3609
|
+
boxSizing: "border-box"
|
|
3552
3610
|
}
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3611
|
+
}
|
|
3612
|
+
),
|
|
3613
|
+
/* @__PURE__ */ jsx3(
|
|
3614
|
+
"button",
|
|
3615
|
+
{
|
|
3616
|
+
type: "button",
|
|
3617
|
+
"data-gg-sheet-send": "",
|
|
3618
|
+
onClick: () => sendTyped(input),
|
|
3619
|
+
disabled: busy || !input.trim(),
|
|
3620
|
+
"aria-label": "Send message",
|
|
3621
|
+
"data-gg-send-message": "",
|
|
3622
|
+
style: {
|
|
3623
|
+
flexShrink: 0,
|
|
3624
|
+
width: "42px",
|
|
3625
|
+
height: "42px",
|
|
3626
|
+
borderRadius: "10px",
|
|
3627
|
+
border: "none",
|
|
3628
|
+
display: "inline-flex",
|
|
3629
|
+
alignItems: "center",
|
|
3630
|
+
justifyContent: "center",
|
|
3631
|
+
backgroundColor: busy || !input.trim() ? t.bgSecondary : t.accent,
|
|
3632
|
+
color: busy || !input.trim() ? t.textMuted : t.accentText,
|
|
3633
|
+
cursor: busy || !input.trim() ? "default" : "pointer"
|
|
3634
|
+
},
|
|
3635
|
+
children: /* @__PURE__ */ jsx3("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
|
|
3636
|
+
"path",
|
|
3637
|
+
{
|
|
3638
|
+
d: "M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z",
|
|
3639
|
+
fill: "currentColor"
|
|
3640
|
+
}
|
|
3641
|
+
) })
|
|
3642
|
+
}
|
|
3643
|
+
)
|
|
3644
|
+
] })
|
|
3556
3645
|
] }),
|
|
3557
3646
|
phase === "draft" && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
3558
3647
|
validationError && /* @__PURE__ */ jsx3(
|
|
@@ -3566,7 +3655,7 @@ function AssistSheet({
|
|
|
3566
3655
|
children: validationError
|
|
3567
3656
|
}
|
|
3568
3657
|
),
|
|
3569
|
-
autoFileLeft !== null ? (
|
|
3658
|
+
similarSlot ? similarSlot : autoFileLeft !== null ? (
|
|
3570
3659
|
// #402: "Yes, that's it" was the confirmation. The draft
|
|
3571
3660
|
// files itself unless they stop it — the bar shows how
|
|
3572
3661
|
// long is left, the button sends now, the × on its right
|
|
@@ -4622,6 +4711,7 @@ function ReportDialog({
|
|
|
4622
4711
|
enhanceText: enhanceText2,
|
|
4623
4712
|
assist,
|
|
4624
4713
|
findSimilarIssues: findSimilarIssues2,
|
|
4714
|
+
readFile,
|
|
4625
4715
|
assistContext = null,
|
|
4626
4716
|
transcribeAudio: transcribeAudio2,
|
|
4627
4717
|
types,
|
|
@@ -4675,6 +4765,15 @@ function ReportDialog({
|
|
|
4675
4765
|
const pendingShotRef = useRef4(null);
|
|
4676
4766
|
const openGenRef = useRef4(0);
|
|
4677
4767
|
const [attachments, setAttachments] = useState4([]);
|
|
4768
|
+
const [pdfTexts, setPdfTexts] = useState4({});
|
|
4769
|
+
const heldFiles = useMemo2(
|
|
4770
|
+
() => attachments.map((a) => {
|
|
4771
|
+
const read = pdfTexts[heldFileKey(a)];
|
|
4772
|
+
if (!read) return a;
|
|
4773
|
+
return "reading" in read ? { ...a, reading: true } : { ...a, text: read.text, ...read.tooLarge ? { tooLarge: true } : {} };
|
|
4774
|
+
}),
|
|
4775
|
+
[attachments, pdfTexts]
|
|
4776
|
+
);
|
|
4678
4777
|
const [previewIndex, setPreviewIndex] = useState4(null);
|
|
4679
4778
|
const [annotatingIndex, setAnnotatingIndex] = useState4(null);
|
|
4680
4779
|
const [previewZoomed, setPreviewZoomed] = useState4(false);
|
|
@@ -4835,10 +4934,16 @@ function ReportDialog({
|
|
|
4835
4934
|
files.filter((file) => !file.type.startsWith("image/")).forEach((file) => {
|
|
4836
4935
|
const reader = new FileReader();
|
|
4837
4936
|
reader.onload = () => {
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
]);
|
|
4937
|
+
const dataUrl = reader.result;
|
|
4938
|
+
setAttachments((prev) => [...prev, { name: file.name, size: file.size, dataUrl }]);
|
|
4939
|
+
const key = heldFileKey(file);
|
|
4940
|
+
if (!readFile || !isPdfFile(file.name) || pdfTexts[key]) return;
|
|
4941
|
+
if (file.size > MAX_READABLE_PDF_BYTES) {
|
|
4942
|
+
setPdfTexts((prev) => ({ ...prev, [key]: { text: null, tooLarge: true } }));
|
|
4943
|
+
return;
|
|
4944
|
+
}
|
|
4945
|
+
setPdfTexts((prev) => ({ ...prev, [key]: { reading: true } }));
|
|
4946
|
+
void Promise.resolve().then(() => readFile({ name: file.name, dataUrl })).catch(() => null).then((text) => setPdfTexts((prev) => ({ ...prev, [key]: { text } })));
|
|
4842
4947
|
};
|
|
4843
4948
|
reader.readAsDataURL(file);
|
|
4844
4949
|
});
|
|
@@ -5274,6 +5379,10 @@ function ReportDialog({
|
|
|
5274
5379
|
stopListeningAndTranscribe();
|
|
5275
5380
|
}
|
|
5276
5381
|
};
|
|
5382
|
+
useEffect4(() => {
|
|
5383
|
+
setSimilarIssues(null);
|
|
5384
|
+
setPickedSimilar(null);
|
|
5385
|
+
}, [description]);
|
|
5277
5386
|
const handleSubmit = async (opts) => {
|
|
5278
5387
|
var _a2, _b, _c;
|
|
5279
5388
|
try {
|
|
@@ -5314,11 +5423,17 @@ function ReportDialog({
|
|
|
5314
5423
|
}
|
|
5315
5424
|
const duplicateOf = (_a2 = opts == null ? void 0 : opts.duplicateOf) != null ? _a2 : duplicateIssueNumber;
|
|
5316
5425
|
const attachKind = (opts == null ? void 0 : opts.duplicateOf) ? (_b = opts.kind) != null ? _b : "duplicate" : duplicateKind;
|
|
5317
|
-
if (findSimilarIssues2 && !(opts == null ? void 0 : opts.skipSimilar) && !duplicateOf
|
|
5426
|
+
if (findSimilarIssues2 && !(opts == null ? void 0 : opts.skipSimilar) && !duplicateOf) {
|
|
5427
|
+
const similarFiles = filesForSimilar(
|
|
5428
|
+
heldFiles,
|
|
5429
|
+
MAX_SIMILAR_FILE_CHARS,
|
|
5430
|
+
MAX_SIMILAR_FILES_TOTAL_CHARS
|
|
5431
|
+
);
|
|
5318
5432
|
setIsSubmitting(true);
|
|
5319
5433
|
setCheckingSimilar(true);
|
|
5320
5434
|
const matches = await Promise.race([
|
|
5321
|
-
|
|
5435
|
+
// A PDF still being read is left out rather than waited for.
|
|
5436
|
+
(similarFiles.length ? findSimilarIssues2(description.trim(), similarFiles) : findSimilarIssues2(description.trim())).catch(() => null),
|
|
5322
5437
|
new Promise((resolve) => setTimeout(() => resolve(null), SIMILAR_WAIT_MS))
|
|
5323
5438
|
]);
|
|
5324
5439
|
setCheckingSimilar(false);
|
|
@@ -5350,6 +5465,8 @@ function ReportDialog({
|
|
|
5350
5465
|
if (duplicateOf) {
|
|
5351
5466
|
metadata.duplicateIssueNumber = String(duplicateOf);
|
|
5352
5467
|
if (attachKind === "related") metadata.duplicateKind = "related";
|
|
5468
|
+
} else if (opts == null ? void 0 : opts.possiblyRelated) {
|
|
5469
|
+
metadata.possiblyRelatedIssue = String(opts.possiblyRelated);
|
|
5353
5470
|
}
|
|
5354
5471
|
if (aiConversationId) {
|
|
5355
5472
|
metadata.aiConversationId = aiConversationId;
|
|
@@ -5363,7 +5480,9 @@ function ReportDialog({
|
|
|
5363
5480
|
Object.keys(metadata).length > 0 ? metadata : void 0
|
|
5364
5481
|
);
|
|
5365
5482
|
if (result) {
|
|
5366
|
-
setAddedToIssue(
|
|
5483
|
+
setAddedToIssue(
|
|
5484
|
+
duplicateOf && result.issueNumber === duplicateOf ? duplicateOf : result.status === "DUPLICATE" && result.issueNumber ? result.issueNumber : null
|
|
5485
|
+
);
|
|
5367
5486
|
setAddedAsRelated(!!duplicateOf && result.issueNumber === duplicateOf && attachKind === "related");
|
|
5368
5487
|
const queued = result.status === "QUEUED" && !!result.message;
|
|
5369
5488
|
setQueuedMessage(queued ? (_c = result.message) != null ? _c : null : null);
|
|
@@ -5371,6 +5490,7 @@ function ReportDialog({
|
|
|
5371
5490
|
setDescription("");
|
|
5372
5491
|
setScreenshots([]);
|
|
5373
5492
|
setAttachments([]);
|
|
5493
|
+
setPdfTexts({});
|
|
5374
5494
|
setAiConversationId(null);
|
|
5375
5495
|
setIssueTitle("");
|
|
5376
5496
|
setDuplicateIssueNumber(null);
|
|
@@ -5391,6 +5511,220 @@ function ReportDialog({
|
|
|
5391
5511
|
setAttachingTo(null);
|
|
5392
5512
|
}
|
|
5393
5513
|
};
|
|
5514
|
+
const similarCard = similarIssues ? /* @__PURE__ */ jsxs5(
|
|
5515
|
+
"div",
|
|
5516
|
+
{
|
|
5517
|
+
"data-gg-similar": "",
|
|
5518
|
+
style: {
|
|
5519
|
+
marginTop: "12px",
|
|
5520
|
+
display: "flex",
|
|
5521
|
+
flexDirection: "column",
|
|
5522
|
+
gap: "10px",
|
|
5523
|
+
padding: "12px",
|
|
5524
|
+
borderRadius: "10px",
|
|
5525
|
+
border: "1px solid rgba(245,158,11,0.4)",
|
|
5526
|
+
backgroundColor: "rgba(245,158,11,0.08)"
|
|
5527
|
+
},
|
|
5528
|
+
children: [
|
|
5529
|
+
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
|
|
5530
|
+
/* @__PURE__ */ jsx5("span", { style: { color: t.text, fontWeight: 600, fontSize: "13px" }, children: "Our team may already have this, or something close" }),
|
|
5531
|
+
/* @__PURE__ */ jsx5("span", { style: { color: t.textMuted, fontSize: "12px", lineHeight: 1.5 }, children: similarIssues.length > 1 ? "Pick the one that matches. Same problem, or a different request for the same feature \u2014 it's added to that issue, so the team has it in one place." : "Same problem, or a different request for the same feature? Pick it \u2014 it's added to that issue, so the team has it in one place." })
|
|
5532
|
+
] }),
|
|
5533
|
+
/* @__PURE__ */ jsx5(
|
|
5534
|
+
"div",
|
|
5535
|
+
{
|
|
5536
|
+
role: "radiogroup",
|
|
5537
|
+
"aria-label": "Existing issues",
|
|
5538
|
+
style: { display: "flex", flexDirection: "column", gap: "6px" },
|
|
5539
|
+
children: similarIssues.map((issue) => {
|
|
5540
|
+
const picked = pickedSimilar === issue.number;
|
|
5541
|
+
return /* @__PURE__ */ jsxs5(
|
|
5542
|
+
"button",
|
|
5543
|
+
{
|
|
5544
|
+
type: "button",
|
|
5545
|
+
role: "radio",
|
|
5546
|
+
"aria-checked": picked,
|
|
5547
|
+
disabled: isSubmitting,
|
|
5548
|
+
onClick: () => setPickedSimilar(issue.number),
|
|
5549
|
+
style: {
|
|
5550
|
+
display: "flex",
|
|
5551
|
+
alignItems: "flex-start",
|
|
5552
|
+
gap: "10px",
|
|
5553
|
+
width: "100%",
|
|
5554
|
+
minHeight: "44px",
|
|
5555
|
+
padding: "9px 10px",
|
|
5556
|
+
borderRadius: "8px",
|
|
5557
|
+
border: `1px solid ${picked ? t.accent : t.border}`,
|
|
5558
|
+
boxShadow: picked ? `0 0 0 1px ${t.accent}` : "none",
|
|
5559
|
+
backgroundColor: t.bg,
|
|
5560
|
+
color: t.text,
|
|
5561
|
+
textAlign: "left",
|
|
5562
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
5563
|
+
fontFamily: "inherit"
|
|
5564
|
+
},
|
|
5565
|
+
children: [
|
|
5566
|
+
/* @__PURE__ */ jsx5(
|
|
5567
|
+
"span",
|
|
5568
|
+
{
|
|
5569
|
+
"aria-hidden": "true",
|
|
5570
|
+
style: {
|
|
5571
|
+
flexShrink: 0,
|
|
5572
|
+
marginTop: "2px",
|
|
5573
|
+
width: "14px",
|
|
5574
|
+
height: "14px",
|
|
5575
|
+
boxSizing: "border-box",
|
|
5576
|
+
borderRadius: "50%",
|
|
5577
|
+
border: `2px solid ${picked ? t.accent : t.textMuted}`,
|
|
5578
|
+
backgroundColor: picked ? t.accent : "transparent",
|
|
5579
|
+
boxShadow: picked ? `inset 0 0 0 2px ${t.bg}` : "none"
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
),
|
|
5583
|
+
/* @__PURE__ */ jsxs5(
|
|
5584
|
+
"span",
|
|
5585
|
+
{
|
|
5586
|
+
style: {
|
|
5587
|
+
display: "flex",
|
|
5588
|
+
flexDirection: "column",
|
|
5589
|
+
gap: "3px",
|
|
5590
|
+
minWidth: 0
|
|
5591
|
+
},
|
|
5592
|
+
children: [
|
|
5593
|
+
/* @__PURE__ */ jsxs5(
|
|
5594
|
+
"span",
|
|
5595
|
+
{
|
|
5596
|
+
title: issue.title,
|
|
5597
|
+
style: {
|
|
5598
|
+
fontSize: "12.5px",
|
|
5599
|
+
lineHeight: 1.45,
|
|
5600
|
+
wordBreak: "break-word",
|
|
5601
|
+
overflow: "hidden",
|
|
5602
|
+
display: "-webkit-box",
|
|
5603
|
+
WebkitLineClamp: 3,
|
|
5604
|
+
WebkitBoxOrient: "vertical"
|
|
5605
|
+
},
|
|
5606
|
+
children: [
|
|
5607
|
+
/* @__PURE__ */ jsxs5("span", { style: { color: t.textMuted, fontWeight: 600 }, children: [
|
|
5608
|
+
"#",
|
|
5609
|
+
issue.number
|
|
5610
|
+
] }),
|
|
5611
|
+
" ",
|
|
5612
|
+
issue.title
|
|
5613
|
+
]
|
|
5614
|
+
}
|
|
5615
|
+
),
|
|
5616
|
+
issue.status && /* @__PURE__ */ jsx5("span", { style: { fontSize: "11.5px", color: t.textMuted }, children: issue.status })
|
|
5617
|
+
]
|
|
5618
|
+
}
|
|
5619
|
+
)
|
|
5620
|
+
]
|
|
5621
|
+
},
|
|
5622
|
+
issue.number
|
|
5623
|
+
);
|
|
5624
|
+
})
|
|
5625
|
+
}
|
|
5626
|
+
),
|
|
5627
|
+
/* @__PURE__ */ jsx5(
|
|
5628
|
+
"button",
|
|
5629
|
+
{
|
|
5630
|
+
type: "button",
|
|
5631
|
+
disabled: isSubmitting || !pickedSimilar,
|
|
5632
|
+
onClick: () => {
|
|
5633
|
+
if (!pickedSimilar) return;
|
|
5634
|
+
setAttachingTo(pickedSimilar);
|
|
5635
|
+
setDuplicateIssueNumber(pickedSimilar);
|
|
5636
|
+
setDuplicateKind("duplicate");
|
|
5637
|
+
void handleSubmit({ duplicateOf: pickedSimilar, kind: "duplicate" });
|
|
5638
|
+
},
|
|
5639
|
+
style: {
|
|
5640
|
+
width: "100%",
|
|
5641
|
+
minHeight: "40px",
|
|
5642
|
+
padding: "10px",
|
|
5643
|
+
borderRadius: "8px",
|
|
5644
|
+
border: "none",
|
|
5645
|
+
backgroundColor: isSubmitting || !pickedSimilar ? t.bgSecondary : t.accent,
|
|
5646
|
+
color: isSubmitting || !pickedSimilar ? t.textMuted : t.accentText,
|
|
5647
|
+
fontSize: "14px",
|
|
5648
|
+
fontWeight: 600,
|
|
5649
|
+
cursor: isSubmitting || !pickedSimilar ? "not-allowed" : "pointer",
|
|
5650
|
+
fontFamily: "inherit"
|
|
5651
|
+
},
|
|
5652
|
+
children: typeof attachingTo === "number" && duplicateKind !== "related" ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
5653
|
+
/* @__PURE__ */ jsx5(ButtonSpinner, {}),
|
|
5654
|
+
"Adding to #",
|
|
5655
|
+
attachingTo,
|
|
5656
|
+
"\u2026"
|
|
5657
|
+
] }) : pickedSimilar ? `Add to #${pickedSimilar}` : "Pick the matching issue"
|
|
5658
|
+
}
|
|
5659
|
+
),
|
|
5660
|
+
pickedSimilar && /* @__PURE__ */ jsx5(
|
|
5661
|
+
"button",
|
|
5662
|
+
{
|
|
5663
|
+
type: "button",
|
|
5664
|
+
disabled: isSubmitting,
|
|
5665
|
+
onClick: () => {
|
|
5666
|
+
setAttachingTo(pickedSimilar);
|
|
5667
|
+
setDuplicateIssueNumber(pickedSimilar);
|
|
5668
|
+
setDuplicateKind("related");
|
|
5669
|
+
void handleSubmit({ duplicateOf: pickedSimilar, kind: "related" });
|
|
5670
|
+
},
|
|
5671
|
+
style: {
|
|
5672
|
+
width: "100%",
|
|
5673
|
+
minHeight: "40px",
|
|
5674
|
+
marginTop: "-4px",
|
|
5675
|
+
padding: "9px 10px",
|
|
5676
|
+
borderRadius: "8px",
|
|
5677
|
+
border: "1px solid rgba(245,158,11,0.4)",
|
|
5678
|
+
backgroundColor: "transparent",
|
|
5679
|
+
color: isSubmitting ? t.textMuted : t.text,
|
|
5680
|
+
fontSize: "13px",
|
|
5681
|
+
fontWeight: 600,
|
|
5682
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
5683
|
+
fontFamily: "inherit"
|
|
5684
|
+
},
|
|
5685
|
+
children: typeof attachingTo === "number" && duplicateKind === "related" ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
5686
|
+
/* @__PURE__ */ jsx5(ButtonSpinner, {}),
|
|
5687
|
+
"Adding to #",
|
|
5688
|
+
attachingTo,
|
|
5689
|
+
"\u2026"
|
|
5690
|
+
] }) : `Related request \u2014 add to #${pickedSimilar}`
|
|
5691
|
+
}
|
|
5692
|
+
),
|
|
5693
|
+
/* @__PURE__ */ jsx5(
|
|
5694
|
+
"button",
|
|
5695
|
+
{
|
|
5696
|
+
type: "button",
|
|
5697
|
+
disabled: isSubmitting,
|
|
5698
|
+
onClick: () => {
|
|
5699
|
+
var _a2;
|
|
5700
|
+
setAttachingTo("new");
|
|
5701
|
+
void handleSubmit({ skipSimilar: true, possiblyRelated: (_a2 = similarIssues[0]) == null ? void 0 : _a2.number });
|
|
5702
|
+
},
|
|
5703
|
+
style: {
|
|
5704
|
+
width: "100%",
|
|
5705
|
+
minHeight: "40px",
|
|
5706
|
+
marginTop: "-4px",
|
|
5707
|
+
padding: "8px",
|
|
5708
|
+
borderRadius: "8px",
|
|
5709
|
+
border: "none",
|
|
5710
|
+
backgroundColor: "transparent",
|
|
5711
|
+
color: isSubmitting ? t.textMuted : t.text,
|
|
5712
|
+
fontSize: "13px",
|
|
5713
|
+
fontWeight: 500,
|
|
5714
|
+
textDecoration: "underline",
|
|
5715
|
+
textUnderlineOffset: "3px",
|
|
5716
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
5717
|
+
fontFamily: "inherit"
|
|
5718
|
+
},
|
|
5719
|
+
children: attachingTo === "new" ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
5720
|
+
/* @__PURE__ */ jsx5(ButtonSpinner, {}),
|
|
5721
|
+
"Sending as new\u2026"
|
|
5722
|
+
] }) : "No, mine is different \u2014 send as new"
|
|
5723
|
+
}
|
|
5724
|
+
)
|
|
5725
|
+
]
|
|
5726
|
+
}
|
|
5727
|
+
) : null;
|
|
5394
5728
|
if (!mounted) return null;
|
|
5395
5729
|
return /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
5396
5730
|
isOpen && createPortal3(
|
|
@@ -6929,224 +7263,7 @@ function ReportDialog({
|
|
|
6929
7263
|
children: validationError
|
|
6930
7264
|
}
|
|
6931
7265
|
),
|
|
6932
|
-
|
|
6933
|
-
// Same visual language as the assistant's "Our team is
|
|
6934
|
-
// already on this" card, so both routes to a duplicate
|
|
6935
|
-
// read as one feature.
|
|
6936
|
-
/* @__PURE__ */ jsxs5(
|
|
6937
|
-
"div",
|
|
6938
|
-
{
|
|
6939
|
-
"data-gg-similar": "",
|
|
6940
|
-
style: {
|
|
6941
|
-
marginTop: "12px",
|
|
6942
|
-
display: "flex",
|
|
6943
|
-
flexDirection: "column",
|
|
6944
|
-
gap: "10px",
|
|
6945
|
-
padding: "12px",
|
|
6946
|
-
borderRadius: "10px",
|
|
6947
|
-
border: "1px solid rgba(245,158,11,0.4)",
|
|
6948
|
-
backgroundColor: "rgba(245,158,11,0.08)"
|
|
6949
|
-
},
|
|
6950
|
-
children: [
|
|
6951
|
-
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
|
|
6952
|
-
/* @__PURE__ */ jsx5("span", { style: { color: t.text, fontWeight: 600, fontSize: "13px" }, children: "Our team may already have this, or something close" }),
|
|
6953
|
-
/* @__PURE__ */ jsx5("span", { style: { color: t.textMuted, fontSize: "12px", lineHeight: 1.5 }, children: similarIssues.length > 1 ? "Pick the one that matches. Same problem, or a different request for the same feature \u2014 it's added to that issue, so the team has it in one place." : "Same problem, or a different request for the same feature? Pick it \u2014 it's added to that issue, so the team has it in one place." })
|
|
6954
|
-
] }),
|
|
6955
|
-
/* @__PURE__ */ jsx5(
|
|
6956
|
-
"div",
|
|
6957
|
-
{
|
|
6958
|
-
role: "radiogroup",
|
|
6959
|
-
"aria-label": "Existing issues",
|
|
6960
|
-
style: { display: "flex", flexDirection: "column", gap: "6px" },
|
|
6961
|
-
children: similarIssues.map((issue) => {
|
|
6962
|
-
const picked = pickedSimilar === issue.number;
|
|
6963
|
-
return /* @__PURE__ */ jsxs5(
|
|
6964
|
-
"button",
|
|
6965
|
-
{
|
|
6966
|
-
type: "button",
|
|
6967
|
-
role: "radio",
|
|
6968
|
-
"aria-checked": picked,
|
|
6969
|
-
disabled: isSubmitting,
|
|
6970
|
-
onClick: () => setPickedSimilar(issue.number),
|
|
6971
|
-
style: {
|
|
6972
|
-
display: "flex",
|
|
6973
|
-
alignItems: "flex-start",
|
|
6974
|
-
gap: "10px",
|
|
6975
|
-
width: "100%",
|
|
6976
|
-
minHeight: "44px",
|
|
6977
|
-
padding: "9px 10px",
|
|
6978
|
-
borderRadius: "8px",
|
|
6979
|
-
border: `1px solid ${picked ? t.accent : t.border}`,
|
|
6980
|
-
boxShadow: picked ? `0 0 0 1px ${t.accent}` : "none",
|
|
6981
|
-
backgroundColor: t.bg,
|
|
6982
|
-
color: t.text,
|
|
6983
|
-
textAlign: "left",
|
|
6984
|
-
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
6985
|
-
fontFamily: "inherit"
|
|
6986
|
-
},
|
|
6987
|
-
children: [
|
|
6988
|
-
/* @__PURE__ */ jsx5(
|
|
6989
|
-
"span",
|
|
6990
|
-
{
|
|
6991
|
-
"aria-hidden": "true",
|
|
6992
|
-
style: {
|
|
6993
|
-
flexShrink: 0,
|
|
6994
|
-
marginTop: "2px",
|
|
6995
|
-
width: "14px",
|
|
6996
|
-
height: "14px",
|
|
6997
|
-
boxSizing: "border-box",
|
|
6998
|
-
borderRadius: "50%",
|
|
6999
|
-
border: `2px solid ${picked ? t.accent : t.textMuted}`,
|
|
7000
|
-
backgroundColor: picked ? t.accent : "transparent",
|
|
7001
|
-
boxShadow: picked ? `inset 0 0 0 2px ${t.bg}` : "none"
|
|
7002
|
-
}
|
|
7003
|
-
}
|
|
7004
|
-
),
|
|
7005
|
-
/* @__PURE__ */ jsxs5(
|
|
7006
|
-
"span",
|
|
7007
|
-
{
|
|
7008
|
-
style: {
|
|
7009
|
-
display: "flex",
|
|
7010
|
-
flexDirection: "column",
|
|
7011
|
-
gap: "3px",
|
|
7012
|
-
minWidth: 0
|
|
7013
|
-
},
|
|
7014
|
-
children: [
|
|
7015
|
-
/* @__PURE__ */ jsxs5(
|
|
7016
|
-
"span",
|
|
7017
|
-
{
|
|
7018
|
-
title: issue.title,
|
|
7019
|
-
style: {
|
|
7020
|
-
fontSize: "12.5px",
|
|
7021
|
-
lineHeight: 1.45,
|
|
7022
|
-
wordBreak: "break-word",
|
|
7023
|
-
overflow: "hidden",
|
|
7024
|
-
display: "-webkit-box",
|
|
7025
|
-
WebkitLineClamp: 3,
|
|
7026
|
-
WebkitBoxOrient: "vertical"
|
|
7027
|
-
},
|
|
7028
|
-
children: [
|
|
7029
|
-
/* @__PURE__ */ jsxs5("span", { style: { color: t.textMuted, fontWeight: 600 }, children: [
|
|
7030
|
-
"#",
|
|
7031
|
-
issue.number
|
|
7032
|
-
] }),
|
|
7033
|
-
" ",
|
|
7034
|
-
issue.title
|
|
7035
|
-
]
|
|
7036
|
-
}
|
|
7037
|
-
),
|
|
7038
|
-
issue.status && /* @__PURE__ */ jsx5("span", { style: { fontSize: "11.5px", color: t.textMuted }, children: issue.status })
|
|
7039
|
-
]
|
|
7040
|
-
}
|
|
7041
|
-
)
|
|
7042
|
-
]
|
|
7043
|
-
},
|
|
7044
|
-
issue.number
|
|
7045
|
-
);
|
|
7046
|
-
})
|
|
7047
|
-
}
|
|
7048
|
-
),
|
|
7049
|
-
/* @__PURE__ */ jsx5(
|
|
7050
|
-
"button",
|
|
7051
|
-
{
|
|
7052
|
-
type: "button",
|
|
7053
|
-
disabled: isSubmitting || !pickedSimilar,
|
|
7054
|
-
onClick: () => {
|
|
7055
|
-
if (!pickedSimilar) return;
|
|
7056
|
-
setAttachingTo(pickedSimilar);
|
|
7057
|
-
setDuplicateIssueNumber(pickedSimilar);
|
|
7058
|
-
setDuplicateKind("duplicate");
|
|
7059
|
-
void handleSubmit({ duplicateOf: pickedSimilar, kind: "duplicate" });
|
|
7060
|
-
},
|
|
7061
|
-
style: {
|
|
7062
|
-
width: "100%",
|
|
7063
|
-
minHeight: "40px",
|
|
7064
|
-
padding: "10px",
|
|
7065
|
-
borderRadius: "8px",
|
|
7066
|
-
border: "none",
|
|
7067
|
-
backgroundColor: isSubmitting || !pickedSimilar ? t.bgSecondary : t.accent,
|
|
7068
|
-
color: isSubmitting || !pickedSimilar ? t.textMuted : t.accentText,
|
|
7069
|
-
fontSize: "14px",
|
|
7070
|
-
fontWeight: 600,
|
|
7071
|
-
cursor: isSubmitting || !pickedSimilar ? "not-allowed" : "pointer",
|
|
7072
|
-
fontFamily: "inherit"
|
|
7073
|
-
},
|
|
7074
|
-
children: typeof attachingTo === "number" && duplicateKind !== "related" ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
7075
|
-
/* @__PURE__ */ jsx5(ButtonSpinner, {}),
|
|
7076
|
-
"Adding to #",
|
|
7077
|
-
attachingTo,
|
|
7078
|
-
"\u2026"
|
|
7079
|
-
] }) : pickedSimilar ? `Add to #${pickedSimilar}` : "Pick the matching issue"
|
|
7080
|
-
}
|
|
7081
|
-
),
|
|
7082
|
-
pickedSimilar && /* @__PURE__ */ jsx5(
|
|
7083
|
-
"button",
|
|
7084
|
-
{
|
|
7085
|
-
type: "button",
|
|
7086
|
-
disabled: isSubmitting,
|
|
7087
|
-
onClick: () => {
|
|
7088
|
-
setAttachingTo(pickedSimilar);
|
|
7089
|
-
setDuplicateIssueNumber(pickedSimilar);
|
|
7090
|
-
setDuplicateKind("related");
|
|
7091
|
-
void handleSubmit({ duplicateOf: pickedSimilar, kind: "related" });
|
|
7092
|
-
},
|
|
7093
|
-
style: {
|
|
7094
|
-
width: "100%",
|
|
7095
|
-
minHeight: "40px",
|
|
7096
|
-
marginTop: "-4px",
|
|
7097
|
-
padding: "9px 10px",
|
|
7098
|
-
borderRadius: "8px",
|
|
7099
|
-
border: "1px solid rgba(245,158,11,0.4)",
|
|
7100
|
-
backgroundColor: "transparent",
|
|
7101
|
-
color: isSubmitting ? t.textMuted : t.text,
|
|
7102
|
-
fontSize: "13px",
|
|
7103
|
-
fontWeight: 600,
|
|
7104
|
-
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
7105
|
-
fontFamily: "inherit"
|
|
7106
|
-
},
|
|
7107
|
-
children: typeof attachingTo === "number" && duplicateKind === "related" ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
7108
|
-
/* @__PURE__ */ jsx5(ButtonSpinner, {}),
|
|
7109
|
-
"Adding to #",
|
|
7110
|
-
attachingTo,
|
|
7111
|
-
"\u2026"
|
|
7112
|
-
] }) : `Related request \u2014 add to #${pickedSimilar}`
|
|
7113
|
-
}
|
|
7114
|
-
),
|
|
7115
|
-
/* @__PURE__ */ jsx5(
|
|
7116
|
-
"button",
|
|
7117
|
-
{
|
|
7118
|
-
type: "button",
|
|
7119
|
-
disabled: isSubmitting,
|
|
7120
|
-
onClick: () => {
|
|
7121
|
-
setAttachingTo("new");
|
|
7122
|
-
void handleSubmit({ skipSimilar: true });
|
|
7123
|
-
},
|
|
7124
|
-
style: {
|
|
7125
|
-
width: "100%",
|
|
7126
|
-
minHeight: "40px",
|
|
7127
|
-
marginTop: "-4px",
|
|
7128
|
-
padding: "8px",
|
|
7129
|
-
borderRadius: "8px",
|
|
7130
|
-
border: "none",
|
|
7131
|
-
backgroundColor: "transparent",
|
|
7132
|
-
color: isSubmitting ? t.textMuted : t.text,
|
|
7133
|
-
fontSize: "13px",
|
|
7134
|
-
fontWeight: 500,
|
|
7135
|
-
textDecoration: "underline",
|
|
7136
|
-
textUnderlineOffset: "3px",
|
|
7137
|
-
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
7138
|
-
fontFamily: "inherit"
|
|
7139
|
-
},
|
|
7140
|
-
children: attachingTo === "new" ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
7141
|
-
/* @__PURE__ */ jsx5(ButtonSpinner, {}),
|
|
7142
|
-
"Sending as new\u2026"
|
|
7143
|
-
] }) : "No, mine is different \u2014 send as new"
|
|
7144
|
-
}
|
|
7145
|
-
)
|
|
7146
|
-
]
|
|
7147
|
-
}
|
|
7148
|
-
)
|
|
7149
|
-
) : /* @__PURE__ */ jsx5(
|
|
7266
|
+
similarCard != null ? similarCard : /* @__PURE__ */ jsx5(
|
|
7150
7267
|
"button",
|
|
7151
7268
|
{
|
|
7152
7269
|
type: "button",
|
|
@@ -7445,7 +7562,8 @@ function ReportDialog({
|
|
|
7445
7562
|
pageShot,
|
|
7446
7563
|
onAddFiles: addFiles,
|
|
7447
7564
|
onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
|
|
7448
|
-
files:
|
|
7565
|
+
files: heldFiles,
|
|
7566
|
+
canReadPdf: !!readFile,
|
|
7449
7567
|
onRemoveFile: (index) => setAttachments((prev) => prev.filter((_, i) => i !== index)),
|
|
7450
7568
|
attachmentCount: screenshots.length + attachments.length,
|
|
7451
7569
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|
|
@@ -7459,6 +7577,10 @@ function ReportDialog({
|
|
|
7459
7577
|
setStep(2);
|
|
7460
7578
|
},
|
|
7461
7579
|
onDuplicateChange: (issueNumber, kind) => {
|
|
7580
|
+
if (issueNumber) {
|
|
7581
|
+
setSimilarIssues(null);
|
|
7582
|
+
setPickedSimilar(null);
|
|
7583
|
+
}
|
|
7462
7584
|
setDuplicateIssueNumber(issueNumber);
|
|
7463
7585
|
setDuplicateKind(issueNumber && kind === "related" ? "related" : "duplicate");
|
|
7464
7586
|
},
|
|
@@ -7488,7 +7610,9 @@ function ReportDialog({
|
|
|
7488
7610
|
severityRefused: needsSeverity,
|
|
7489
7611
|
isSubmitting,
|
|
7490
7612
|
submitted,
|
|
7491
|
-
onSend: () => void handleSubmit(
|
|
7613
|
+
onSend: () => void handleSubmit(),
|
|
7614
|
+
similarSlot: similarCard,
|
|
7615
|
+
submittedText: addedToIssue ? `Added to #${addedToIssue}${addedAsRelated ? " as a related request" : ""}. Thank you!` : null,
|
|
7492
7616
|
onReportGlitchgrabProblem: reportGlitchgrabProblem ? (prefill) => {
|
|
7493
7617
|
setSelfReportPrefill(prefill != null ? prefill : "");
|
|
7494
7618
|
setSelfReportFrom("assist");
|
|
@@ -7782,7 +7906,9 @@ function BookingDialog({
|
|
|
7782
7906
|
token,
|
|
7783
7907
|
baseUrl,
|
|
7784
7908
|
open,
|
|
7785
|
-
onClose
|
|
7909
|
+
onClose,
|
|
7910
|
+
preview = false,
|
|
7911
|
+
availabilityUrl
|
|
7786
7912
|
}) {
|
|
7787
7913
|
var _a, _b, _c, _d, _e;
|
|
7788
7914
|
const wide = useMediaQuery(WIDE_QUERY, true);
|
|
@@ -7816,10 +7942,12 @@ function BookingDialog({
|
|
|
7816
7942
|
const [meetUrl, setMeetUrl] = useState5(null);
|
|
7817
7943
|
const [busy, setBusy] = useState5(false);
|
|
7818
7944
|
const [error, setError] = useState5(null);
|
|
7819
|
-
const
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7945
|
+
const [previewEnded, setPreviewEnded] = useState5(false);
|
|
7946
|
+
const headers = useMemo3(() => {
|
|
7947
|
+
const out = { "Content-Type": "application/json" };
|
|
7948
|
+
if (token) out.Authorization = `Bearer ${token}`;
|
|
7949
|
+
return out;
|
|
7950
|
+
}, [token]);
|
|
7823
7951
|
const loadMonth = useCallback2(
|
|
7824
7952
|
async (target) => {
|
|
7825
7953
|
var _a2, _b2, _c2;
|
|
@@ -7831,8 +7959,9 @@ function BookingDialog({
|
|
|
7831
7959
|
return;
|
|
7832
7960
|
}
|
|
7833
7961
|
try {
|
|
7962
|
+
const source = availabilityUrl != null ? availabilityUrl : `${baseUrl}/api/v1/sdk/booking/availability`;
|
|
7834
7963
|
const res = await fetch(
|
|
7835
|
-
`${
|
|
7964
|
+
`${source}${source.includes("?") ? "&" : "?"}from=${encodeURIComponent(new Date(from).toISOString())}&to=${encodeURIComponent(new Date(to).toISOString())}${preview ? "&preview=1" : ""}`,
|
|
7836
7965
|
{ headers }
|
|
7837
7966
|
);
|
|
7838
7967
|
const json = await res.json();
|
|
@@ -7861,7 +7990,7 @@ function BookingDialog({
|
|
|
7861
7990
|
setPageLoaded(true);
|
|
7862
7991
|
}
|
|
7863
7992
|
},
|
|
7864
|
-
[baseUrl, headers]
|
|
7993
|
+
[baseUrl, headers, availabilityUrl, preview]
|
|
7865
7994
|
);
|
|
7866
7995
|
useEffect5(() => {
|
|
7867
7996
|
if (!open) return;
|
|
@@ -7875,6 +8004,7 @@ function BookingDialog({
|
|
|
7875
8004
|
setCode("");
|
|
7876
8005
|
setBookingId(null);
|
|
7877
8006
|
setError(null);
|
|
8007
|
+
setPreviewEnded(false);
|
|
7878
8008
|
setAvatarFailed(false);
|
|
7879
8009
|
setPageLoaded(false);
|
|
7880
8010
|
setAsked(false);
|
|
@@ -7913,6 +8043,10 @@ function BookingDialog({
|
|
|
7913
8043
|
async function startBooking() {
|
|
7914
8044
|
var _a2, _b2;
|
|
7915
8045
|
if (!selected) return;
|
|
8046
|
+
if (preview) {
|
|
8047
|
+
setPreviewEnded(true);
|
|
8048
|
+
return;
|
|
8049
|
+
}
|
|
7916
8050
|
setBusy(true);
|
|
7917
8051
|
setError(null);
|
|
7918
8052
|
try {
|
|
@@ -8106,6 +8240,22 @@ function BookingDialog({
|
|
|
8106
8240
|
) : null,
|
|
8107
8241
|
page.hostName && /* @__PURE__ */ jsx6("div", { style: { fontSize: 14, fontWeight: 500, ...muted }, children: page.hostName })
|
|
8108
8242
|
] }),
|
|
8243
|
+
preview && /* @__PURE__ */ jsx6(
|
|
8244
|
+
"div",
|
|
8245
|
+
{
|
|
8246
|
+
style: {
|
|
8247
|
+
alignSelf: "flex-start",
|
|
8248
|
+
padding: "3px 9px",
|
|
8249
|
+
borderRadius: 999,
|
|
8250
|
+
border: `1px dashed ${t.border}`,
|
|
8251
|
+
fontSize: 11.5,
|
|
8252
|
+
fontWeight: 600,
|
|
8253
|
+
letterSpacing: "0.02em",
|
|
8254
|
+
color: t.muted
|
|
8255
|
+
},
|
|
8256
|
+
children: "Preview \u2014 nothing is booked"
|
|
8257
|
+
}
|
|
8258
|
+
),
|
|
8109
8259
|
/* @__PURE__ */ jsx6("div", { style: { fontSize: 20, fontWeight: 600, lineHeight: 1.25, paddingRight: 32, overflowWrap: "anywhere" }, children: page.title }),
|
|
8110
8260
|
page.description && /* @__PURE__ */ jsx6("div", { style: { fontSize: 13, lineHeight: 1.5, overflowWrap: "anywhere", ...muted }, children: page.description }),
|
|
8111
8261
|
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: 10, marginTop: 4, fontSize: 14 }, children: [
|
|
@@ -8543,6 +8693,7 @@ function BookingDialog({
|
|
|
8543
8693
|
},
|
|
8544
8694
|
children: /* @__PURE__ */ jsxs6("div", { style: { maxWidth: 440, display: "flex", flexDirection: "column", gap: 14 }, children: [
|
|
8545
8695
|
error && /* @__PURE__ */ jsx6("div", { style: { color: t.danger, fontSize: 13, lineHeight: 1.5 }, children: error }),
|
|
8696
|
+
previewEnded && /* @__PURE__ */ jsx6("div", { style: { fontSize: 13, lineHeight: 1.5, ...muted }, children: "End of the preview \u2014 a prospect would be booked here. Nothing was booked and no code was sent." }),
|
|
8546
8697
|
step === "details" && /* @__PURE__ */ jsxs6(Fragment5, { children: [
|
|
8547
8698
|
/* @__PURE__ */ jsx6(Field, { t, label: "Your name", value: name, onChange: setName, autoComplete: "name" }),
|
|
8548
8699
|
/* @__PURE__ */ jsx6(Field, { t, label: "Email", value: email, onChange: setEmail, type: "email", autoComplete: "email" }),
|
|
@@ -9383,7 +9534,11 @@ function GlitchgrabProviderInner({
|
|
|
9383
9534
|
[token, baseUrl, session]
|
|
9384
9535
|
);
|
|
9385
9536
|
const findSimilar = useCallback3(
|
|
9386
|
-
(description) => findSimilarIssues(description, token, baseUrl, identity),
|
|
9537
|
+
(description, files) => findSimilarIssues(description, token, baseUrl, identity, files),
|
|
9538
|
+
[token, baseUrl, identity]
|
|
9539
|
+
);
|
|
9540
|
+
const readFile = useCallback3(
|
|
9541
|
+
(file) => readAttachment(file, token, baseUrl, identity),
|
|
9387
9542
|
[token, baseUrl, identity]
|
|
9388
9543
|
);
|
|
9389
9544
|
const transcribe = useCallback3(
|
|
@@ -9414,8 +9569,9 @@ function GlitchgrabProviderInner({
|
|
|
9414
9569
|
const [glitchgrabReport, setGlitchgrabReport] = useState6(false);
|
|
9415
9570
|
const [signedUsers, setSignedUsers] = useState6("OFF");
|
|
9416
9571
|
const aiBlockedUnsigned = signedUsers === "ENFORCE" && !signature;
|
|
9417
|
-
const [
|
|
9418
|
-
const openBookingDialog = useCallback3(() =>
|
|
9572
|
+
const [booking, setBooking] = useState6("closed");
|
|
9573
|
+
const openBookingDialog = useCallback3(() => setBooking("live"), []);
|
|
9574
|
+
const openBookingPreview = useCallback3(() => setBooking("preview"), []);
|
|
9419
9575
|
useEffect6(() => {
|
|
9420
9576
|
let cancelled = false;
|
|
9421
9577
|
fetch(`${baseUrl}/api/v1/sdk/project`, {
|
|
@@ -9490,6 +9646,7 @@ function GlitchgrabProviderInner({
|
|
|
9490
9646
|
addBreadcrumb: addBreadcrumb2,
|
|
9491
9647
|
openReportDialog,
|
|
9492
9648
|
openBookingDialog,
|
|
9649
|
+
openBookingPreview,
|
|
9493
9650
|
enhanceText: enhance,
|
|
9494
9651
|
shortcutLabel
|
|
9495
9652
|
},
|
|
@@ -9511,8 +9668,9 @@ function GlitchgrabProviderInner({
|
|
|
9511
9668
|
{
|
|
9512
9669
|
token,
|
|
9513
9670
|
baseUrl: baseUrl != null ? baseUrl : DEFAULT_BASE_URL2,
|
|
9514
|
-
open:
|
|
9515
|
-
|
|
9671
|
+
open: booking !== "closed",
|
|
9672
|
+
preview: booking === "preview",
|
|
9673
|
+
onClose: () => setBooking("closed")
|
|
9516
9674
|
}
|
|
9517
9675
|
),
|
|
9518
9676
|
/* @__PURE__ */ jsx7(
|
|
@@ -9523,6 +9681,7 @@ function GlitchgrabProviderInner({
|
|
|
9523
9681
|
enhanceText: aiAssist && !aiBlockedUnsigned ? enhance : void 0,
|
|
9524
9682
|
assist: aiAssist && !aiBlockedUnsigned ? assist : void 0,
|
|
9525
9683
|
findSimilarIssues: aiAssist && !aiBlockedUnsigned ? findSimilar : void 0,
|
|
9684
|
+
readFile: aiAssist && !aiBlockedUnsigned ? readFile : void 0,
|
|
9526
9685
|
reportGlitchgrabProblem: glitchgrabReport ? reportGlitchgrabProblem : void 0,
|
|
9527
9686
|
transcribeAudio: aiBlockedUnsigned ? void 0 : transcribe,
|
|
9528
9687
|
types,
|
|
@@ -9926,6 +10085,7 @@ function useGlitchgrabFeedback(query) {
|
|
|
9926
10085
|
}
|
|
9927
10086
|
export {
|
|
9928
10087
|
BookDemoButton,
|
|
10088
|
+
BookingDialog,
|
|
9929
10089
|
FeedbackButton,
|
|
9930
10090
|
GLITCHGRAB_SHORTCUT2 as GLITCHGRAB_SHORTCUT,
|
|
9931
10091
|
GLITCHGRAB_SHORTCUT_MAC2 as GLITCHGRAB_SHORTCUT_MAC,
|