glitchgrab 1.43.0 → 1.45.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/README.md +53 -0
- package/dist/index.d.mts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +701 -74
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +731 -104
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +29 -22
- package/dist/server.d.ts +29 -22
- package/dist/server.js +26 -2
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +26 -1
- package/dist/server.mjs.map +1 -1
- package/dist/{types-YpA_jHFp.d.mts → types-Lldp5noh.d.mts} +7 -0
- package/dist/{types-YpA_jHFp.d.ts → types-Lldp5noh.d.ts} +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -693,7 +693,11 @@ async function sendFeedback(payload, baseUrl) {
|
|
|
693
693
|
return null;
|
|
694
694
|
}
|
|
695
695
|
}
|
|
696
|
-
|
|
696
|
+
function signedFields(identity) {
|
|
697
|
+
if (!(identity == null ? void 0 : identity.signature) || !identity.userId) return {};
|
|
698
|
+
return { userId: identity.userId, signature: identity.signature };
|
|
699
|
+
}
|
|
700
|
+
async function enhanceText(text, token, baseUrl, screenshot, context, identity) {
|
|
697
701
|
var _a;
|
|
698
702
|
try {
|
|
699
703
|
const trimmed = text.trim();
|
|
@@ -708,7 +712,8 @@ async function enhanceText(text, token, baseUrl, screenshot, context) {
|
|
|
708
712
|
body: JSON.stringify({
|
|
709
713
|
text: trimmed,
|
|
710
714
|
...screenshot ? { screenshot } : {},
|
|
711
|
-
...context ? { context } : {}
|
|
715
|
+
...context ? { context } : {},
|
|
716
|
+
...signedFields(identity)
|
|
712
717
|
})
|
|
713
718
|
});
|
|
714
719
|
if (!response.ok) return text;
|
|
@@ -721,6 +726,26 @@ async function enhanceText(text, token, baseUrl, screenshot, context) {
|
|
|
721
726
|
return text;
|
|
722
727
|
}
|
|
723
728
|
}
|
|
729
|
+
async function findSimilarIssues(description, token, baseUrl, identity) {
|
|
730
|
+
var _a;
|
|
731
|
+
try {
|
|
732
|
+
const url = `${baseUrl != null ? baseUrl : DEFAULT_BASE_URL}/api/v1/reports/similar`;
|
|
733
|
+
const response = await fetch(url, {
|
|
734
|
+
method: "POST",
|
|
735
|
+
headers: {
|
|
736
|
+
"Content-Type": "application/json",
|
|
737
|
+
Authorization: `Bearer ${token}`
|
|
738
|
+
},
|
|
739
|
+
body: JSON.stringify({ text: description, ...signedFields(identity) })
|
|
740
|
+
});
|
|
741
|
+
const envelope = await response.json().catch(() => null);
|
|
742
|
+
if (!response.ok || !(envelope == null ? void 0 : envelope.success)) return null;
|
|
743
|
+
if (!((_a = envelope.data) == null ? void 0 : _a.enabled)) return [];
|
|
744
|
+
return Array.isArray(envelope.data.matches) ? envelope.data.matches : [];
|
|
745
|
+
} catch (e) {
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
724
749
|
async function assistTurn(params, token, baseUrl) {
|
|
725
750
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
726
751
|
const offline = {
|
|
@@ -745,7 +770,9 @@ async function assistTurn(params, token, baseUrl) {
|
|
|
745
770
|
conversationId: null,
|
|
746
771
|
question: null,
|
|
747
772
|
report: null,
|
|
748
|
-
degraded: (_a = envelope == null ? void 0 : envelope.error) != null ? _a : offline.degraded
|
|
773
|
+
degraded: (_a = envelope == null ? void 0 : envelope.error) != null ? _a : offline.degraded,
|
|
774
|
+
// An hourly limit, not a cap: the dialog keeps the assistant button.
|
|
775
|
+
retryable: (envelope == null ? void 0 : envelope.retryable) === true
|
|
749
776
|
};
|
|
750
777
|
}
|
|
751
778
|
return {
|
|
@@ -762,13 +789,18 @@ async function assistTurn(params, token, baseUrl) {
|
|
|
762
789
|
return offline;
|
|
763
790
|
}
|
|
764
791
|
}
|
|
765
|
-
async function transcribeAudio(blob, token, baseUrl) {
|
|
792
|
+
async function transcribeAudio(blob, token, baseUrl, identity) {
|
|
766
793
|
var _a;
|
|
767
794
|
try {
|
|
768
795
|
if (blob.size === 0) return "";
|
|
769
796
|
const url = `${baseUrl != null ? baseUrl : DEFAULT_BASE_URL}/api/v1/sdk/stt`;
|
|
770
797
|
const form = new FormData();
|
|
771
798
|
form.append("file", blob, "audio.webm");
|
|
799
|
+
const signed = signedFields(identity);
|
|
800
|
+
if (signed.userId && signed.signature) {
|
|
801
|
+
form.append("userId", signed.userId);
|
|
802
|
+
form.append("signature", signed.signature);
|
|
803
|
+
}
|
|
772
804
|
const response = await fetch(url, {
|
|
773
805
|
method: "POST",
|
|
774
806
|
headers: { Authorization: `Bearer ${token}` },
|
|
@@ -1337,6 +1369,59 @@ var SEVERITY_LABELS = {
|
|
|
1337
1369
|
};
|
|
1338
1370
|
var MAX_ASSIST_IMAGES = 3;
|
|
1339
1371
|
var MAX_ASSIST_IMAGE_CHARS = 35e5;
|
|
1372
|
+
var MAX_ASSIST_FILES = 3;
|
|
1373
|
+
var MAX_ASSIST_FILE_CHARS = 3e5;
|
|
1374
|
+
var MAX_ASSIST_FILE_CHARS_EACH = 2e5;
|
|
1375
|
+
var TEXT_ATTACHMENT_EXTENSIONS = [
|
|
1376
|
+
".html",
|
|
1377
|
+
".htm",
|
|
1378
|
+
".txt",
|
|
1379
|
+
".md",
|
|
1380
|
+
".json",
|
|
1381
|
+
".xml",
|
|
1382
|
+
".log",
|
|
1383
|
+
".yml",
|
|
1384
|
+
".yaml",
|
|
1385
|
+
".csv",
|
|
1386
|
+
".har",
|
|
1387
|
+
".js",
|
|
1388
|
+
".mjs",
|
|
1389
|
+
".cjs",
|
|
1390
|
+
".ts",
|
|
1391
|
+
".tsx",
|
|
1392
|
+
".jsx",
|
|
1393
|
+
".css",
|
|
1394
|
+
".scss",
|
|
1395
|
+
".py",
|
|
1396
|
+
".sh"
|
|
1397
|
+
];
|
|
1398
|
+
var BINARY_ATTACHMENT_EXTENSIONS = [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".zip"];
|
|
1399
|
+
var ATTACHMENT_ACCEPT = [
|
|
1400
|
+
"image/*",
|
|
1401
|
+
...TEXT_ATTACHMENT_EXTENSIONS,
|
|
1402
|
+
...BINARY_ATTACHMENT_EXTENSIONS
|
|
1403
|
+
].join(",");
|
|
1404
|
+
var ASSIST_ATTACHMENT_ACCEPT = ["image/*", ...TEXT_ATTACHMENT_EXTENSIONS].join(",");
|
|
1405
|
+
function isAssistReadableFile(name) {
|
|
1406
|
+
const lower = name.toLowerCase();
|
|
1407
|
+
return TEXT_ATTACHMENT_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
1408
|
+
}
|
|
1409
|
+
function decodeTextDataUrl(dataUrl) {
|
|
1410
|
+
try {
|
|
1411
|
+
if (!dataUrl.startsWith("data:")) return null;
|
|
1412
|
+
const comma = dataUrl.indexOf(",");
|
|
1413
|
+
if (comma < 0) return null;
|
|
1414
|
+
const meta = dataUrl.slice(5, comma);
|
|
1415
|
+
const payload = dataUrl.slice(comma + 1);
|
|
1416
|
+
if (!meta.endsWith(";base64")) return decodeURIComponent(payload);
|
|
1417
|
+
const binary = atob(payload);
|
|
1418
|
+
const bytes = new Uint8Array(binary.length);
|
|
1419
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1420
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
1421
|
+
} catch (e) {
|
|
1422
|
+
return null;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1340
1425
|
function getTypeLabel(type) {
|
|
1341
1426
|
switch (type) {
|
|
1342
1427
|
case "RATING":
|
|
@@ -1368,6 +1453,22 @@ function pickAssistImages(all) {
|
|
|
1368
1453
|
}
|
|
1369
1454
|
return picked;
|
|
1370
1455
|
}
|
|
1456
|
+
var NO_FILES = [];
|
|
1457
|
+
function pickAssistFiles(files) {
|
|
1458
|
+
const picked = [];
|
|
1459
|
+
let total = 0;
|
|
1460
|
+
for (let i = files.length - 1; i >= 0 && picked.length < MAX_ASSIST_FILES; i--) {
|
|
1461
|
+
const attached = files[i];
|
|
1462
|
+
if (!isAssistReadableFile(attached.name)) continue;
|
|
1463
|
+
const text = decodeTextDataUrl(attached.dataUrl);
|
|
1464
|
+
if (!text || !text.trim()) continue;
|
|
1465
|
+
const content = text.slice(0, MAX_ASSIST_FILE_CHARS_EACH);
|
|
1466
|
+
if (total + content.length > MAX_ASSIST_FILE_CHARS) continue;
|
|
1467
|
+
picked.unshift({ index: i, file: { name: attached.name, content } });
|
|
1468
|
+
total += content.length;
|
|
1469
|
+
}
|
|
1470
|
+
return picked;
|
|
1471
|
+
}
|
|
1371
1472
|
var STARTERS = [
|
|
1372
1473
|
"Something on this page is broken",
|
|
1373
1474
|
"It did the wrong thing",
|
|
@@ -1444,7 +1545,9 @@ function AssistSheet({
|
|
|
1444
1545
|
theme: t2,
|
|
1445
1546
|
screenshots,
|
|
1446
1547
|
pageShot = null,
|
|
1447
|
-
|
|
1548
|
+
onAddFiles,
|
|
1549
|
+
files = NO_FILES,
|
|
1550
|
+
onRemoveFile,
|
|
1448
1551
|
onRemoveImage,
|
|
1449
1552
|
attachmentCount,
|
|
1450
1553
|
context,
|
|
@@ -1515,6 +1618,8 @@ function AssistSheet({
|
|
|
1515
1618
|
}
|
|
1516
1619
|
}
|
|
1517
1620
|
const readShots = new Set(pickAssistImages(screenshots));
|
|
1621
|
+
const sentFiles = (0, import_react3.useMemo)(() => pickAssistFiles(files), [files]);
|
|
1622
|
+
const readFiles = new Set(sentFiles.map((f) => f.index));
|
|
1518
1623
|
function leave(type, detail) {
|
|
1519
1624
|
logEvent(type, detail);
|
|
1520
1625
|
flushEvents();
|
|
@@ -1528,10 +1633,10 @@ function AssistSheet({
|
|
|
1528
1633
|
var _a;
|
|
1529
1634
|
if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
|
|
1530
1635
|
}, [phase]);
|
|
1531
|
-
function degradeKeepingEvents(events, message) {
|
|
1636
|
+
function degradeKeepingEvents(events, message, retryable) {
|
|
1532
1637
|
if (events) eventsRef.current = [...events, ...eventsRef.current];
|
|
1533
1638
|
flushEvents();
|
|
1534
|
-
onDegrade(message);
|
|
1639
|
+
onDegrade(message, retryable);
|
|
1535
1640
|
}
|
|
1536
1641
|
async function runTurn(history2) {
|
|
1537
1642
|
var _a, _b, _c, _d;
|
|
@@ -1549,6 +1654,9 @@ function AssistSheet({
|
|
|
1549
1654
|
),
|
|
1550
1655
|
conversationId,
|
|
1551
1656
|
screenshots: sent,
|
|
1657
|
+
// Only when there is something: an older server then sees the body
|
|
1658
|
+
// it always did.
|
|
1659
|
+
...sentFiles.length > 0 ? { files: sentFiles.map((f) => f.file) } : {},
|
|
1552
1660
|
context: {
|
|
1553
1661
|
...context != null ? context : {},
|
|
1554
1662
|
imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached"),
|
|
@@ -1568,7 +1676,7 @@ function AssistSheet({
|
|
|
1568
1676
|
setBusy(false);
|
|
1569
1677
|
}
|
|
1570
1678
|
if (result.degraded) {
|
|
1571
|
-
degradeKeepingEvents(events, result.degraded);
|
|
1679
|
+
degradeKeepingEvents(events, result.degraded, result.retryable === true);
|
|
1572
1680
|
return;
|
|
1573
1681
|
}
|
|
1574
1682
|
if (result.conversationId) {
|
|
@@ -1668,7 +1776,7 @@ function AssistSheet({
|
|
|
1668
1776
|
minWidth: 0
|
|
1669
1777
|
},
|
|
1670
1778
|
children: [
|
|
1671
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color:
|
|
1779
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: t2.text, fontWeight: 600 }, children: title ? "Our team is already on this" : `Our team is already on #${duplicate.number}` }),
|
|
1672
1780
|
title && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
|
|
1673
1781
|
"#",
|
|
1674
1782
|
duplicate.number,
|
|
@@ -2556,7 +2664,7 @@ function AssistSheet({
|
|
|
2556
2664
|
// instead of remounting, and a draft is something you can
|
|
2557
2665
|
// still reply to (#360), not a form that replaced the chat.
|
|
2558
2666
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2559
|
-
(screenshots.length > 0 ||
|
|
2667
|
+
(screenshots.length > 0 || files.length > 0 || onAddFiles) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2560
2668
|
"div",
|
|
2561
2669
|
{
|
|
2562
2670
|
style: {
|
|
@@ -2660,11 +2768,118 @@ function AssistSheet({
|
|
|
2660
2768
|
`${i}-${shot.slice(-16)}`
|
|
2661
2769
|
);
|
|
2662
2770
|
}),
|
|
2663
|
-
|
|
2771
|
+
files.map((file, i) => {
|
|
2772
|
+
const read = readFiles.has(i);
|
|
2773
|
+
const why = read ? "the assistant reads this file" : 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";
|
|
2774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2775
|
+
"div",
|
|
2776
|
+
{
|
|
2777
|
+
"data-gg-assist-file": "",
|
|
2778
|
+
"data-gg-assist-file-read": read ? "" : void 0,
|
|
2779
|
+
title: `${file.name} \u2014 ${why}`,
|
|
2780
|
+
style: {
|
|
2781
|
+
position: "relative",
|
|
2782
|
+
height: "40px",
|
|
2783
|
+
maxWidth: "170px",
|
|
2784
|
+
display: "flex",
|
|
2785
|
+
alignItems: "center",
|
|
2786
|
+
gap: "6px",
|
|
2787
|
+
padding: "0 10px",
|
|
2788
|
+
borderRadius: "8px",
|
|
2789
|
+
border: `1px solid ${read ? t2.accent : t2.inputBorder}`,
|
|
2790
|
+
opacity: read ? 1 : 0.55,
|
|
2791
|
+
boxSizing: "border-box",
|
|
2792
|
+
flexShrink: 0
|
|
2793
|
+
},
|
|
2794
|
+
children: [
|
|
2795
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2796
|
+
"path",
|
|
2797
|
+
{
|
|
2798
|
+
d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6",
|
|
2799
|
+
stroke: t2.textMuted,
|
|
2800
|
+
strokeWidth: "1.5",
|
|
2801
|
+
strokeLinecap: "round",
|
|
2802
|
+
strokeLinejoin: "round"
|
|
2803
|
+
}
|
|
2804
|
+
) }),
|
|
2805
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2806
|
+
"span",
|
|
2807
|
+
{
|
|
2808
|
+
style: {
|
|
2809
|
+
fontSize: "11.5px",
|
|
2810
|
+
color: t2.text,
|
|
2811
|
+
overflow: "hidden",
|
|
2812
|
+
textOverflow: "ellipsis",
|
|
2813
|
+
whiteSpace: "nowrap"
|
|
2814
|
+
},
|
|
2815
|
+
children: file.name
|
|
2816
|
+
}
|
|
2817
|
+
),
|
|
2818
|
+
onRemoveFile && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2819
|
+
"button",
|
|
2820
|
+
{
|
|
2821
|
+
type: "button",
|
|
2822
|
+
"data-gg-assist-remove-file": "",
|
|
2823
|
+
"aria-label": `Remove file ${file.name}`,
|
|
2824
|
+
title: "Remove this file",
|
|
2825
|
+
onClick: () => {
|
|
2826
|
+
logEvent("file_removed", read ? "read" : "not read");
|
|
2827
|
+
onRemoveFile(i);
|
|
2828
|
+
},
|
|
2829
|
+
style: {
|
|
2830
|
+
position: "absolute",
|
|
2831
|
+
top: "-13px",
|
|
2832
|
+
right: "-13px",
|
|
2833
|
+
width: "32px",
|
|
2834
|
+
height: "32px",
|
|
2835
|
+
border: "none",
|
|
2836
|
+
background: "transparent",
|
|
2837
|
+
padding: 0,
|
|
2838
|
+
cursor: "pointer",
|
|
2839
|
+
display: "flex",
|
|
2840
|
+
alignItems: "center",
|
|
2841
|
+
justifyContent: "center",
|
|
2842
|
+
borderRadius: "50%"
|
|
2843
|
+
},
|
|
2844
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2845
|
+
"span",
|
|
2846
|
+
{
|
|
2847
|
+
"aria-hidden": "true",
|
|
2848
|
+
style: {
|
|
2849
|
+
width: "20px",
|
|
2850
|
+
height: "20px",
|
|
2851
|
+
boxSizing: "border-box",
|
|
2852
|
+
borderRadius: "50%",
|
|
2853
|
+
border: `2px solid ${t2.bg}`,
|
|
2854
|
+
background: "#ef4444",
|
|
2855
|
+
color: "#fff",
|
|
2856
|
+
display: "flex",
|
|
2857
|
+
alignItems: "center",
|
|
2858
|
+
justifyContent: "center"
|
|
2859
|
+
},
|
|
2860
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2861
|
+
"path",
|
|
2862
|
+
{
|
|
2863
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
2864
|
+
stroke: "currentColor",
|
|
2865
|
+
strokeWidth: "1.6",
|
|
2866
|
+
strokeLinecap: "round"
|
|
2867
|
+
}
|
|
2868
|
+
) })
|
|
2869
|
+
}
|
|
2870
|
+
)
|
|
2871
|
+
}
|
|
2872
|
+
)
|
|
2873
|
+
]
|
|
2874
|
+
},
|
|
2875
|
+
`file-${i}-${file.name}`
|
|
2876
|
+
);
|
|
2877
|
+
}),
|
|
2878
|
+
onAddFiles && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2664
2879
|
"label",
|
|
2665
2880
|
{
|
|
2666
2881
|
"data-gg-assist-attach": "",
|
|
2667
|
-
title: "Attach an image \u2014 or
|
|
2882
|
+
title: "Attach an image or a file (html, json, log\u2026) \u2014 or paste one",
|
|
2668
2883
|
style: {
|
|
2669
2884
|
width: "40px",
|
|
2670
2885
|
height: "40px",
|
|
@@ -2684,14 +2899,18 @@ function AssistSheet({
|
|
|
2684
2899
|
"input",
|
|
2685
2900
|
{
|
|
2686
2901
|
type: "file",
|
|
2687
|
-
accept:
|
|
2902
|
+
accept: ASSIST_ATTACHMENT_ACCEPT,
|
|
2688
2903
|
multiple: true,
|
|
2689
2904
|
onChange: (e) => {
|
|
2690
2905
|
var _a;
|
|
2691
|
-
const
|
|
2692
|
-
if (
|
|
2693
|
-
|
|
2694
|
-
|
|
2906
|
+
const picked = Array.from((_a = e.target.files) != null ? _a : []);
|
|
2907
|
+
if (picked.length) {
|
|
2908
|
+
const images = picked.filter((f) => f.type.startsWith("image/")).length;
|
|
2909
|
+
if (images) logEvent("image_added", String(images));
|
|
2910
|
+
if (picked.length > images) {
|
|
2911
|
+
logEvent("file_added", String(picked.length - images));
|
|
2912
|
+
}
|
|
2913
|
+
onAddFiles(picked);
|
|
2695
2914
|
}
|
|
2696
2915
|
e.target.value = "";
|
|
2697
2916
|
},
|
|
@@ -2872,6 +3091,7 @@ function AssistSheet({
|
|
|
2872
3091
|
}
|
|
2873
3092
|
var FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2874
3093
|
var FAILED = "Couldn't send it. Try again in a moment.";
|
|
3094
|
+
var MAX_SELF_REPORT_IMAGES = 5;
|
|
2875
3095
|
function describeSentAlong(hasChat, screenshotCount) {
|
|
2876
3096
|
const parts = [
|
|
2877
3097
|
...hasChat ? ["your AI chat"] : [],
|
|
@@ -2895,11 +3115,49 @@ function GlitchgrabProblemPanel({
|
|
|
2895
3115
|
const [busy, setBusy] = (0, import_react4.useState)(false);
|
|
2896
3116
|
const [sent, setSent] = (0, import_react4.useState)(false);
|
|
2897
3117
|
const [error, setError] = (0, import_react4.useState)(null);
|
|
3118
|
+
const [images, setImages] = (0, import_react4.useState)(
|
|
3119
|
+
() => screenshots.slice(0, MAX_SELF_REPORT_IMAGES)
|
|
3120
|
+
);
|
|
2898
3121
|
const inputRef = (0, import_react4.useRef)(null);
|
|
3122
|
+
const fileRef = (0, import_react4.useRef)(null);
|
|
2899
3123
|
(0, import_react4.useEffect)(() => {
|
|
2900
3124
|
var _a;
|
|
2901
3125
|
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
2902
3126
|
}, []);
|
|
3127
|
+
const addImages = (0, import_react4.useCallback)((files) => {
|
|
3128
|
+
const picked = files.filter((file) => file.type.startsWith("image/"));
|
|
3129
|
+
if (!picked.length) return;
|
|
3130
|
+
void Promise.all(picked.map((file) => encodeImageFile(file).catch(() => null))).then(
|
|
3131
|
+
(encoded) => {
|
|
3132
|
+
const added = encoded.filter((url) => !!url);
|
|
3133
|
+
if (added.length) {
|
|
3134
|
+
setImages((prev) => [...prev, ...added].slice(0, MAX_SELF_REPORT_IMAGES));
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
);
|
|
3138
|
+
}, []);
|
|
3139
|
+
(0, import_react4.useEffect)(() => {
|
|
3140
|
+
const onPaste = (e) => {
|
|
3141
|
+
var _a;
|
|
3142
|
+
try {
|
|
3143
|
+
const items = (_a = e.clipboardData) == null ? void 0 : _a.items;
|
|
3144
|
+
if (!items) return;
|
|
3145
|
+
const files = [];
|
|
3146
|
+
for (let i = 0; i < items.length; i++) {
|
|
3147
|
+
if (items[i].kind !== "file") continue;
|
|
3148
|
+
const file = items[i].getAsFile();
|
|
3149
|
+
if (file) files.push(file);
|
|
3150
|
+
}
|
|
3151
|
+
if (!files.length) return;
|
|
3152
|
+
e.preventDefault();
|
|
3153
|
+
e.stopImmediatePropagation();
|
|
3154
|
+
addImages(files);
|
|
3155
|
+
} catch (e2) {
|
|
3156
|
+
}
|
|
3157
|
+
};
|
|
3158
|
+
window.addEventListener("paste", onPaste, true);
|
|
3159
|
+
return () => window.removeEventListener("paste", onPaste, true);
|
|
3160
|
+
}, [addImages]);
|
|
2903
3161
|
(0, import_react4.useEffect)(() => {
|
|
2904
3162
|
const onKey = (e) => {
|
|
2905
3163
|
if (e.key !== "Escape") return;
|
|
@@ -2915,7 +3173,13 @@ function GlitchgrabProblemPanel({
|
|
|
2915
3173
|
setBusy(true);
|
|
2916
3174
|
setError(null);
|
|
2917
3175
|
try {
|
|
2918
|
-
const result = await send({
|
|
3176
|
+
const result = await send({
|
|
3177
|
+
description,
|
|
3178
|
+
surface,
|
|
3179
|
+
conversationId,
|
|
3180
|
+
reportType,
|
|
3181
|
+
screenshots: images
|
|
3182
|
+
});
|
|
2919
3183
|
if (result == null ? void 0 : result.success) setSent(true);
|
|
2920
3184
|
else setError((result == null ? void 0 : result.message) || FAILED);
|
|
2921
3185
|
} catch (e) {
|
|
@@ -3068,6 +3332,134 @@ function GlitchgrabProblemPanel({
|
|
|
3068
3332
|
}
|
|
3069
3333
|
}
|
|
3070
3334
|
),
|
|
3335
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3336
|
+
"div",
|
|
3337
|
+
{
|
|
3338
|
+
"data-gg-self-report-images": "",
|
|
3339
|
+
style: {
|
|
3340
|
+
display: "flex",
|
|
3341
|
+
flexWrap: "wrap",
|
|
3342
|
+
alignItems: "center",
|
|
3343
|
+
gap: "8px",
|
|
3344
|
+
marginTop: "10px"
|
|
3345
|
+
},
|
|
3346
|
+
children: [
|
|
3347
|
+
images.map((src, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { position: "relative", width: "48px", height: "48px" }, children: [
|
|
3348
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3349
|
+
"img",
|
|
3350
|
+
{
|
|
3351
|
+
src,
|
|
3352
|
+
alt: `Screenshot ${i + 1}`,
|
|
3353
|
+
style: {
|
|
3354
|
+
width: "100%",
|
|
3355
|
+
height: "100%",
|
|
3356
|
+
objectFit: "cover",
|
|
3357
|
+
display: "block",
|
|
3358
|
+
boxSizing: "border-box",
|
|
3359
|
+
borderRadius: "8px",
|
|
3360
|
+
border: `1px solid ${t2.inputBorder}`
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
),
|
|
3364
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3365
|
+
"button",
|
|
3366
|
+
{
|
|
3367
|
+
type: "button",
|
|
3368
|
+
"data-gg-self-report-remove-image": "",
|
|
3369
|
+
"aria-label": `Remove screenshot ${i + 1}`,
|
|
3370
|
+
title: "Don't send this one",
|
|
3371
|
+
onClick: () => setImages((prev) => prev.filter((_, j) => j !== i)),
|
|
3372
|
+
style: {
|
|
3373
|
+
position: "absolute",
|
|
3374
|
+
top: "-13px",
|
|
3375
|
+
right: "-13px",
|
|
3376
|
+
width: "32px",
|
|
3377
|
+
height: "32px",
|
|
3378
|
+
border: "none",
|
|
3379
|
+
background: "transparent",
|
|
3380
|
+
padding: 0,
|
|
3381
|
+
cursor: "pointer",
|
|
3382
|
+
display: "flex",
|
|
3383
|
+
alignItems: "center",
|
|
3384
|
+
justifyContent: "center",
|
|
3385
|
+
borderRadius: "50%"
|
|
3386
|
+
},
|
|
3387
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3388
|
+
"span",
|
|
3389
|
+
{
|
|
3390
|
+
"aria-hidden": "true",
|
|
3391
|
+
style: {
|
|
3392
|
+
width: "20px",
|
|
3393
|
+
height: "20px",
|
|
3394
|
+
boxSizing: "border-box",
|
|
3395
|
+
borderRadius: "50%",
|
|
3396
|
+
border: `2px solid ${t2.bg}`,
|
|
3397
|
+
background: "#ef4444",
|
|
3398
|
+
color: "#fff",
|
|
3399
|
+
display: "flex",
|
|
3400
|
+
alignItems: "center",
|
|
3401
|
+
justifyContent: "center"
|
|
3402
|
+
},
|
|
3403
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3404
|
+
"path",
|
|
3405
|
+
{
|
|
3406
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
3407
|
+
stroke: "currentColor",
|
|
3408
|
+
strokeWidth: "1.6",
|
|
3409
|
+
strokeLinecap: "round"
|
|
3410
|
+
}
|
|
3411
|
+
) })
|
|
3412
|
+
}
|
|
3413
|
+
)
|
|
3414
|
+
}
|
|
3415
|
+
)
|
|
3416
|
+
] }, i)),
|
|
3417
|
+
images.length < MAX_SELF_REPORT_IMAGES && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3418
|
+
"button",
|
|
3419
|
+
{
|
|
3420
|
+
type: "button",
|
|
3421
|
+
"data-gg-self-report-attach": "",
|
|
3422
|
+
"aria-label": "Add screenshot",
|
|
3423
|
+
title: "Add a screenshot \u2014 or paste one",
|
|
3424
|
+
onClick: () => {
|
|
3425
|
+
var _a;
|
|
3426
|
+
return (_a = fileRef.current) == null ? void 0 : _a.click();
|
|
3427
|
+
},
|
|
3428
|
+
style: {
|
|
3429
|
+
height: "48px",
|
|
3430
|
+
padding: "0 12px",
|
|
3431
|
+
boxSizing: "border-box",
|
|
3432
|
+
borderRadius: "8px",
|
|
3433
|
+
border: `1px dashed ${t2.inputBorder}`,
|
|
3434
|
+
background: "transparent",
|
|
3435
|
+
color: t2.textMuted,
|
|
3436
|
+
fontSize: "12.5px",
|
|
3437
|
+
fontWeight: 600,
|
|
3438
|
+
fontFamily: "inherit",
|
|
3439
|
+
cursor: "pointer"
|
|
3440
|
+
},
|
|
3441
|
+
children: images.length >= 3 ? "+ Add" : "+ Add screenshot"
|
|
3442
|
+
}
|
|
3443
|
+
),
|
|
3444
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3445
|
+
"input",
|
|
3446
|
+
{
|
|
3447
|
+
ref: fileRef,
|
|
3448
|
+
type: "file",
|
|
3449
|
+
accept: "image/*",
|
|
3450
|
+
multiple: true,
|
|
3451
|
+
"data-gg-self-report-file": "",
|
|
3452
|
+
onChange: (e) => {
|
|
3453
|
+
var _a;
|
|
3454
|
+
addImages(Array.from((_a = e.target.files) != null ? _a : []));
|
|
3455
|
+
e.target.value = "";
|
|
3456
|
+
},
|
|
3457
|
+
style: { display: "none" }
|
|
3458
|
+
}
|
|
3459
|
+
)
|
|
3460
|
+
]
|
|
3461
|
+
}
|
|
3462
|
+
),
|
|
3071
3463
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3072
3464
|
"p",
|
|
3073
3465
|
{
|
|
@@ -3076,7 +3468,7 @@ function GlitchgrabProblemPanel({
|
|
|
3076
3468
|
children: [
|
|
3077
3469
|
"Also sent, so we can see what happened:",
|
|
3078
3470
|
" ",
|
|
3079
|
-
describeSentAlong(conversationId !== null,
|
|
3471
|
+
describeSentAlong(conversationId !== null, images.length),
|
|
3080
3472
|
"."
|
|
3081
3473
|
]
|
|
3082
3474
|
}
|
|
@@ -3117,38 +3509,6 @@ function isMac() {
|
|
|
3117
3509
|
function getShortcutLabel() {
|
|
3118
3510
|
return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;
|
|
3119
3511
|
}
|
|
3120
|
-
var ATTACHMENT_ACCEPT = [
|
|
3121
|
-
"image/*",
|
|
3122
|
-
// text — inlined into the issue body
|
|
3123
|
-
".html",
|
|
3124
|
-
".htm",
|
|
3125
|
-
".txt",
|
|
3126
|
-
".md",
|
|
3127
|
-
".json",
|
|
3128
|
-
".xml",
|
|
3129
|
-
".log",
|
|
3130
|
-
".yml",
|
|
3131
|
-
".yaml",
|
|
3132
|
-
".csv",
|
|
3133
|
-
".har",
|
|
3134
|
-
".js",
|
|
3135
|
-
".mjs",
|
|
3136
|
-
".cjs",
|
|
3137
|
-
".ts",
|
|
3138
|
-
".tsx",
|
|
3139
|
-
".jsx",
|
|
3140
|
-
".css",
|
|
3141
|
-
".scss",
|
|
3142
|
-
".py",
|
|
3143
|
-
".sh",
|
|
3144
|
-
// binary documents
|
|
3145
|
-
".pdf",
|
|
3146
|
-
".doc",
|
|
3147
|
-
".docx",
|
|
3148
|
-
".xls",
|
|
3149
|
-
".xlsx",
|
|
3150
|
-
".zip"
|
|
3151
|
-
].join(",");
|
|
3152
3512
|
var MAX_SCALE = 2;
|
|
3153
3513
|
var FRAME_TIMEOUT_MS = 3e3;
|
|
3154
3514
|
var GRAB_TIMEOUT_MS = FRAME_TIMEOUT_MS + 2e3;
|
|
@@ -3292,6 +3652,27 @@ function captureDefaultScreenshot(options) {
|
|
|
3292
3652
|
}
|
|
3293
3653
|
var SEVERITY_REQUIRED = "Pick how bad it is before sending.";
|
|
3294
3654
|
var SHOT_WAIT_MS = 3e3;
|
|
3655
|
+
var SIMILAR_WAIT_MS = 2500;
|
|
3656
|
+
var MAX_SIMILAR_SHOWN = 3;
|
|
3657
|
+
function ButtonSpinner() {
|
|
3658
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3659
|
+
"span",
|
|
3660
|
+
{
|
|
3661
|
+
"aria-hidden": "true",
|
|
3662
|
+
style: {
|
|
3663
|
+
display: "inline-block",
|
|
3664
|
+
width: "11px",
|
|
3665
|
+
height: "11px",
|
|
3666
|
+
marginRight: "6px",
|
|
3667
|
+
verticalAlign: "-1px",
|
|
3668
|
+
border: "2px solid currentColor",
|
|
3669
|
+
borderRightColor: "transparent",
|
|
3670
|
+
borderRadius: "50%",
|
|
3671
|
+
animation: "gg-spin .7s linear infinite"
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
);
|
|
3675
|
+
}
|
|
3295
3676
|
function detectDark() {
|
|
3296
3677
|
if (typeof window === "undefined") return true;
|
|
3297
3678
|
try {
|
|
@@ -3598,6 +3979,7 @@ function ReportDialog({
|
|
|
3598
3979
|
sendFeedback: sendFeedback2,
|
|
3599
3980
|
enhanceText: enhanceText2,
|
|
3600
3981
|
assist,
|
|
3982
|
+
findSimilarIssues: findSimilarIssues2,
|
|
3601
3983
|
assistContext = null,
|
|
3602
3984
|
transcribeAudio: transcribeAudio2,
|
|
3603
3985
|
types,
|
|
@@ -3617,6 +3999,11 @@ function ReportDialog({
|
|
|
3617
3999
|
const [selfReportPrefill, setSelfReportPrefill] = (0, import_react.useState)("");
|
|
3618
4000
|
const [typeChosen, setTypeChosen] = (0, import_react.useState)(false);
|
|
3619
4001
|
const [duplicateIssueNumber, setDuplicateIssueNumber] = (0, import_react.useState)(null);
|
|
4002
|
+
const [similarIssues, setSimilarIssues] = (0, import_react.useState)(null);
|
|
4003
|
+
const [checkingSimilar, setCheckingSimilar] = (0, import_react.useState)(false);
|
|
4004
|
+
const [attachingTo, setAttachingTo] = (0, import_react.useState)(null);
|
|
4005
|
+
const [pickedSimilar, setPickedSimilar] = (0, import_react.useState)(null);
|
|
4006
|
+
const [addedToIssue, setAddedToIssue] = (0, import_react.useState)(null);
|
|
3620
4007
|
const [aiConversationId, setAiConversationId] = (0, import_react.useState)(null);
|
|
3621
4008
|
const [isEnhanced, setIsEnhanced] = (0, import_react.useState)(false);
|
|
3622
4009
|
const [originalDescription, setOriginalDescription] = (0, import_react.useState)(
|
|
@@ -4047,6 +4434,10 @@ function ReportDialog({
|
|
|
4047
4434
|
setReportType("BUG");
|
|
4048
4435
|
setTypeChosen(false);
|
|
4049
4436
|
setDuplicateIssueNumber(null);
|
|
4437
|
+
setSimilarIssues(null);
|
|
4438
|
+
setPickedSimilar(null);
|
|
4439
|
+
setCheckingSimilar(false);
|
|
4440
|
+
setAttachingTo(null);
|
|
4050
4441
|
setSeverity(null);
|
|
4051
4442
|
setValidationError(null);
|
|
4052
4443
|
setSelfReportFrom(null);
|
|
@@ -4234,7 +4625,8 @@ function ReportDialog({
|
|
|
4234
4625
|
stopListeningAndTranscribe();
|
|
4235
4626
|
}
|
|
4236
4627
|
};
|
|
4237
|
-
const handleSubmit = async () => {
|
|
4628
|
+
const handleSubmit = async (opts) => {
|
|
4629
|
+
var _a2;
|
|
4238
4630
|
try {
|
|
4239
4631
|
if (isSubmitting) return;
|
|
4240
4632
|
if (isRating) {
|
|
@@ -4271,6 +4663,22 @@ function ReportDialog({
|
|
|
4271
4663
|
setStep(2);
|
|
4272
4664
|
return;
|
|
4273
4665
|
}
|
|
4666
|
+
const duplicateOf = (_a2 = opts == null ? void 0 : opts.duplicateOf) != null ? _a2 : duplicateIssueNumber;
|
|
4667
|
+
if (findSimilarIssues2 && !(opts == null ? void 0 : opts.skipSimilar) && !duplicateOf && !aiConversationId) {
|
|
4668
|
+
setIsSubmitting(true);
|
|
4669
|
+
setCheckingSimilar(true);
|
|
4670
|
+
const matches = await Promise.race([
|
|
4671
|
+
findSimilarIssues2(description.trim()).catch(() => null),
|
|
4672
|
+
new Promise((resolve) => setTimeout(() => resolve(null), SIMILAR_WAIT_MS))
|
|
4673
|
+
]);
|
|
4674
|
+
setCheckingSimilar(false);
|
|
4675
|
+
if (matches && matches.length > 0) {
|
|
4676
|
+
setSimilarIssues(matches.slice(0, MAX_SIMILAR_SHOWN));
|
|
4677
|
+
setPickedSimilar(null);
|
|
4678
|
+
setIsSubmitting(false);
|
|
4679
|
+
return;
|
|
4680
|
+
}
|
|
4681
|
+
}
|
|
4274
4682
|
setIsSubmitting(true);
|
|
4275
4683
|
let shots = screenshots;
|
|
4276
4684
|
const pending = pendingShotRef.current;
|
|
@@ -4289,8 +4697,8 @@ function ReportDialog({
|
|
|
4289
4697
|
if (showSeverity && reportType === "BUG" && severity) {
|
|
4290
4698
|
metadata.severity = severity;
|
|
4291
4699
|
}
|
|
4292
|
-
if (
|
|
4293
|
-
metadata.duplicateIssueNumber = String(
|
|
4700
|
+
if (duplicateOf) {
|
|
4701
|
+
metadata.duplicateIssueNumber = String(duplicateOf);
|
|
4294
4702
|
}
|
|
4295
4703
|
if (aiConversationId) {
|
|
4296
4704
|
metadata.aiConversationId = aiConversationId;
|
|
@@ -4303,20 +4711,26 @@ function ReportDialog({
|
|
|
4303
4711
|
Object.keys(metadata).length > 0 ? metadata : void 0
|
|
4304
4712
|
);
|
|
4305
4713
|
if (result) {
|
|
4714
|
+
setAddedToIssue(duplicateOf && result.issueNumber === duplicateOf ? duplicateOf : null);
|
|
4306
4715
|
setSubmitted(true);
|
|
4307
4716
|
setDescription("");
|
|
4308
4717
|
setScreenshots([]);
|
|
4309
4718
|
setAttachments([]);
|
|
4310
4719
|
setAiConversationId(null);
|
|
4311
4720
|
setDuplicateIssueNumber(null);
|
|
4721
|
+
setSimilarIssues(null);
|
|
4722
|
+
setPickedSimilar(null);
|
|
4312
4723
|
setTimeout(() => {
|
|
4313
4724
|
setSubmitted(false);
|
|
4314
4725
|
handleClose();
|
|
4315
4726
|
}, 2e3);
|
|
4316
4727
|
}
|
|
4317
4728
|
setIsSubmitting(false);
|
|
4729
|
+
setAttachingTo(null);
|
|
4318
4730
|
} catch (e) {
|
|
4319
4731
|
setIsSubmitting(false);
|
|
4732
|
+
setCheckingSimilar(false);
|
|
4733
|
+
setAttachingTo(null);
|
|
4320
4734
|
}
|
|
4321
4735
|
};
|
|
4322
4736
|
if (!mounted) return null;
|
|
@@ -4324,6 +4738,7 @@ function ReportDialog({
|
|
|
4324
4738
|
isOpen && (0, import_react_dom.createPortal)(
|
|
4325
4739
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
|
|
4326
4740
|
@keyframes gg-pulse{0%,100%{opacity:1}50%{opacity:0.35}}
|
|
4741
|
+
@keyframes gg-spin{to{transform:rotate(360deg)}}
|
|
4327
4742
|
@keyframes gg-b1{0%,100%{height:3px}40%{height:13px}}
|
|
4328
4743
|
@keyframes gg-b2{0%,100%{height:8px}50%{height:3px}}
|
|
4329
4744
|
@keyframes gg-b3{0%,100%{height:4px}30%{height:14px}70%{height:5px}}
|
|
@@ -4608,7 +5023,7 @@ function ReportDialog({
|
|
|
4608
5023
|
flex: "1 1 auto",
|
|
4609
5024
|
minHeight: 0
|
|
4610
5025
|
},
|
|
4611
|
-
children: submitted ? /* @__PURE__ */ (0, import_jsx_runtime4.
|
|
5026
|
+
children: submitted ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4612
5027
|
"div",
|
|
4613
5028
|
{
|
|
4614
5029
|
style: {
|
|
@@ -4618,10 +5033,7 @@ function ReportDialog({
|
|
|
4618
5033
|
fontSize: "14px",
|
|
4619
5034
|
fontWeight: 500
|
|
4620
5035
|
},
|
|
4621
|
-
children:
|
|
4622
|
-
getTypeLabel(reportType),
|
|
4623
|
-
" sent. Thank you!"
|
|
4624
|
-
]
|
|
5036
|
+
children: addedToIssue ? `Added to #${addedToIssue}. Thank you!` : `${getTypeLabel(reportType)} sent. Thank you!`
|
|
4625
5037
|
}
|
|
4626
5038
|
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
4627
5039
|
step === 1 && headerSlot ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { marginBottom: "14px" }, children: headerSlot }) : null,
|
|
@@ -5846,11 +6258,194 @@ function ReportDialog({
|
|
|
5846
6258
|
children: validationError
|
|
5847
6259
|
}
|
|
5848
6260
|
),
|
|
5849
|
-
|
|
6261
|
+
similarIssues ? (
|
|
6262
|
+
// Same visual language as the assistant's "Our team is
|
|
6263
|
+
// already on this" card, so both routes to a duplicate
|
|
6264
|
+
// read as one feature.
|
|
6265
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
6266
|
+
"div",
|
|
6267
|
+
{
|
|
6268
|
+
"data-gg-similar": "",
|
|
6269
|
+
style: {
|
|
6270
|
+
marginTop: "12px",
|
|
6271
|
+
display: "flex",
|
|
6272
|
+
flexDirection: "column",
|
|
6273
|
+
gap: "10px",
|
|
6274
|
+
padding: "12px",
|
|
6275
|
+
borderRadius: "10px",
|
|
6276
|
+
border: "1px solid rgba(245,158,11,0.4)",
|
|
6277
|
+
backgroundColor: "rgba(245,158,11,0.08)"
|
|
6278
|
+
},
|
|
6279
|
+
children: [
|
|
6280
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
|
|
6281
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: t2.text, fontWeight: 600, fontSize: "13px" }, children: "Our team may already have this" }),
|
|
6282
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: t2.textMuted, fontSize: "12px", lineHeight: 1.5 }, children: similarIssues.length > 1 ? "Pick the one that matches \u2014 your report is added to it, so the team sees everyone hitting it in one place." : "If it's the same problem, pick it \u2014 your report is added to it, so the team sees everyone hitting it in one place." })
|
|
6283
|
+
] }),
|
|
6284
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
6285
|
+
"div",
|
|
6286
|
+
{
|
|
6287
|
+
role: "radiogroup",
|
|
6288
|
+
"aria-label": "Existing issues",
|
|
6289
|
+
style: { display: "flex", flexDirection: "column", gap: "6px" },
|
|
6290
|
+
children: similarIssues.map((issue) => {
|
|
6291
|
+
const picked = pickedSimilar === issue.number;
|
|
6292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
6293
|
+
"button",
|
|
6294
|
+
{
|
|
6295
|
+
type: "button",
|
|
6296
|
+
role: "radio",
|
|
6297
|
+
"aria-checked": picked,
|
|
6298
|
+
disabled: isSubmitting,
|
|
6299
|
+
onClick: () => setPickedSimilar(issue.number),
|
|
6300
|
+
style: {
|
|
6301
|
+
display: "flex",
|
|
6302
|
+
alignItems: "flex-start",
|
|
6303
|
+
gap: "10px",
|
|
6304
|
+
width: "100%",
|
|
6305
|
+
minHeight: "44px",
|
|
6306
|
+
padding: "9px 10px",
|
|
6307
|
+
borderRadius: "8px",
|
|
6308
|
+
border: `1px solid ${picked ? t2.accent : t2.border}`,
|
|
6309
|
+
boxShadow: picked ? `0 0 0 1px ${t2.accent}` : "none",
|
|
6310
|
+
backgroundColor: t2.bg,
|
|
6311
|
+
color: t2.text,
|
|
6312
|
+
textAlign: "left",
|
|
6313
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
6314
|
+
fontFamily: "inherit"
|
|
6315
|
+
},
|
|
6316
|
+
children: [
|
|
6317
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
6318
|
+
"span",
|
|
6319
|
+
{
|
|
6320
|
+
"aria-hidden": "true",
|
|
6321
|
+
style: {
|
|
6322
|
+
flexShrink: 0,
|
|
6323
|
+
marginTop: "2px",
|
|
6324
|
+
width: "14px",
|
|
6325
|
+
height: "14px",
|
|
6326
|
+
boxSizing: "border-box",
|
|
6327
|
+
borderRadius: "50%",
|
|
6328
|
+
border: `2px solid ${picked ? t2.accent : t2.textMuted}`,
|
|
6329
|
+
backgroundColor: picked ? t2.accent : "transparent",
|
|
6330
|
+
boxShadow: picked ? `inset 0 0 0 2px ${t2.bg}` : "none"
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6333
|
+
),
|
|
6334
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
6335
|
+
"span",
|
|
6336
|
+
{
|
|
6337
|
+
style: {
|
|
6338
|
+
display: "flex",
|
|
6339
|
+
flexDirection: "column",
|
|
6340
|
+
gap: "3px",
|
|
6341
|
+
minWidth: 0
|
|
6342
|
+
},
|
|
6343
|
+
children: [
|
|
6344
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
6345
|
+
"span",
|
|
6346
|
+
{
|
|
6347
|
+
title: issue.title,
|
|
6348
|
+
style: {
|
|
6349
|
+
fontSize: "12.5px",
|
|
6350
|
+
lineHeight: 1.45,
|
|
6351
|
+
wordBreak: "break-word",
|
|
6352
|
+
overflow: "hidden",
|
|
6353
|
+
display: "-webkit-box",
|
|
6354
|
+
WebkitLineClamp: 3,
|
|
6355
|
+
WebkitBoxOrient: "vertical"
|
|
6356
|
+
},
|
|
6357
|
+
children: [
|
|
6358
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { color: t2.textMuted, fontWeight: 600 }, children: [
|
|
6359
|
+
"#",
|
|
6360
|
+
issue.number
|
|
6361
|
+
] }),
|
|
6362
|
+
" ",
|
|
6363
|
+
issue.title
|
|
6364
|
+
]
|
|
6365
|
+
}
|
|
6366
|
+
),
|
|
6367
|
+
issue.status && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "11.5px", color: t2.textMuted }, children: issue.status })
|
|
6368
|
+
]
|
|
6369
|
+
}
|
|
6370
|
+
)
|
|
6371
|
+
]
|
|
6372
|
+
},
|
|
6373
|
+
issue.number
|
|
6374
|
+
);
|
|
6375
|
+
})
|
|
6376
|
+
}
|
|
6377
|
+
),
|
|
6378
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
6379
|
+
"button",
|
|
6380
|
+
{
|
|
6381
|
+
type: "button",
|
|
6382
|
+
disabled: isSubmitting || !pickedSimilar,
|
|
6383
|
+
onClick: () => {
|
|
6384
|
+
if (!pickedSimilar) return;
|
|
6385
|
+
setAttachingTo(pickedSimilar);
|
|
6386
|
+
setDuplicateIssueNumber(pickedSimilar);
|
|
6387
|
+
void handleSubmit({ duplicateOf: pickedSimilar });
|
|
6388
|
+
},
|
|
6389
|
+
style: {
|
|
6390
|
+
width: "100%",
|
|
6391
|
+
minHeight: "40px",
|
|
6392
|
+
padding: "10px",
|
|
6393
|
+
borderRadius: "8px",
|
|
6394
|
+
border: "none",
|
|
6395
|
+
backgroundColor: isSubmitting || !pickedSimilar ? t2.bgSecondary : t2.accent,
|
|
6396
|
+
color: isSubmitting || !pickedSimilar ? t2.textMuted : t2.accentText,
|
|
6397
|
+
fontSize: "14px",
|
|
6398
|
+
fontWeight: 600,
|
|
6399
|
+
cursor: isSubmitting || !pickedSimilar ? "not-allowed" : "pointer",
|
|
6400
|
+
fontFamily: "inherit"
|
|
6401
|
+
},
|
|
6402
|
+
children: typeof attachingTo === "number" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
6403
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ButtonSpinner, {}),
|
|
6404
|
+
"Adding to #",
|
|
6405
|
+
attachingTo,
|
|
6406
|
+
"\u2026"
|
|
6407
|
+
] }) : pickedSimilar ? `Add to #${pickedSimilar}` : "Pick the matching issue"
|
|
6408
|
+
}
|
|
6409
|
+
),
|
|
6410
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
6411
|
+
"button",
|
|
6412
|
+
{
|
|
6413
|
+
type: "button",
|
|
6414
|
+
disabled: isSubmitting,
|
|
6415
|
+
onClick: () => {
|
|
6416
|
+
setAttachingTo("new");
|
|
6417
|
+
void handleSubmit({ skipSimilar: true });
|
|
6418
|
+
},
|
|
6419
|
+
style: {
|
|
6420
|
+
width: "100%",
|
|
6421
|
+
minHeight: "40px",
|
|
6422
|
+
marginTop: "-4px",
|
|
6423
|
+
padding: "8px",
|
|
6424
|
+
borderRadius: "8px",
|
|
6425
|
+
border: "none",
|
|
6426
|
+
backgroundColor: "transparent",
|
|
6427
|
+
color: isSubmitting ? t2.textMuted : t2.text,
|
|
6428
|
+
fontSize: "13px",
|
|
6429
|
+
fontWeight: 500,
|
|
6430
|
+
textDecoration: "underline",
|
|
6431
|
+
textUnderlineOffset: "3px",
|
|
6432
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
6433
|
+
fontFamily: "inherit"
|
|
6434
|
+
},
|
|
6435
|
+
children: attachingTo === "new" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
6436
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ButtonSpinner, {}),
|
|
6437
|
+
"Sending as new\u2026"
|
|
6438
|
+
] }) : "No, mine is different \u2014 send as new"
|
|
6439
|
+
}
|
|
6440
|
+
)
|
|
6441
|
+
]
|
|
6442
|
+
}
|
|
6443
|
+
)
|
|
6444
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
5850
6445
|
"button",
|
|
5851
6446
|
{
|
|
5852
6447
|
type: "button",
|
|
5853
|
-
onClick: handleSubmit,
|
|
6448
|
+
onClick: () => void handleSubmit(),
|
|
5854
6449
|
disabled: submitDisabled,
|
|
5855
6450
|
style: {
|
|
5856
6451
|
marginTop: "12px",
|
|
@@ -5866,7 +6461,10 @@ function ReportDialog({
|
|
|
5866
6461
|
fontFamily: "inherit",
|
|
5867
6462
|
transition: "background-color 0.15s ease"
|
|
5868
6463
|
},
|
|
5869
|
-
children:
|
|
6464
|
+
children: checkingSimilar ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
6465
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ButtonSpinner, {}),
|
|
6466
|
+
"Checking for existing reports\u2026"
|
|
6467
|
+
] }) : isSubmitting ? shotPending && !isRating ? "Attaching screenshot\u2026" : "Sending..." : isRating ? "Send Rating" : "Send Report"
|
|
5870
6468
|
}
|
|
5871
6469
|
)
|
|
5872
6470
|
] })
|
|
@@ -6140,8 +6738,10 @@ function ReportDialog({
|
|
|
6140
6738
|
theme: layerTheme,
|
|
6141
6739
|
screenshots,
|
|
6142
6740
|
pageShot,
|
|
6143
|
-
|
|
6741
|
+
onAddFiles: addFiles,
|
|
6144
6742
|
onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
|
|
6743
|
+
files: attachments,
|
|
6744
|
+
onRemoveFile: (index) => setAttachments((prev) => prev.filter((_, i) => i !== index)),
|
|
6145
6745
|
attachmentCount: screenshots.length + attachments.length,
|
|
6146
6746
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|
|
6147
6747
|
reportTypeLabel: getTypeLabel(reportType),
|
|
@@ -6178,14 +6778,14 @@ function ReportDialog({
|
|
|
6178
6778
|
severityRefused: needsSeverity,
|
|
6179
6779
|
isSubmitting,
|
|
6180
6780
|
submitted,
|
|
6181
|
-
onSend: () => void handleSubmit(),
|
|
6781
|
+
onSend: () => void handleSubmit({ skipSimilar: true }),
|
|
6182
6782
|
onReportGlitchgrabProblem: reportGlitchgrabProblem ? (prefill) => {
|
|
6183
6783
|
setSelfReportPrefill(prefill != null ? prefill : "");
|
|
6184
6784
|
setSelfReportFrom("assist");
|
|
6185
6785
|
} : void 0,
|
|
6186
|
-
onDegrade: (message) => {
|
|
6786
|
+
onDegrade: (message, retryable) => {
|
|
6187
6787
|
setAssistOpen(false);
|
|
6188
|
-
setAssistUsed(true);
|
|
6788
|
+
if (!retryable) setAssistUsed(true);
|
|
6189
6789
|
setAssistNotice(message);
|
|
6190
6790
|
},
|
|
6191
6791
|
onClose: () => {
|
|
@@ -7203,6 +7803,12 @@ function GlitchgrabProviderInner({
|
|
|
7203
7803
|
},
|
|
7204
7804
|
[]
|
|
7205
7805
|
);
|
|
7806
|
+
const signedUserId = session == null ? void 0 : session.userId;
|
|
7807
|
+
const signature = typeof (session == null ? void 0 : session.signature) === "string" ? session.signature : null;
|
|
7808
|
+
const identity = (0, import_react6.useMemo)(
|
|
7809
|
+
() => ({ userId: signedUserId != null ? signedUserId : null, signature }),
|
|
7810
|
+
[signedUserId, signature]
|
|
7811
|
+
);
|
|
7206
7812
|
const enhance = (0, import_react6.useCallback)(
|
|
7207
7813
|
async (text, screenshot) => {
|
|
7208
7814
|
try {
|
|
@@ -7212,12 +7818,12 @@ function GlitchgrabProviderInner({
|
|
|
7212
7818
|
visitedPages: ctx.visitedPages.slice(-5),
|
|
7213
7819
|
breadcrumbs: ctx.breadcrumbs.slice(-10).map((b) => ({ type: b.type, message: b.message }))
|
|
7214
7820
|
};
|
|
7215
|
-
return await enhanceText(text, token, baseUrl, screenshot, context);
|
|
7821
|
+
return await enhanceText(text, token, baseUrl, screenshot, context, identity);
|
|
7216
7822
|
} catch (e) {
|
|
7217
7823
|
return text;
|
|
7218
7824
|
}
|
|
7219
7825
|
},
|
|
7220
|
-
[token, baseUrl]
|
|
7826
|
+
[token, baseUrl, identity]
|
|
7221
7827
|
);
|
|
7222
7828
|
const assist = (0, import_react6.useCallback)(
|
|
7223
7829
|
async (params) => {
|
|
@@ -7230,7 +7836,8 @@ function GlitchgrabProviderInner({
|
|
|
7230
7836
|
reporter: session ? {
|
|
7231
7837
|
key: session.userId,
|
|
7232
7838
|
name: session.name ? String(session.name) : null,
|
|
7233
|
-
email: session.email ? String(session.email) : null
|
|
7839
|
+
email: session.email ? String(session.email) : null,
|
|
7840
|
+
...signature ? { signature } : {}
|
|
7234
7841
|
} : void 0,
|
|
7235
7842
|
context: {
|
|
7236
7843
|
...(_a = params.context) != null ? _a : {},
|
|
@@ -7245,15 +7852,19 @@ function GlitchgrabProviderInner({
|
|
|
7245
7852
|
},
|
|
7246
7853
|
[token, baseUrl, session]
|
|
7247
7854
|
);
|
|
7855
|
+
const findSimilar = (0, import_react6.useCallback)(
|
|
7856
|
+
(description) => findSimilarIssues(description, token, baseUrl, identity),
|
|
7857
|
+
[token, baseUrl, identity]
|
|
7858
|
+
);
|
|
7248
7859
|
const transcribe = (0, import_react6.useCallback)(
|
|
7249
7860
|
async (blob) => {
|
|
7250
7861
|
try {
|
|
7251
|
-
return await transcribeAudio(blob, token, baseUrl);
|
|
7862
|
+
return await transcribeAudio(blob, token, baseUrl, identity);
|
|
7252
7863
|
} catch (e) {
|
|
7253
7864
|
return "";
|
|
7254
7865
|
}
|
|
7255
7866
|
},
|
|
7256
|
-
[token, baseUrl]
|
|
7867
|
+
[token, baseUrl, identity]
|
|
7257
7868
|
);
|
|
7258
7869
|
const openReportDialog = (0, import_react6.useCallback)((options) => {
|
|
7259
7870
|
if (typeof window !== "undefined") {
|
|
@@ -7271,6 +7882,8 @@ function GlitchgrabProviderInner({
|
|
|
7271
7882
|
const [projectName, setProjectName] = (0, import_react6.useState)(null);
|
|
7272
7883
|
const [aiAssist, setAiAssist] = (0, import_react6.useState)(false);
|
|
7273
7884
|
const [glitchgrabReport, setGlitchgrabReport] = (0, import_react6.useState)(false);
|
|
7885
|
+
const [signedUsers, setSignedUsers] = (0, import_react6.useState)("OFF");
|
|
7886
|
+
const aiBlockedUnsigned = signedUsers === "ENFORCE" && !signature;
|
|
7274
7887
|
const [bookingOpen, setBookingOpen] = (0, import_react6.useState)(false);
|
|
7275
7888
|
const openBookingDialog = (0, import_react6.useCallback)(() => setBookingOpen(true), []);
|
|
7276
7889
|
(0, import_react6.useEffect)(() => {
|
|
@@ -7283,12 +7896,25 @@ function GlitchgrabProviderInner({
|
|
|
7283
7896
|
setProjectName(json.data.name);
|
|
7284
7897
|
setAiAssist(json.data.aiAssist === true);
|
|
7285
7898
|
setGlitchgrabReport(json.data.glitchgrabReport === true);
|
|
7899
|
+
const mode = json.data.signedUsers;
|
|
7900
|
+
setSignedUsers(mode === "WARN" || mode === "ENFORCE" ? mode : "OFF");
|
|
7286
7901
|
}).catch(() => {
|
|
7287
7902
|
});
|
|
7288
7903
|
return () => {
|
|
7289
7904
|
cancelled = true;
|
|
7290
7905
|
};
|
|
7291
7906
|
}, [baseUrl, token]);
|
|
7907
|
+
(0, import_react6.useEffect)(() => {
|
|
7908
|
+
var _a;
|
|
7909
|
+
try {
|
|
7910
|
+
if (signedUsers === "OFF" || signature || !session) return;
|
|
7911
|
+
if (typeof process === "undefined" || ((_a = process.env) == null ? void 0 : _a.NODE_ENV) !== "development") return;
|
|
7912
|
+
console.warn(
|
|
7913
|
+
signedUsers === "ENFORCE" ? '[glitchgrab] This project enforces signed users and `session.signature` is missing \u2014 AI features are hidden. Sign it on your server with signSession() from "glitchgrab/server".' : '[glitchgrab] This project warns on unsigned users and `session.signature` is missing. Sign it on your server with signSession() from "glitchgrab/server" before the owner switches to Enforce.'
|
|
7914
|
+
);
|
|
7915
|
+
} catch (e) {
|
|
7916
|
+
}
|
|
7917
|
+
}, [signedUsers, signature, session]);
|
|
7292
7918
|
(0, import_react6.useEffect)(() => {
|
|
7293
7919
|
try {
|
|
7294
7920
|
if (typeof window === "undefined") return;
|
|
@@ -7363,10 +7989,11 @@ function GlitchgrabProviderInner({
|
|
|
7363
7989
|
{
|
|
7364
7990
|
report,
|
|
7365
7991
|
sendFeedback: feedback,
|
|
7366
|
-
enhanceText: enhance,
|
|
7367
|
-
assist: aiAssist ? assist : void 0,
|
|
7992
|
+
enhanceText: aiAssist && !aiBlockedUnsigned ? enhance : void 0,
|
|
7993
|
+
assist: aiAssist && !aiBlockedUnsigned ? assist : void 0,
|
|
7994
|
+
findSimilarIssues: aiAssist && !aiBlockedUnsigned ? findSimilar : void 0,
|
|
7368
7995
|
reportGlitchgrabProblem: glitchgrabReport ? reportGlitchgrabProblem : void 0,
|
|
7369
|
-
transcribeAudio: transcribe,
|
|
7996
|
+
transcribeAudio: aiBlockedUnsigned ? void 0 : transcribe,
|
|
7370
7997
|
types,
|
|
7371
7998
|
showSeverity,
|
|
7372
7999
|
reporter,
|