glitchgrab 1.44.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/dist/index.js +382 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +414 -82
- package/dist/index.mjs.map +1 -1
- package/dist/server.js.map +1 -1
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
useContext,
|
|
7
7
|
useRef as useRef5,
|
|
8
8
|
useEffect as useEffect6,
|
|
9
|
-
useCallback as
|
|
10
|
-
useMemo as
|
|
9
|
+
useCallback as useCallback3,
|
|
10
|
+
useMemo as useMemo4,
|
|
11
11
|
useState as useState6
|
|
12
12
|
} from "react";
|
|
13
13
|
|
|
@@ -711,7 +711,9 @@ async function assistTurn(params, token, baseUrl) {
|
|
|
711
711
|
conversationId: null,
|
|
712
712
|
question: null,
|
|
713
713
|
report: null,
|
|
714
|
-
degraded: (_a = envelope == null ? void 0 : envelope.error) != null ? _a : offline.degraded
|
|
714
|
+
degraded: (_a = envelope == null ? void 0 : envelope.error) != null ? _a : offline.degraded,
|
|
715
|
+
// An hourly limit, not a cap: the dialog keeps the assistant button.
|
|
716
|
+
retryable: (envelope == null ? void 0 : envelope.retryable) === true
|
|
715
717
|
};
|
|
716
718
|
}
|
|
717
719
|
return {
|
|
@@ -944,15 +946,15 @@ import {
|
|
|
944
946
|
useState as useState4,
|
|
945
947
|
useRef as useRef4,
|
|
946
948
|
useEffect as useEffect4,
|
|
947
|
-
useMemo
|
|
949
|
+
useMemo as useMemo2
|
|
948
950
|
} from "react";
|
|
949
951
|
import { createPortal as createPortal3 } from "react-dom";
|
|
950
952
|
import { useEffect, useRef, useState } from "react";
|
|
951
953
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
952
|
-
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
954
|
+
import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
953
955
|
import { createPortal } from "react-dom";
|
|
954
956
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
955
|
-
import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
957
|
+
import { useCallback, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
956
958
|
import { createPortal as createPortal2 } from "react-dom";
|
|
957
959
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
958
960
|
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -1313,6 +1315,59 @@ var SEVERITY_LABELS = {
|
|
|
1313
1315
|
};
|
|
1314
1316
|
var MAX_ASSIST_IMAGES = 3;
|
|
1315
1317
|
var MAX_ASSIST_IMAGE_CHARS = 35e5;
|
|
1318
|
+
var MAX_ASSIST_FILES = 3;
|
|
1319
|
+
var MAX_ASSIST_FILE_CHARS = 3e5;
|
|
1320
|
+
var MAX_ASSIST_FILE_CHARS_EACH = 2e5;
|
|
1321
|
+
var TEXT_ATTACHMENT_EXTENSIONS = [
|
|
1322
|
+
".html",
|
|
1323
|
+
".htm",
|
|
1324
|
+
".txt",
|
|
1325
|
+
".md",
|
|
1326
|
+
".json",
|
|
1327
|
+
".xml",
|
|
1328
|
+
".log",
|
|
1329
|
+
".yml",
|
|
1330
|
+
".yaml",
|
|
1331
|
+
".csv",
|
|
1332
|
+
".har",
|
|
1333
|
+
".js",
|
|
1334
|
+
".mjs",
|
|
1335
|
+
".cjs",
|
|
1336
|
+
".ts",
|
|
1337
|
+
".tsx",
|
|
1338
|
+
".jsx",
|
|
1339
|
+
".css",
|
|
1340
|
+
".scss",
|
|
1341
|
+
".py",
|
|
1342
|
+
".sh"
|
|
1343
|
+
];
|
|
1344
|
+
var BINARY_ATTACHMENT_EXTENSIONS = [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".zip"];
|
|
1345
|
+
var ATTACHMENT_ACCEPT = [
|
|
1346
|
+
"image/*",
|
|
1347
|
+
...TEXT_ATTACHMENT_EXTENSIONS,
|
|
1348
|
+
...BINARY_ATTACHMENT_EXTENSIONS
|
|
1349
|
+
].join(",");
|
|
1350
|
+
var ASSIST_ATTACHMENT_ACCEPT = ["image/*", ...TEXT_ATTACHMENT_EXTENSIONS].join(",");
|
|
1351
|
+
function isAssistReadableFile(name) {
|
|
1352
|
+
const lower = name.toLowerCase();
|
|
1353
|
+
return TEXT_ATTACHMENT_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
1354
|
+
}
|
|
1355
|
+
function decodeTextDataUrl(dataUrl) {
|
|
1356
|
+
try {
|
|
1357
|
+
if (!dataUrl.startsWith("data:")) return null;
|
|
1358
|
+
const comma = dataUrl.indexOf(",");
|
|
1359
|
+
if (comma < 0) return null;
|
|
1360
|
+
const meta = dataUrl.slice(5, comma);
|
|
1361
|
+
const payload = dataUrl.slice(comma + 1);
|
|
1362
|
+
if (!meta.endsWith(";base64")) return decodeURIComponent(payload);
|
|
1363
|
+
const binary = atob(payload);
|
|
1364
|
+
const bytes = new Uint8Array(binary.length);
|
|
1365
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1366
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
1367
|
+
} catch (e) {
|
|
1368
|
+
return null;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1316
1371
|
function getTypeLabel(type) {
|
|
1317
1372
|
switch (type) {
|
|
1318
1373
|
case "RATING":
|
|
@@ -1344,6 +1399,22 @@ function pickAssistImages(all) {
|
|
|
1344
1399
|
}
|
|
1345
1400
|
return picked;
|
|
1346
1401
|
}
|
|
1402
|
+
var NO_FILES = [];
|
|
1403
|
+
function pickAssistFiles(files) {
|
|
1404
|
+
const picked = [];
|
|
1405
|
+
let total = 0;
|
|
1406
|
+
for (let i = files.length - 1; i >= 0 && picked.length < MAX_ASSIST_FILES; i--) {
|
|
1407
|
+
const attached = files[i];
|
|
1408
|
+
if (!isAssistReadableFile(attached.name)) continue;
|
|
1409
|
+
const text = decodeTextDataUrl(attached.dataUrl);
|
|
1410
|
+
if (!text || !text.trim()) continue;
|
|
1411
|
+
const content = text.slice(0, MAX_ASSIST_FILE_CHARS_EACH);
|
|
1412
|
+
if (total + content.length > MAX_ASSIST_FILE_CHARS) continue;
|
|
1413
|
+
picked.unshift({ index: i, file: { name: attached.name, content } });
|
|
1414
|
+
total += content.length;
|
|
1415
|
+
}
|
|
1416
|
+
return picked;
|
|
1417
|
+
}
|
|
1347
1418
|
var STARTERS = [
|
|
1348
1419
|
"Something on this page is broken",
|
|
1349
1420
|
"It did the wrong thing",
|
|
@@ -1420,7 +1491,9 @@ function AssistSheet({
|
|
|
1420
1491
|
theme: t2,
|
|
1421
1492
|
screenshots,
|
|
1422
1493
|
pageShot = null,
|
|
1423
|
-
|
|
1494
|
+
onAddFiles,
|
|
1495
|
+
files = NO_FILES,
|
|
1496
|
+
onRemoveFile,
|
|
1424
1497
|
onRemoveImage,
|
|
1425
1498
|
attachmentCount,
|
|
1426
1499
|
context,
|
|
@@ -1491,6 +1564,8 @@ function AssistSheet({
|
|
|
1491
1564
|
}
|
|
1492
1565
|
}
|
|
1493
1566
|
const readShots = new Set(pickAssistImages(screenshots));
|
|
1567
|
+
const sentFiles = useMemo(() => pickAssistFiles(files), [files]);
|
|
1568
|
+
const readFiles = new Set(sentFiles.map((f) => f.index));
|
|
1494
1569
|
function leave(type, detail) {
|
|
1495
1570
|
logEvent(type, detail);
|
|
1496
1571
|
flushEvents();
|
|
@@ -1504,10 +1579,10 @@ function AssistSheet({
|
|
|
1504
1579
|
var _a;
|
|
1505
1580
|
if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
|
|
1506
1581
|
}, [phase]);
|
|
1507
|
-
function degradeKeepingEvents(events, message) {
|
|
1582
|
+
function degradeKeepingEvents(events, message, retryable) {
|
|
1508
1583
|
if (events) eventsRef.current = [...events, ...eventsRef.current];
|
|
1509
1584
|
flushEvents();
|
|
1510
|
-
onDegrade(message);
|
|
1585
|
+
onDegrade(message, retryable);
|
|
1511
1586
|
}
|
|
1512
1587
|
async function runTurn(history2) {
|
|
1513
1588
|
var _a, _b, _c, _d;
|
|
@@ -1525,6 +1600,9 @@ function AssistSheet({
|
|
|
1525
1600
|
),
|
|
1526
1601
|
conversationId,
|
|
1527
1602
|
screenshots: sent,
|
|
1603
|
+
// Only when there is something: an older server then sees the body
|
|
1604
|
+
// it always did.
|
|
1605
|
+
...sentFiles.length > 0 ? { files: sentFiles.map((f) => f.file) } : {},
|
|
1528
1606
|
context: {
|
|
1529
1607
|
...context != null ? context : {},
|
|
1530
1608
|
imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached"),
|
|
@@ -1544,7 +1622,7 @@ function AssistSheet({
|
|
|
1544
1622
|
setBusy(false);
|
|
1545
1623
|
}
|
|
1546
1624
|
if (result.degraded) {
|
|
1547
|
-
degradeKeepingEvents(events, result.degraded);
|
|
1625
|
+
degradeKeepingEvents(events, result.degraded, result.retryable === true);
|
|
1548
1626
|
return;
|
|
1549
1627
|
}
|
|
1550
1628
|
if (result.conversationId) {
|
|
@@ -2532,7 +2610,7 @@ function AssistSheet({
|
|
|
2532
2610
|
// instead of remounting, and a draft is something you can
|
|
2533
2611
|
// still reply to (#360), not a form that replaced the chat.
|
|
2534
2612
|
/* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
2535
|
-
(screenshots.length > 0 ||
|
|
2613
|
+
(screenshots.length > 0 || files.length > 0 || onAddFiles) && /* @__PURE__ */ jsxs2(
|
|
2536
2614
|
"div",
|
|
2537
2615
|
{
|
|
2538
2616
|
style: {
|
|
@@ -2636,11 +2714,118 @@ function AssistSheet({
|
|
|
2636
2714
|
`${i}-${shot.slice(-16)}`
|
|
2637
2715
|
);
|
|
2638
2716
|
}),
|
|
2639
|
-
|
|
2717
|
+
files.map((file, i) => {
|
|
2718
|
+
const read = readFiles.has(i);
|
|
2719
|
+
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";
|
|
2720
|
+
return /* @__PURE__ */ jsxs2(
|
|
2721
|
+
"div",
|
|
2722
|
+
{
|
|
2723
|
+
"data-gg-assist-file": "",
|
|
2724
|
+
"data-gg-assist-file-read": read ? "" : void 0,
|
|
2725
|
+
title: `${file.name} \u2014 ${why}`,
|
|
2726
|
+
style: {
|
|
2727
|
+
position: "relative",
|
|
2728
|
+
height: "40px",
|
|
2729
|
+
maxWidth: "170px",
|
|
2730
|
+
display: "flex",
|
|
2731
|
+
alignItems: "center",
|
|
2732
|
+
gap: "6px",
|
|
2733
|
+
padding: "0 10px",
|
|
2734
|
+
borderRadius: "8px",
|
|
2735
|
+
border: `1px solid ${read ? t2.accent : t2.inputBorder}`,
|
|
2736
|
+
opacity: read ? 1 : 0.55,
|
|
2737
|
+
boxSizing: "border-box",
|
|
2738
|
+
flexShrink: 0
|
|
2739
|
+
},
|
|
2740
|
+
children: [
|
|
2741
|
+
/* @__PURE__ */ jsx2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx2(
|
|
2742
|
+
"path",
|
|
2743
|
+
{
|
|
2744
|
+
d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6",
|
|
2745
|
+
stroke: t2.textMuted,
|
|
2746
|
+
strokeWidth: "1.5",
|
|
2747
|
+
strokeLinecap: "round",
|
|
2748
|
+
strokeLinejoin: "round"
|
|
2749
|
+
}
|
|
2750
|
+
) }),
|
|
2751
|
+
/* @__PURE__ */ jsx2(
|
|
2752
|
+
"span",
|
|
2753
|
+
{
|
|
2754
|
+
style: {
|
|
2755
|
+
fontSize: "11.5px",
|
|
2756
|
+
color: t2.text,
|
|
2757
|
+
overflow: "hidden",
|
|
2758
|
+
textOverflow: "ellipsis",
|
|
2759
|
+
whiteSpace: "nowrap"
|
|
2760
|
+
},
|
|
2761
|
+
children: file.name
|
|
2762
|
+
}
|
|
2763
|
+
),
|
|
2764
|
+
onRemoveFile && /* @__PURE__ */ jsx2(
|
|
2765
|
+
"button",
|
|
2766
|
+
{
|
|
2767
|
+
type: "button",
|
|
2768
|
+
"data-gg-assist-remove-file": "",
|
|
2769
|
+
"aria-label": `Remove file ${file.name}`,
|
|
2770
|
+
title: "Remove this file",
|
|
2771
|
+
onClick: () => {
|
|
2772
|
+
logEvent("file_removed", read ? "read" : "not read");
|
|
2773
|
+
onRemoveFile(i);
|
|
2774
|
+
},
|
|
2775
|
+
style: {
|
|
2776
|
+
position: "absolute",
|
|
2777
|
+
top: "-13px",
|
|
2778
|
+
right: "-13px",
|
|
2779
|
+
width: "32px",
|
|
2780
|
+
height: "32px",
|
|
2781
|
+
border: "none",
|
|
2782
|
+
background: "transparent",
|
|
2783
|
+
padding: 0,
|
|
2784
|
+
cursor: "pointer",
|
|
2785
|
+
display: "flex",
|
|
2786
|
+
alignItems: "center",
|
|
2787
|
+
justifyContent: "center",
|
|
2788
|
+
borderRadius: "50%"
|
|
2789
|
+
},
|
|
2790
|
+
children: /* @__PURE__ */ jsx2(
|
|
2791
|
+
"span",
|
|
2792
|
+
{
|
|
2793
|
+
"aria-hidden": "true",
|
|
2794
|
+
style: {
|
|
2795
|
+
width: "20px",
|
|
2796
|
+
height: "20px",
|
|
2797
|
+
boxSizing: "border-box",
|
|
2798
|
+
borderRadius: "50%",
|
|
2799
|
+
border: `2px solid ${t2.bg}`,
|
|
2800
|
+
background: "#ef4444",
|
|
2801
|
+
color: "#fff",
|
|
2802
|
+
display: "flex",
|
|
2803
|
+
alignItems: "center",
|
|
2804
|
+
justifyContent: "center"
|
|
2805
|
+
},
|
|
2806
|
+
children: /* @__PURE__ */ jsx2("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx2(
|
|
2807
|
+
"path",
|
|
2808
|
+
{
|
|
2809
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
2810
|
+
stroke: "currentColor",
|
|
2811
|
+
strokeWidth: "1.6",
|
|
2812
|
+
strokeLinecap: "round"
|
|
2813
|
+
}
|
|
2814
|
+
) })
|
|
2815
|
+
}
|
|
2816
|
+
)
|
|
2817
|
+
}
|
|
2818
|
+
)
|
|
2819
|
+
]
|
|
2820
|
+
},
|
|
2821
|
+
`file-${i}-${file.name}`
|
|
2822
|
+
);
|
|
2823
|
+
}),
|
|
2824
|
+
onAddFiles && /* @__PURE__ */ jsxs2(
|
|
2640
2825
|
"label",
|
|
2641
2826
|
{
|
|
2642
2827
|
"data-gg-assist-attach": "",
|
|
2643
|
-
title: "Attach an image \u2014 or
|
|
2828
|
+
title: "Attach an image or a file (html, json, log\u2026) \u2014 or paste one",
|
|
2644
2829
|
style: {
|
|
2645
2830
|
width: "40px",
|
|
2646
2831
|
height: "40px",
|
|
@@ -2660,14 +2845,18 @@ function AssistSheet({
|
|
|
2660
2845
|
"input",
|
|
2661
2846
|
{
|
|
2662
2847
|
type: "file",
|
|
2663
|
-
accept:
|
|
2848
|
+
accept: ASSIST_ATTACHMENT_ACCEPT,
|
|
2664
2849
|
multiple: true,
|
|
2665
2850
|
onChange: (e) => {
|
|
2666
2851
|
var _a;
|
|
2667
|
-
const
|
|
2668
|
-
if (
|
|
2669
|
-
|
|
2670
|
-
|
|
2852
|
+
const picked = Array.from((_a = e.target.files) != null ? _a : []);
|
|
2853
|
+
if (picked.length) {
|
|
2854
|
+
const images = picked.filter((f) => f.type.startsWith("image/")).length;
|
|
2855
|
+
if (images) logEvent("image_added", String(images));
|
|
2856
|
+
if (picked.length > images) {
|
|
2857
|
+
logEvent("file_added", String(picked.length - images));
|
|
2858
|
+
}
|
|
2859
|
+
onAddFiles(picked);
|
|
2671
2860
|
}
|
|
2672
2861
|
e.target.value = "";
|
|
2673
2862
|
},
|
|
@@ -2848,6 +3037,7 @@ function AssistSheet({
|
|
|
2848
3037
|
}
|
|
2849
3038
|
var FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2850
3039
|
var FAILED = "Couldn't send it. Try again in a moment.";
|
|
3040
|
+
var MAX_SELF_REPORT_IMAGES = 5;
|
|
2851
3041
|
function describeSentAlong(hasChat, screenshotCount) {
|
|
2852
3042
|
const parts = [
|
|
2853
3043
|
...hasChat ? ["your AI chat"] : [],
|
|
@@ -2871,11 +3061,49 @@ function GlitchgrabProblemPanel({
|
|
|
2871
3061
|
const [busy, setBusy] = useState3(false);
|
|
2872
3062
|
const [sent, setSent] = useState3(false);
|
|
2873
3063
|
const [error, setError] = useState3(null);
|
|
3064
|
+
const [images, setImages] = useState3(
|
|
3065
|
+
() => screenshots.slice(0, MAX_SELF_REPORT_IMAGES)
|
|
3066
|
+
);
|
|
2874
3067
|
const inputRef = useRef3(null);
|
|
3068
|
+
const fileRef = useRef3(null);
|
|
2875
3069
|
useEffect3(() => {
|
|
2876
3070
|
var _a;
|
|
2877
3071
|
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
2878
3072
|
}, []);
|
|
3073
|
+
const addImages = useCallback((files) => {
|
|
3074
|
+
const picked = files.filter((file) => file.type.startsWith("image/"));
|
|
3075
|
+
if (!picked.length) return;
|
|
3076
|
+
void Promise.all(picked.map((file) => encodeImageFile(file).catch(() => null))).then(
|
|
3077
|
+
(encoded) => {
|
|
3078
|
+
const added = encoded.filter((url) => !!url);
|
|
3079
|
+
if (added.length) {
|
|
3080
|
+
setImages((prev) => [...prev, ...added].slice(0, MAX_SELF_REPORT_IMAGES));
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
);
|
|
3084
|
+
}, []);
|
|
3085
|
+
useEffect3(() => {
|
|
3086
|
+
const onPaste = (e) => {
|
|
3087
|
+
var _a;
|
|
3088
|
+
try {
|
|
3089
|
+
const items = (_a = e.clipboardData) == null ? void 0 : _a.items;
|
|
3090
|
+
if (!items) return;
|
|
3091
|
+
const files = [];
|
|
3092
|
+
for (let i = 0; i < items.length; i++) {
|
|
3093
|
+
if (items[i].kind !== "file") continue;
|
|
3094
|
+
const file = items[i].getAsFile();
|
|
3095
|
+
if (file) files.push(file);
|
|
3096
|
+
}
|
|
3097
|
+
if (!files.length) return;
|
|
3098
|
+
e.preventDefault();
|
|
3099
|
+
e.stopImmediatePropagation();
|
|
3100
|
+
addImages(files);
|
|
3101
|
+
} catch (e2) {
|
|
3102
|
+
}
|
|
3103
|
+
};
|
|
3104
|
+
window.addEventListener("paste", onPaste, true);
|
|
3105
|
+
return () => window.removeEventListener("paste", onPaste, true);
|
|
3106
|
+
}, [addImages]);
|
|
2879
3107
|
useEffect3(() => {
|
|
2880
3108
|
const onKey = (e) => {
|
|
2881
3109
|
if (e.key !== "Escape") return;
|
|
@@ -2891,7 +3119,13 @@ function GlitchgrabProblemPanel({
|
|
|
2891
3119
|
setBusy(true);
|
|
2892
3120
|
setError(null);
|
|
2893
3121
|
try {
|
|
2894
|
-
const result = await send({
|
|
3122
|
+
const result = await send({
|
|
3123
|
+
description,
|
|
3124
|
+
surface,
|
|
3125
|
+
conversationId,
|
|
3126
|
+
reportType,
|
|
3127
|
+
screenshots: images
|
|
3128
|
+
});
|
|
2895
3129
|
if (result == null ? void 0 : result.success) setSent(true);
|
|
2896
3130
|
else setError((result == null ? void 0 : result.message) || FAILED);
|
|
2897
3131
|
} catch (e) {
|
|
@@ -3044,6 +3278,134 @@ function GlitchgrabProblemPanel({
|
|
|
3044
3278
|
}
|
|
3045
3279
|
}
|
|
3046
3280
|
),
|
|
3281
|
+
/* @__PURE__ */ jsxs3(
|
|
3282
|
+
"div",
|
|
3283
|
+
{
|
|
3284
|
+
"data-gg-self-report-images": "",
|
|
3285
|
+
style: {
|
|
3286
|
+
display: "flex",
|
|
3287
|
+
flexWrap: "wrap",
|
|
3288
|
+
alignItems: "center",
|
|
3289
|
+
gap: "8px",
|
|
3290
|
+
marginTop: "10px"
|
|
3291
|
+
},
|
|
3292
|
+
children: [
|
|
3293
|
+
images.map((src, i) => /* @__PURE__ */ jsxs3("div", { style: { position: "relative", width: "48px", height: "48px" }, children: [
|
|
3294
|
+
/* @__PURE__ */ jsx3(
|
|
3295
|
+
"img",
|
|
3296
|
+
{
|
|
3297
|
+
src,
|
|
3298
|
+
alt: `Screenshot ${i + 1}`,
|
|
3299
|
+
style: {
|
|
3300
|
+
width: "100%",
|
|
3301
|
+
height: "100%",
|
|
3302
|
+
objectFit: "cover",
|
|
3303
|
+
display: "block",
|
|
3304
|
+
boxSizing: "border-box",
|
|
3305
|
+
borderRadius: "8px",
|
|
3306
|
+
border: `1px solid ${t2.inputBorder}`
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
),
|
|
3310
|
+
/* @__PURE__ */ jsx3(
|
|
3311
|
+
"button",
|
|
3312
|
+
{
|
|
3313
|
+
type: "button",
|
|
3314
|
+
"data-gg-self-report-remove-image": "",
|
|
3315
|
+
"aria-label": `Remove screenshot ${i + 1}`,
|
|
3316
|
+
title: "Don't send this one",
|
|
3317
|
+
onClick: () => setImages((prev) => prev.filter((_, j) => j !== i)),
|
|
3318
|
+
style: {
|
|
3319
|
+
position: "absolute",
|
|
3320
|
+
top: "-13px",
|
|
3321
|
+
right: "-13px",
|
|
3322
|
+
width: "32px",
|
|
3323
|
+
height: "32px",
|
|
3324
|
+
border: "none",
|
|
3325
|
+
background: "transparent",
|
|
3326
|
+
padding: 0,
|
|
3327
|
+
cursor: "pointer",
|
|
3328
|
+
display: "flex",
|
|
3329
|
+
alignItems: "center",
|
|
3330
|
+
justifyContent: "center",
|
|
3331
|
+
borderRadius: "50%"
|
|
3332
|
+
},
|
|
3333
|
+
children: /* @__PURE__ */ jsx3(
|
|
3334
|
+
"span",
|
|
3335
|
+
{
|
|
3336
|
+
"aria-hidden": "true",
|
|
3337
|
+
style: {
|
|
3338
|
+
width: "20px",
|
|
3339
|
+
height: "20px",
|
|
3340
|
+
boxSizing: "border-box",
|
|
3341
|
+
borderRadius: "50%",
|
|
3342
|
+
border: `2px solid ${t2.bg}`,
|
|
3343
|
+
background: "#ef4444",
|
|
3344
|
+
color: "#fff",
|
|
3345
|
+
display: "flex",
|
|
3346
|
+
alignItems: "center",
|
|
3347
|
+
justifyContent: "center"
|
|
3348
|
+
},
|
|
3349
|
+
children: /* @__PURE__ */ jsx3("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx3(
|
|
3350
|
+
"path",
|
|
3351
|
+
{
|
|
3352
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
3353
|
+
stroke: "currentColor",
|
|
3354
|
+
strokeWidth: "1.6",
|
|
3355
|
+
strokeLinecap: "round"
|
|
3356
|
+
}
|
|
3357
|
+
) })
|
|
3358
|
+
}
|
|
3359
|
+
)
|
|
3360
|
+
}
|
|
3361
|
+
)
|
|
3362
|
+
] }, i)),
|
|
3363
|
+
images.length < MAX_SELF_REPORT_IMAGES && /* @__PURE__ */ jsx3(
|
|
3364
|
+
"button",
|
|
3365
|
+
{
|
|
3366
|
+
type: "button",
|
|
3367
|
+
"data-gg-self-report-attach": "",
|
|
3368
|
+
"aria-label": "Add screenshot",
|
|
3369
|
+
title: "Add a screenshot \u2014 or paste one",
|
|
3370
|
+
onClick: () => {
|
|
3371
|
+
var _a;
|
|
3372
|
+
return (_a = fileRef.current) == null ? void 0 : _a.click();
|
|
3373
|
+
},
|
|
3374
|
+
style: {
|
|
3375
|
+
height: "48px",
|
|
3376
|
+
padding: "0 12px",
|
|
3377
|
+
boxSizing: "border-box",
|
|
3378
|
+
borderRadius: "8px",
|
|
3379
|
+
border: `1px dashed ${t2.inputBorder}`,
|
|
3380
|
+
background: "transparent",
|
|
3381
|
+
color: t2.textMuted,
|
|
3382
|
+
fontSize: "12.5px",
|
|
3383
|
+
fontWeight: 600,
|
|
3384
|
+
fontFamily: "inherit",
|
|
3385
|
+
cursor: "pointer"
|
|
3386
|
+
},
|
|
3387
|
+
children: images.length >= 3 ? "+ Add" : "+ Add screenshot"
|
|
3388
|
+
}
|
|
3389
|
+
),
|
|
3390
|
+
/* @__PURE__ */ jsx3(
|
|
3391
|
+
"input",
|
|
3392
|
+
{
|
|
3393
|
+
ref: fileRef,
|
|
3394
|
+
type: "file",
|
|
3395
|
+
accept: "image/*",
|
|
3396
|
+
multiple: true,
|
|
3397
|
+
"data-gg-self-report-file": "",
|
|
3398
|
+
onChange: (e) => {
|
|
3399
|
+
var _a;
|
|
3400
|
+
addImages(Array.from((_a = e.target.files) != null ? _a : []));
|
|
3401
|
+
e.target.value = "";
|
|
3402
|
+
},
|
|
3403
|
+
style: { display: "none" }
|
|
3404
|
+
}
|
|
3405
|
+
)
|
|
3406
|
+
]
|
|
3407
|
+
}
|
|
3408
|
+
),
|
|
3047
3409
|
/* @__PURE__ */ jsxs3(
|
|
3048
3410
|
"p",
|
|
3049
3411
|
{
|
|
@@ -3052,7 +3414,7 @@ function GlitchgrabProblemPanel({
|
|
|
3052
3414
|
children: [
|
|
3053
3415
|
"Also sent, so we can see what happened:",
|
|
3054
3416
|
" ",
|
|
3055
|
-
describeSentAlong(conversationId !== null,
|
|
3417
|
+
describeSentAlong(conversationId !== null, images.length),
|
|
3056
3418
|
"."
|
|
3057
3419
|
]
|
|
3058
3420
|
}
|
|
@@ -3093,38 +3455,6 @@ function isMac() {
|
|
|
3093
3455
|
function getShortcutLabel() {
|
|
3094
3456
|
return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;
|
|
3095
3457
|
}
|
|
3096
|
-
var ATTACHMENT_ACCEPT = [
|
|
3097
|
-
"image/*",
|
|
3098
|
-
// text — inlined into the issue body
|
|
3099
|
-
".html",
|
|
3100
|
-
".htm",
|
|
3101
|
-
".txt",
|
|
3102
|
-
".md",
|
|
3103
|
-
".json",
|
|
3104
|
-
".xml",
|
|
3105
|
-
".log",
|
|
3106
|
-
".yml",
|
|
3107
|
-
".yaml",
|
|
3108
|
-
".csv",
|
|
3109
|
-
".har",
|
|
3110
|
-
".js",
|
|
3111
|
-
".mjs",
|
|
3112
|
-
".cjs",
|
|
3113
|
-
".ts",
|
|
3114
|
-
".tsx",
|
|
3115
|
-
".jsx",
|
|
3116
|
-
".css",
|
|
3117
|
-
".scss",
|
|
3118
|
-
".py",
|
|
3119
|
-
".sh",
|
|
3120
|
-
// binary documents
|
|
3121
|
-
".pdf",
|
|
3122
|
-
".doc",
|
|
3123
|
-
".docx",
|
|
3124
|
-
".xls",
|
|
3125
|
-
".xlsx",
|
|
3126
|
-
".zip"
|
|
3127
|
-
].join(",");
|
|
3128
3458
|
var MAX_SCALE = 2;
|
|
3129
3459
|
var FRAME_TIMEOUT_MS = 3e3;
|
|
3130
3460
|
var GRAB_TIMEOUT_MS = FRAME_TIMEOUT_MS + 2e3;
|
|
@@ -3770,7 +4100,7 @@ function ReportDialog({
|
|
|
3770
4100
|
const next = current === -1 ? 0 : Math.min(Math.max(current + delta, 0), tiles.length - 1);
|
|
3771
4101
|
(_c = tiles[next]) == null ? void 0 : _c.focus();
|
|
3772
4102
|
};
|
|
3773
|
-
const isDark =
|
|
4103
|
+
const isDark = useMemo2(() => isOpen ? detectDark() : true, [isOpen]);
|
|
3774
4104
|
const t2 = getTheme(isDark);
|
|
3775
4105
|
const layerTheme = {
|
|
3776
4106
|
bg: t2.bg,
|
|
@@ -6354,8 +6684,10 @@ function ReportDialog({
|
|
|
6354
6684
|
theme: layerTheme,
|
|
6355
6685
|
screenshots,
|
|
6356
6686
|
pageShot,
|
|
6357
|
-
|
|
6687
|
+
onAddFiles: addFiles,
|
|
6358
6688
|
onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
|
|
6689
|
+
files: attachments,
|
|
6690
|
+
onRemoveFile: (index) => setAttachments((prev) => prev.filter((_, i) => i !== index)),
|
|
6359
6691
|
attachmentCount: screenshots.length + attachments.length,
|
|
6360
6692
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|
|
6361
6693
|
reportTypeLabel: getTypeLabel(reportType),
|
|
@@ -6397,9 +6729,9 @@ function ReportDialog({
|
|
|
6397
6729
|
setSelfReportPrefill(prefill != null ? prefill : "");
|
|
6398
6730
|
setSelfReportFrom("assist");
|
|
6399
6731
|
} : void 0,
|
|
6400
|
-
onDegrade: (message) => {
|
|
6732
|
+
onDegrade: (message, retryable) => {
|
|
6401
6733
|
setAssistOpen(false);
|
|
6402
|
-
setAssistUsed(true);
|
|
6734
|
+
if (!retryable) setAssistUsed(true);
|
|
6403
6735
|
setAssistNotice(message);
|
|
6404
6736
|
},
|
|
6405
6737
|
onClose: () => {
|
|
@@ -6545,7 +6877,7 @@ function getTypeIcon(type, color, size = 24) {
|
|
|
6545
6877
|
}
|
|
6546
6878
|
|
|
6547
6879
|
// src/booking-dialog.tsx
|
|
6548
|
-
import { useCallback, useEffect as useEffect5, useMemo as
|
|
6880
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
|
|
6549
6881
|
import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
6550
6882
|
var t = {
|
|
6551
6883
|
bg: "#141414",
|
|
@@ -6600,11 +6932,11 @@ function BookingDialog({
|
|
|
6600
6932
|
const [meetUrl, setMeetUrl] = useState5(null);
|
|
6601
6933
|
const [busy, setBusy] = useState5(false);
|
|
6602
6934
|
const [error, setError] = useState5(null);
|
|
6603
|
-
const headers =
|
|
6935
|
+
const headers = useMemo3(
|
|
6604
6936
|
() => ({ Authorization: `Bearer ${token}`, "Content-Type": "application/json" }),
|
|
6605
6937
|
[token]
|
|
6606
6938
|
);
|
|
6607
|
-
const loadSlots =
|
|
6939
|
+
const loadSlots = useCallback2(async () => {
|
|
6608
6940
|
var _a2, _b, _c;
|
|
6609
6941
|
setError(null);
|
|
6610
6942
|
setSlots(null);
|
|
@@ -7111,7 +7443,7 @@ function GlitchgrabProviderInner({
|
|
|
7111
7443
|
sessionProp.avatarUrl,
|
|
7112
7444
|
sessionProp.image
|
|
7113
7445
|
].map((v) => v == null ? "" : String(v)).join("\0") : "";
|
|
7114
|
-
const session =
|
|
7446
|
+
const session = useMemo4(() => sessionProp, [sessionKey]);
|
|
7115
7447
|
setRelease(release2);
|
|
7116
7448
|
if (appContext2) setContexts(appContext2);
|
|
7117
7449
|
registerCaptureConfig({
|
|
@@ -7292,7 +7624,7 @@ function GlitchgrabProviderInner({
|
|
|
7292
7624
|
} catch (e) {
|
|
7293
7625
|
}
|
|
7294
7626
|
}, [token, baseUrl, onError, onReportSent, session, ignoreErrors]);
|
|
7295
|
-
const report =
|
|
7627
|
+
const report = useCallback3(
|
|
7296
7628
|
async (type, description, metadata) => {
|
|
7297
7629
|
var _a;
|
|
7298
7630
|
try {
|
|
@@ -7326,11 +7658,11 @@ function GlitchgrabProviderInner({
|
|
|
7326
7658
|
},
|
|
7327
7659
|
[token, baseUrl, onReportSent, session]
|
|
7328
7660
|
);
|
|
7329
|
-
const reportBug =
|
|
7661
|
+
const reportBug = useCallback3(
|
|
7330
7662
|
(description, metadata) => report("BUG", description, metadata),
|
|
7331
7663
|
[report]
|
|
7332
7664
|
);
|
|
7333
|
-
const reportGlitchgrabProblem =
|
|
7665
|
+
const reportGlitchgrabProblem = useCallback3(
|
|
7334
7666
|
async (params) => {
|
|
7335
7667
|
var _a, _b;
|
|
7336
7668
|
try {
|
|
@@ -7364,7 +7696,7 @@ function GlitchgrabProviderInner({
|
|
|
7364
7696
|
},
|
|
7365
7697
|
[token, baseUrl, session]
|
|
7366
7698
|
);
|
|
7367
|
-
const feedback =
|
|
7699
|
+
const feedback = useCallback3(
|
|
7368
7700
|
async (rating, message, metadata) => {
|
|
7369
7701
|
try {
|
|
7370
7702
|
const context = captureContext(visitedPagesRef.current);
|
|
@@ -7392,26 +7724,26 @@ function GlitchgrabProviderInner({
|
|
|
7392
7724
|
},
|
|
7393
7725
|
[token, baseUrl, session]
|
|
7394
7726
|
);
|
|
7395
|
-
const openFeedbackDialog =
|
|
7727
|
+
const openFeedbackDialog = useCallback3(() => {
|
|
7396
7728
|
if (typeof window !== "undefined") {
|
|
7397
7729
|
window.dispatchEvent(
|
|
7398
7730
|
new CustomEvent("glitchgrab:open-report", { detail: { type: "RATING" } })
|
|
7399
7731
|
);
|
|
7400
7732
|
}
|
|
7401
7733
|
}, []);
|
|
7402
|
-
const captureError2 =
|
|
7734
|
+
const captureError2 = useCallback3(
|
|
7403
7735
|
(error, options) => {
|
|
7404
7736
|
captureError(error, options);
|
|
7405
7737
|
},
|
|
7406
7738
|
[]
|
|
7407
7739
|
);
|
|
7408
|
-
const setContext2 =
|
|
7740
|
+
const setContext2 = useCallback3((key, value) => {
|
|
7409
7741
|
setContext(key, value);
|
|
7410
7742
|
}, []);
|
|
7411
|
-
const setContexts2 =
|
|
7743
|
+
const setContexts2 = useCallback3((values) => {
|
|
7412
7744
|
setContexts(values);
|
|
7413
7745
|
}, []);
|
|
7414
|
-
const addBreadcrumb2 =
|
|
7746
|
+
const addBreadcrumb2 = useCallback3(
|
|
7415
7747
|
(message, data) => {
|
|
7416
7748
|
addBreadcrumb("custom", message, data);
|
|
7417
7749
|
},
|
|
@@ -7419,11 +7751,11 @@ function GlitchgrabProviderInner({
|
|
|
7419
7751
|
);
|
|
7420
7752
|
const signedUserId = session == null ? void 0 : session.userId;
|
|
7421
7753
|
const signature = typeof (session == null ? void 0 : session.signature) === "string" ? session.signature : null;
|
|
7422
|
-
const identity =
|
|
7754
|
+
const identity = useMemo4(
|
|
7423
7755
|
() => ({ userId: signedUserId != null ? signedUserId : null, signature }),
|
|
7424
7756
|
[signedUserId, signature]
|
|
7425
7757
|
);
|
|
7426
|
-
const enhance =
|
|
7758
|
+
const enhance = useCallback3(
|
|
7427
7759
|
async (text, screenshot) => {
|
|
7428
7760
|
try {
|
|
7429
7761
|
const ctx = captureContext(visitedPagesRef.current);
|
|
@@ -7439,7 +7771,7 @@ function GlitchgrabProviderInner({
|
|
|
7439
7771
|
},
|
|
7440
7772
|
[token, baseUrl, identity]
|
|
7441
7773
|
);
|
|
7442
|
-
const assist =
|
|
7774
|
+
const assist = useCallback3(
|
|
7443
7775
|
async (params) => {
|
|
7444
7776
|
var _a;
|
|
7445
7777
|
const ctx = captureContext(visitedPagesRef.current);
|
|
@@ -7466,11 +7798,11 @@ function GlitchgrabProviderInner({
|
|
|
7466
7798
|
},
|
|
7467
7799
|
[token, baseUrl, session]
|
|
7468
7800
|
);
|
|
7469
|
-
const findSimilar =
|
|
7801
|
+
const findSimilar = useCallback3(
|
|
7470
7802
|
(description) => findSimilarIssues(description, token, baseUrl, identity),
|
|
7471
7803
|
[token, baseUrl, identity]
|
|
7472
7804
|
);
|
|
7473
|
-
const transcribe =
|
|
7805
|
+
const transcribe = useCallback3(
|
|
7474
7806
|
async (blob) => {
|
|
7475
7807
|
try {
|
|
7476
7808
|
return await transcribeAudio(blob, token, baseUrl, identity);
|
|
@@ -7480,7 +7812,7 @@ function GlitchgrabProviderInner({
|
|
|
7480
7812
|
},
|
|
7481
7813
|
[token, baseUrl, identity]
|
|
7482
7814
|
);
|
|
7483
|
-
const openReportDialog =
|
|
7815
|
+
const openReportDialog = useCallback3((options) => {
|
|
7484
7816
|
if (typeof window !== "undefined") {
|
|
7485
7817
|
window.dispatchEvent(new CustomEvent("glitchgrab:open-report", { detail: options }));
|
|
7486
7818
|
}
|
|
@@ -7499,7 +7831,7 @@ function GlitchgrabProviderInner({
|
|
|
7499
7831
|
const [signedUsers, setSignedUsers] = useState6("OFF");
|
|
7500
7832
|
const aiBlockedUnsigned = signedUsers === "ENFORCE" && !signature;
|
|
7501
7833
|
const [bookingOpen, setBookingOpen] = useState6(false);
|
|
7502
|
-
const openBookingDialog =
|
|
7834
|
+
const openBookingDialog = useCallback3(() => setBookingOpen(true), []);
|
|
7503
7835
|
useEffect6(() => {
|
|
7504
7836
|
let cancelled = false;
|
|
7505
7837
|
fetch(`${baseUrl}/api/v1/sdk/project`, {
|
|
@@ -7543,7 +7875,7 @@ function GlitchgrabProviderInner({
|
|
|
7543
7875
|
} catch (e) {
|
|
7544
7876
|
}
|
|
7545
7877
|
}, [openReportDialog]);
|
|
7546
|
-
const reporter =
|
|
7878
|
+
const reporter = useMemo4(() => {
|
|
7547
7879
|
var _a;
|
|
7548
7880
|
if (!session) return null;
|
|
7549
7881
|
const avatar = (_a = session.avatarUrl) != null ? _a : session.image;
|
|
@@ -7842,7 +8174,7 @@ function FeedbackButton({
|
|
|
7842
8174
|
}
|
|
7843
8175
|
|
|
7844
8176
|
// src/use-reports.ts
|
|
7845
|
-
import { useState as useState8, useEffect as useEffect7, useCallback as
|
|
8177
|
+
import { useState as useState8, useEffect as useEffect7, useCallback as useCallback4 } from "react";
|
|
7846
8178
|
var BASE_URL = "https://glitchgrab.dev";
|
|
7847
8179
|
function useGlitchgrabReports({
|
|
7848
8180
|
token,
|
|
@@ -7853,7 +8185,7 @@ function useGlitchgrabReports({
|
|
|
7853
8185
|
const [isLoading, setIsLoading] = useState8(true);
|
|
7854
8186
|
const [isFetching, setIsFetching] = useState8(false);
|
|
7855
8187
|
const [error, setError] = useState8(null);
|
|
7856
|
-
const fetchReports =
|
|
8188
|
+
const fetchReports = useCallback4(async () => {
|
|
7857
8189
|
var _a, _b;
|
|
7858
8190
|
if (!token || !userId) {
|
|
7859
8191
|
setIsLoading(false);
|
|
@@ -7918,7 +8250,7 @@ function useGlitchgrabActions({
|
|
|
7918
8250
|
}) {
|
|
7919
8251
|
const [isPending, setIsPending] = useState8(false);
|
|
7920
8252
|
const [error, setError] = useState8(null);
|
|
7921
|
-
const run =
|
|
8253
|
+
const run = useCallback4(
|
|
7922
8254
|
async (reportId, body) => {
|
|
7923
8255
|
setIsPending(true);
|
|
7924
8256
|
setError(null);
|
|
@@ -7948,7 +8280,7 @@ function useGlitchgrabActions({
|
|
|
7948
8280
|
}
|
|
7949
8281
|
|
|
7950
8282
|
// src/use-feedback.ts
|
|
7951
|
-
import { useState as useState9, useEffect as useEffect8, useCallback as
|
|
8283
|
+
import { useState as useState9, useEffect as useEffect8, useCallback as useCallback5 } from "react";
|
|
7952
8284
|
var DEFAULT_BASE_URL3 = "https://glitchgrab.dev";
|
|
7953
8285
|
function buildUrl({
|
|
7954
8286
|
approvedOnly,
|
|
@@ -7978,7 +8310,7 @@ function useGlitchgrabFeedback(query) {
|
|
|
7978
8310
|
const [isLoading, setIsLoading] = useState9(true);
|
|
7979
8311
|
const [isFetching, setIsFetching] = useState9(false);
|
|
7980
8312
|
const [error, setError] = useState9(null);
|
|
7981
|
-
const load =
|
|
8313
|
+
const load = useCallback5(async () => {
|
|
7982
8314
|
if (!token) {
|
|
7983
8315
|
setIsLoading(false);
|
|
7984
8316
|
return;
|