glitchgrab 1.41.0 → 1.42.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 +390 -269
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +390 -269
- 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.js
CHANGED
|
@@ -904,6 +904,7 @@ var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
|
904
904
|
var MAX_SCREENSHOT_DATA_URL_LENGTH = 18e5;
|
|
905
905
|
var QUALITY_LADDER = [0.92, 0.85, 0.75];
|
|
906
906
|
var DOWNSCALE_FACTOR = 0.7;
|
|
907
|
+
var MAX_ROUNDS = 4;
|
|
907
908
|
function downscale(canvas, factor) {
|
|
908
909
|
const next = document.createElement("canvas");
|
|
909
910
|
next.width = Math.max(1, Math.round(canvas.width * factor));
|
|
@@ -917,18 +918,55 @@ function downscale(canvas, factor) {
|
|
|
917
918
|
}
|
|
918
919
|
function encodeScreenshot(canvas, maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH) {
|
|
919
920
|
let current = canvas;
|
|
920
|
-
|
|
921
|
-
|
|
921
|
+
let encoded = "";
|
|
922
|
+
for (let round = 0; round < MAX_ROUNDS; round++) {
|
|
922
923
|
for (const quality of QUALITY_LADDER) {
|
|
923
924
|
encoded = current.toDataURL("image/jpeg", quality);
|
|
924
925
|
if (encoded.length <= maxLength) return encoded;
|
|
925
926
|
}
|
|
926
|
-
if (round === 1)
|
|
927
|
+
if (round === MAX_ROUNDS - 1) break;
|
|
927
928
|
const smaller = downscale(current, DOWNSCALE_FACTOR);
|
|
928
|
-
if (!smaller)
|
|
929
|
+
if (!smaller) break;
|
|
929
930
|
current = smaller;
|
|
930
931
|
}
|
|
931
|
-
return
|
|
932
|
+
return encoded;
|
|
933
|
+
}
|
|
934
|
+
function readAsDataUrl(file) {
|
|
935
|
+
return new Promise((resolve, reject) => {
|
|
936
|
+
const reader = new FileReader();
|
|
937
|
+
reader.onload = () => resolve(reader.result);
|
|
938
|
+
reader.onerror = () => reject(reader.error);
|
|
939
|
+
reader.readAsDataURL(file);
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
async function reencodeImageFile(file, maxLength) {
|
|
943
|
+
var _a;
|
|
944
|
+
if (typeof createImageBitmap !== "function") return null;
|
|
945
|
+
const bitmap = await createImageBitmap(file);
|
|
946
|
+
try {
|
|
947
|
+
const canvas = document.createElement("canvas");
|
|
948
|
+
canvas.width = bitmap.width;
|
|
949
|
+
canvas.height = bitmap.height;
|
|
950
|
+
const ctx = canvas.getContext("2d");
|
|
951
|
+
if (!ctx) return null;
|
|
952
|
+
ctx.fillStyle = "#ffffff";
|
|
953
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
954
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
955
|
+
return encodeScreenshot(canvas, maxLength);
|
|
956
|
+
} finally {
|
|
957
|
+
(_a = bitmap.close) == null ? void 0 : _a.call(bitmap);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
async function encodeImageFile(file, maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH) {
|
|
961
|
+
const rawLength = Math.ceil(file.size / 3) * 4 + 64;
|
|
962
|
+
if (rawLength > maxLength) {
|
|
963
|
+
try {
|
|
964
|
+
const shrunk = await reencodeImageFile(file, maxLength);
|
|
965
|
+
if (shrunk && shrunk.length < rawLength) return shrunk;
|
|
966
|
+
} catch (e) {
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return readAsDataUrl(file);
|
|
932
970
|
}
|
|
933
971
|
var PALETTE = ["#ef4444", "#f59e0b", "#22c55e", "#3b82f6", "#a855f7", "#ffffff"];
|
|
934
972
|
function drawStroke(ctx, s) {
|
|
@@ -1219,6 +1257,7 @@ var SEVERITY_LABELS = {
|
|
|
1219
1257
|
critical: "Critical"
|
|
1220
1258
|
};
|
|
1221
1259
|
var MAX_ASSIST_IMAGES = 3;
|
|
1260
|
+
var MAX_ASSIST_IMAGE_CHARS = 35e5;
|
|
1222
1261
|
function getTypeLabel(type) {
|
|
1223
1262
|
switch (type) {
|
|
1224
1263
|
case "RATING":
|
|
@@ -1239,6 +1278,17 @@ function getTypeLabel(type) {
|
|
|
1239
1278
|
return "Other";
|
|
1240
1279
|
}
|
|
1241
1280
|
}
|
|
1281
|
+
function pickAssistImages(all) {
|
|
1282
|
+
const picked = [];
|
|
1283
|
+
let total = 0;
|
|
1284
|
+
for (let i = all.length - 1; i >= 0 && picked.length < MAX_ASSIST_IMAGES; i--) {
|
|
1285
|
+
const shot = all[i];
|
|
1286
|
+
if (total + shot.length > MAX_ASSIST_IMAGE_CHARS) continue;
|
|
1287
|
+
picked.unshift(shot);
|
|
1288
|
+
total += shot.length;
|
|
1289
|
+
}
|
|
1290
|
+
return picked;
|
|
1291
|
+
}
|
|
1242
1292
|
var STARTERS = [
|
|
1243
1293
|
"Something on this page is broken",
|
|
1244
1294
|
"It did the wrong thing",
|
|
@@ -1316,6 +1366,7 @@ function AssistSheet({
|
|
|
1316
1366
|
screenshots,
|
|
1317
1367
|
pageShot = null,
|
|
1318
1368
|
onAddImages,
|
|
1369
|
+
onRemoveImage,
|
|
1319
1370
|
attachmentCount,
|
|
1320
1371
|
context,
|
|
1321
1372
|
reportTypeLabel,
|
|
@@ -1357,7 +1408,6 @@ function AssistSheet({
|
|
|
1357
1408
|
!typePicked ? "type" : currentTile === "RATING" ? "rating" : "chat"
|
|
1358
1409
|
);
|
|
1359
1410
|
const scrollRef = (0, import_react3.useRef)(null);
|
|
1360
|
-
const inputRef = (0, import_react3.useRef)(null);
|
|
1361
1411
|
const draftRef = (0, import_react3.useRef)(null);
|
|
1362
1412
|
const seededRef = (0, import_react3.useRef)(false);
|
|
1363
1413
|
const eventsRef = (0, import_react3.useRef)([]);
|
|
@@ -1383,6 +1433,7 @@ function AssistSheet({
|
|
|
1383
1433
|
} catch (e) {
|
|
1384
1434
|
}
|
|
1385
1435
|
}
|
|
1436
|
+
const readShots = new Set(pickAssistImages(screenshots));
|
|
1386
1437
|
function leave(type, detail) {
|
|
1387
1438
|
logEvent(type, detail);
|
|
1388
1439
|
flushEvents();
|
|
@@ -1402,12 +1453,12 @@ function AssistSheet({
|
|
|
1402
1453
|
onDegrade(message);
|
|
1403
1454
|
}
|
|
1404
1455
|
async function runTurn(history2) {
|
|
1405
|
-
var _a, _b, _c, _d
|
|
1456
|
+
var _a, _b, _c, _d;
|
|
1406
1457
|
setBusy(true);
|
|
1407
1458
|
let result;
|
|
1408
1459
|
const events = takeEvents();
|
|
1409
1460
|
try {
|
|
1410
|
-
const sent = screenshots
|
|
1461
|
+
const sent = pickAssistImages(screenshots);
|
|
1411
1462
|
result = await assist({
|
|
1412
1463
|
// `kind` only on drafts, so an older server sees the exact shape it
|
|
1413
1464
|
// always did — it just learns the draft text now instead of a
|
|
@@ -1417,7 +1468,6 @@ function AssistSheet({
|
|
|
1417
1468
|
),
|
|
1418
1469
|
conversationId,
|
|
1419
1470
|
screenshots: sent,
|
|
1420
|
-
screenshot: (_a = sent[sent.length - 1]) != null ? _a : null,
|
|
1421
1471
|
context: {
|
|
1422
1472
|
...context != null ? context : {},
|
|
1423
1473
|
imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached")
|
|
@@ -1441,8 +1491,8 @@ function AssistSheet({
|
|
|
1441
1491
|
setConversationId(result.conversationId);
|
|
1442
1492
|
onConversationChange == null ? void 0 : onConversationChange(result.conversationId);
|
|
1443
1493
|
}
|
|
1444
|
-
setDuplicate((
|
|
1445
|
-
onDuplicateChange == null ? void 0 : onDuplicateChange((
|
|
1494
|
+
setDuplicate((_a = result.duplicate) != null ? _a : null);
|
|
1495
|
+
onDuplicateChange == null ? void 0 : onDuplicateChange((_c = (_b = result.duplicate) == null ? void 0 : _b.number) != null ? _c : null);
|
|
1446
1496
|
if (result.solved) {
|
|
1447
1497
|
setSolved(result.solved);
|
|
1448
1498
|
setOptions([]);
|
|
@@ -1460,7 +1510,7 @@ function AssistSheet({
|
|
|
1460
1510
|
}
|
|
1461
1511
|
if (result.question) {
|
|
1462
1512
|
setMessages([...history2, { role: "assistant", content: result.question }]);
|
|
1463
|
-
setOptions((
|
|
1513
|
+
setOptions((_d = result.options) != null ? _d : []);
|
|
1464
1514
|
return;
|
|
1465
1515
|
}
|
|
1466
1516
|
onDegrade("The assistant had nothing to add \u2014 write your report below and send it as normal.");
|
|
@@ -1479,7 +1529,14 @@ function AssistSheet({
|
|
|
1479
1529
|
const value = text.trim();
|
|
1480
1530
|
if (!value || busy) return;
|
|
1481
1531
|
setOptions([]);
|
|
1482
|
-
const
|
|
1532
|
+
const underDraft = phase === "draft";
|
|
1533
|
+
if (underDraft) {
|
|
1534
|
+
const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
|
|
1535
|
+
logEvent("keep_chatting", edited ? "after editing" : void 0);
|
|
1536
|
+
setPhase("chat");
|
|
1537
|
+
}
|
|
1538
|
+
const base = underDraft ? withCurrentDraft(messages) : messages;
|
|
1539
|
+
const history2 = [...base, { role: "user", content: value }];
|
|
1483
1540
|
setMessages(history2);
|
|
1484
1541
|
setInput("");
|
|
1485
1542
|
void runTurn(history2);
|
|
@@ -1488,27 +1545,16 @@ function AssistSheet({
|
|
|
1488
1545
|
onPickType(tile);
|
|
1489
1546
|
setPhase(tile === "RATING" ? "rating" : "chat");
|
|
1490
1547
|
}
|
|
1491
|
-
function
|
|
1548
|
+
function withCurrentDraft(history2) {
|
|
1492
1549
|
const current = description.trim();
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
const next = [...prev];
|
|
1499
|
-
for (let i = next.length - 1; i >= 0; i--) {
|
|
1500
|
-
if (next[i].kind === "report") {
|
|
1501
|
-
if (current) next[i] = { ...next[i], content: current };
|
|
1502
|
-
break;
|
|
1503
|
-
}
|
|
1550
|
+
const next = [...history2];
|
|
1551
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
1552
|
+
if (next[i].kind === "report") {
|
|
1553
|
+
if (current) next[i] = { ...next[i], content: current };
|
|
1554
|
+
break;
|
|
1504
1555
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
setPhase("chat");
|
|
1508
|
-
requestAnimationFrame(() => {
|
|
1509
|
-
var _a;
|
|
1510
|
-
return (_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1511
|
-
});
|
|
1556
|
+
}
|
|
1557
|
+
return next;
|
|
1512
1558
|
}
|
|
1513
1559
|
function sendDraft() {
|
|
1514
1560
|
const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
|
|
@@ -1516,9 +1562,39 @@ function AssistSheet({
|
|
|
1516
1562
|
flushEvents();
|
|
1517
1563
|
onSend();
|
|
1518
1564
|
}
|
|
1519
|
-
const lastMessage = messages[messages.length - 1];
|
|
1520
|
-
const correcting = phase === "chat" && (lastMessage == null ? void 0 : lastMessage.kind) === "report";
|
|
1521
1565
|
const empty = phase === "chat" && messages.length === 0 && !busy;
|
|
1566
|
+
function renderKnownIssue({ title, footer }) {
|
|
1567
|
+
if (!duplicate) return null;
|
|
1568
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1569
|
+
"div",
|
|
1570
|
+
{
|
|
1571
|
+
"data-gg-known-issue": "",
|
|
1572
|
+
style: {
|
|
1573
|
+
display: "flex",
|
|
1574
|
+
flexDirection: "column",
|
|
1575
|
+
gap: "3px",
|
|
1576
|
+
padding: "9px 10px",
|
|
1577
|
+
borderRadius: "8px",
|
|
1578
|
+
border: "1px solid rgba(245,158,11,0.4)",
|
|
1579
|
+
backgroundColor: "rgba(245,158,11,0.08)",
|
|
1580
|
+
fontSize: "12px",
|
|
1581
|
+
lineHeight: 1.5,
|
|
1582
|
+
minWidth: 0
|
|
1583
|
+
},
|
|
1584
|
+
children: [
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: title ? "Our team is already on this" : `Our team is already on #${duplicate.number}` }),
|
|
1586
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
|
|
1587
|
+
"#",
|
|
1588
|
+
duplicate.number,
|
|
1589
|
+
" ",
|
|
1590
|
+
duplicate.title
|
|
1591
|
+
] }),
|
|
1592
|
+
duplicate.status && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: t2.text, fontWeight: 600 }, children: duplicate.status }),
|
|
1593
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: t2.textMuted }, children: footer })
|
|
1594
|
+
]
|
|
1595
|
+
}
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1522
1598
|
const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
|
|
1523
1599
|
var _a, _b;
|
|
1524
1600
|
return (_b = (_a = w[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
|
|
@@ -1543,7 +1619,7 @@ function AssistSheet({
|
|
|
1543
1619
|
@keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}
|
|
1544
1620
|
@keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}
|
|
1545
1621
|
@keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}
|
|
1546
|
-
[data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible{outline:2px solid currentColor;outline-offset:2px}
|
|
1622
|
+
[data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible,[data-gg-assist-remove]:focus-visible{outline:2px solid currentColor;outline-offset:2px}
|
|
1547
1623
|
` }),
|
|
1548
1624
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1549
1625
|
"div",
|
|
@@ -2009,6 +2085,7 @@ function AssistSheet({
|
|
|
2009
2085
|
i
|
|
2010
2086
|
);
|
|
2011
2087
|
}),
|
|
2088
|
+
duplicate && !busy && phase === "chat" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: renderKnownIssue({ title: false }) }),
|
|
2012
2089
|
options.length > 0 && !busy && phase === "chat" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2013
2090
|
"div",
|
|
2014
2091
|
{
|
|
@@ -2107,35 +2184,13 @@ function AssistSheet({
|
|
|
2107
2184
|
textTransform: "uppercase",
|
|
2108
2185
|
color: t2.accent
|
|
2109
2186
|
},
|
|
2110
|
-
children: "Your report \xB7 edit anything"
|
|
2111
|
-
}
|
|
2112
|
-
),
|
|
2113
|
-
duplicate && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2114
|
-
"div",
|
|
2115
|
-
{
|
|
2116
|
-
style: {
|
|
2117
|
-
display: "flex",
|
|
2118
|
-
flexDirection: "column",
|
|
2119
|
-
gap: "3px",
|
|
2120
|
-
padding: "9px 10px",
|
|
2121
|
-
borderRadius: "8px",
|
|
2122
|
-
border: "1px solid rgba(245,158,11,0.4)",
|
|
2123
|
-
backgroundColor: "rgba(245,158,11,0.08)",
|
|
2124
|
-
fontSize: "12px",
|
|
2125
|
-
lineHeight: 1.5
|
|
2126
|
-
},
|
|
2127
|
-
children: [
|
|
2128
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: "Our team is already on this" }),
|
|
2129
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
|
|
2130
|
-
"#",
|
|
2131
|
-
duplicate.number,
|
|
2132
|
-
" ",
|
|
2133
|
-
duplicate.title
|
|
2134
|
-
] }),
|
|
2135
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: t2.textMuted }, children: "Your details will be added to it instead of opening a new issue." })
|
|
2136
|
-
]
|
|
2187
|
+
children: duplicate ? `What we'll add to #${duplicate.number} \xB7 edit anything` : "Your report \xB7 edit anything"
|
|
2137
2188
|
}
|
|
2138
2189
|
),
|
|
2190
|
+
renderKnownIssue({
|
|
2191
|
+
title: true,
|
|
2192
|
+
footer: "Your details will be added to it instead of opening a new issue."
|
|
2193
|
+
}),
|
|
2139
2194
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2140
2195
|
"textarea",
|
|
2141
2196
|
{
|
|
@@ -2230,26 +2285,7 @@ function AssistSheet({
|
|
|
2230
2285
|
" ",
|
|
2231
2286
|
attachmentCount === 1 ? "attachment" : "attachments",
|
|
2232
2287
|
" will be sent with this."
|
|
2233
|
-
] })
|
|
2234
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2235
|
-
"button",
|
|
2236
|
-
{
|
|
2237
|
-
type: "button",
|
|
2238
|
-
onClick: keepChatting,
|
|
2239
|
-
style: {
|
|
2240
|
-
alignSelf: "flex-start",
|
|
2241
|
-
border: "none",
|
|
2242
|
-
background: "transparent",
|
|
2243
|
-
color: t2.textMuted,
|
|
2244
|
-
fontSize: "12px",
|
|
2245
|
-
fontFamily: "inherit",
|
|
2246
|
-
padding: "9px 0",
|
|
2247
|
-
cursor: "pointer",
|
|
2248
|
-
textDecoration: "underline"
|
|
2249
|
-
},
|
|
2250
|
-
children: "Not quite \u2014 keep chatting"
|
|
2251
|
-
}
|
|
2252
|
-
)
|
|
2288
|
+
] })
|
|
2253
2289
|
]
|
|
2254
2290
|
}
|
|
2255
2291
|
),
|
|
@@ -2353,189 +2389,270 @@ function AssistSheet({
|
|
|
2353
2389
|
},
|
|
2354
2390
|
children: isSubmitting ? "Sending\u2026" : rating < 1 ? "Pick a star first" : "Send Rating"
|
|
2355
2391
|
}
|
|
2356
|
-
) :
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2392
|
+
) : (
|
|
2393
|
+
// Chat AND draft share this branch, so the chat box is the same
|
|
2394
|
+
// element on both sides of a draft landing — it stays put
|
|
2395
|
+
// instead of remounting, and a draft is something you can
|
|
2396
|
+
// still reply to (#360), not a form that replaced the chat.
|
|
2397
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2398
|
+
(screenshots.length > 0 || onAddImages) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2399
|
+
"div",
|
|
2400
|
+
{
|
|
2401
|
+
style: {
|
|
2402
|
+
display: "flex",
|
|
2403
|
+
gap: "8px",
|
|
2404
|
+
alignItems: "center",
|
|
2405
|
+
flexWrap: "wrap",
|
|
2406
|
+
marginBottom: "8px"
|
|
2407
|
+
},
|
|
2408
|
+
children: [
|
|
2409
|
+
screenshots.map((shot, i) => {
|
|
2410
|
+
const read = readShots.has(shot);
|
|
2411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2412
|
+
"div",
|
|
2413
|
+
{
|
|
2414
|
+
style: {
|
|
2415
|
+
position: "relative",
|
|
2416
|
+
width: "40px",
|
|
2417
|
+
height: "40px",
|
|
2418
|
+
flexShrink: 0
|
|
2419
|
+
},
|
|
2420
|
+
children: [
|
|
2421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2422
|
+
"img",
|
|
2423
|
+
{
|
|
2424
|
+
src: shot,
|
|
2425
|
+
alt: read ? "Attached image the assistant reads" : "Attached image",
|
|
2426
|
+
"data-gg-assist-thumb": "",
|
|
2427
|
+
style: {
|
|
2428
|
+
display: "block",
|
|
2429
|
+
width: "100%",
|
|
2430
|
+
height: "100%",
|
|
2431
|
+
objectFit: "cover",
|
|
2432
|
+
borderRadius: "8px",
|
|
2433
|
+
border: `1px solid ${read ? t2.accent : t2.inputBorder}`,
|
|
2434
|
+
opacity: read ? 1 : 0.45,
|
|
2435
|
+
boxSizing: "border-box"
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
),
|
|
2439
|
+
onRemoveImage && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2440
|
+
"button",
|
|
2441
|
+
{
|
|
2442
|
+
type: "button",
|
|
2443
|
+
"data-gg-assist-remove": "",
|
|
2444
|
+
"aria-label": `Remove image ${i + 1}`,
|
|
2445
|
+
title: "Remove this image",
|
|
2446
|
+
onClick: () => {
|
|
2447
|
+
logEvent(
|
|
2448
|
+
"image_removed",
|
|
2449
|
+
pageShot && shot === pageShot ? "page capture" : "attached"
|
|
2450
|
+
);
|
|
2451
|
+
onRemoveImage(i);
|
|
2452
|
+
},
|
|
2453
|
+
style: {
|
|
2454
|
+
position: "absolute",
|
|
2455
|
+
top: "-13px",
|
|
2456
|
+
right: "-13px",
|
|
2457
|
+
width: "32px",
|
|
2458
|
+
height: "32px",
|
|
2459
|
+
border: "none",
|
|
2460
|
+
background: "transparent",
|
|
2461
|
+
padding: 0,
|
|
2462
|
+
cursor: "pointer",
|
|
2463
|
+
display: "flex",
|
|
2464
|
+
alignItems: "center",
|
|
2465
|
+
justifyContent: "center",
|
|
2466
|
+
borderRadius: "50%"
|
|
2467
|
+
},
|
|
2468
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2469
|
+
"span",
|
|
2470
|
+
{
|
|
2471
|
+
"aria-hidden": "true",
|
|
2472
|
+
style: {
|
|
2473
|
+
width: "20px",
|
|
2474
|
+
height: "20px",
|
|
2475
|
+
boxSizing: "border-box",
|
|
2476
|
+
borderRadius: "50%",
|
|
2477
|
+
border: `2px solid ${t2.bg}`,
|
|
2478
|
+
background: "#ef4444",
|
|
2479
|
+
color: "#fff",
|
|
2480
|
+
display: "flex",
|
|
2481
|
+
alignItems: "center",
|
|
2482
|
+
justifyContent: "center"
|
|
2483
|
+
},
|
|
2484
|
+
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)(
|
|
2485
|
+
"path",
|
|
2486
|
+
{
|
|
2487
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
2488
|
+
stroke: "currentColor",
|
|
2489
|
+
strokeWidth: "1.6",
|
|
2490
|
+
strokeLinecap: "round"
|
|
2491
|
+
}
|
|
2492
|
+
) })
|
|
2493
|
+
}
|
|
2494
|
+
)
|
|
2495
|
+
}
|
|
2496
|
+
)
|
|
2497
|
+
]
|
|
2498
|
+
},
|
|
2499
|
+
`${i}-${shot.slice(-16)}`
|
|
2500
|
+
);
|
|
2501
|
+
}),
|
|
2502
|
+
onAddImages && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2503
|
+
"label",
|
|
2406
2504
|
{
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
"data-gg-assist-thumb": "",
|
|
2505
|
+
"data-gg-assist-attach": "",
|
|
2506
|
+
title: "Attach an image \u2014 or just paste one",
|
|
2410
2507
|
style: {
|
|
2411
2508
|
width: "40px",
|
|
2412
2509
|
height: "40px",
|
|
2413
|
-
objectFit: "cover",
|
|
2414
2510
|
borderRadius: "8px",
|
|
2415
|
-
border: `1px
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
}
|
|
2455
|
-
e.target.value = "";
|
|
2456
|
-
},
|
|
2457
|
-
style: { display: "none" }
|
|
2458
|
-
}
|
|
2459
|
-
)
|
|
2460
|
-
]
|
|
2461
|
-
}
|
|
2462
|
-
),
|
|
2463
|
-
screenshots.length > MAX_ASSIST_IMAGES && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
|
|
2464
|
-
"newest ",
|
|
2465
|
-
MAX_ASSIST_IMAGES,
|
|
2466
|
-
" read"
|
|
2467
|
-
] })
|
|
2468
|
-
]
|
|
2469
|
-
}
|
|
2470
|
-
),
|
|
2471
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
2472
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2473
|
-
"textarea",
|
|
2474
|
-
{
|
|
2475
|
-
ref: inputRef,
|
|
2476
|
-
value: input,
|
|
2477
|
-
onChange: (e) => setInput(e.target.value),
|
|
2478
|
-
onKeyDown: (e) => {
|
|
2479
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
2480
|
-
e.preventDefault();
|
|
2481
|
-
send(input);
|
|
2482
|
-
}
|
|
2483
|
-
},
|
|
2484
|
-
placeholder: correcting ? "What should change in the draft?" : "Type your answer\u2026",
|
|
2485
|
-
rows: 1,
|
|
2486
|
-
disabled: busy,
|
|
2487
|
-
autoFocus: true,
|
|
2488
|
-
style: {
|
|
2489
|
-
flex: 1,
|
|
2490
|
-
minHeight: "42px",
|
|
2491
|
-
maxHeight: "120px",
|
|
2492
|
-
padding: "11px 12px",
|
|
2493
|
-
borderRadius: "10px",
|
|
2494
|
-
border: `1px solid ${t2.inputBorder}`,
|
|
2495
|
-
backgroundColor: t2.inputBg,
|
|
2496
|
-
color: t2.text,
|
|
2497
|
-
fontSize: "13px",
|
|
2498
|
-
lineHeight: 1.4,
|
|
2499
|
-
fontFamily: "inherit",
|
|
2500
|
-
resize: "none",
|
|
2501
|
-
outline: "none",
|
|
2502
|
-
boxSizing: "border-box"
|
|
2503
|
-
}
|
|
2511
|
+
border: `1px dashed ${t2.inputBorder}`,
|
|
2512
|
+
display: "inline-flex",
|
|
2513
|
+
alignItems: "center",
|
|
2514
|
+
justifyContent: "center",
|
|
2515
|
+
color: t2.textMuted,
|
|
2516
|
+
fontSize: "18px",
|
|
2517
|
+
cursor: "pointer",
|
|
2518
|
+
flexShrink: 0
|
|
2519
|
+
},
|
|
2520
|
+
children: [
|
|
2521
|
+
"+",
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2523
|
+
"input",
|
|
2524
|
+
{
|
|
2525
|
+
type: "file",
|
|
2526
|
+
accept: "image/*",
|
|
2527
|
+
multiple: true,
|
|
2528
|
+
onChange: (e) => {
|
|
2529
|
+
var _a;
|
|
2530
|
+
const files = Array.from((_a = e.target.files) != null ? _a : []);
|
|
2531
|
+
if (files.length) {
|
|
2532
|
+
logEvent("image_added", String(files.length));
|
|
2533
|
+
onAddImages(files);
|
|
2534
|
+
}
|
|
2535
|
+
e.target.value = "";
|
|
2536
|
+
},
|
|
2537
|
+
style: { display: "none" }
|
|
2538
|
+
}
|
|
2539
|
+
)
|
|
2540
|
+
]
|
|
2541
|
+
}
|
|
2542
|
+
),
|
|
2543
|
+
readShots.size < screenshots.length && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
|
|
2544
|
+
readShots.size,
|
|
2545
|
+
" of ",
|
|
2546
|
+
screenshots.length,
|
|
2547
|
+
" read"
|
|
2548
|
+
] })
|
|
2549
|
+
]
|
|
2504
2550
|
}
|
|
2505
2551
|
),
|
|
2506
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2552
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
2553
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2554
|
+
"textarea",
|
|
2555
|
+
{
|
|
2556
|
+
value: input,
|
|
2557
|
+
onChange: (e) => setInput(e.target.value),
|
|
2558
|
+
onKeyDown: (e) => {
|
|
2559
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2560
|
+
e.preventDefault();
|
|
2561
|
+
send(input);
|
|
2562
|
+
}
|
|
2563
|
+
},
|
|
2564
|
+
placeholder: phase === "draft" ? "Anything to change? Tell me here\u2026" : "Type your answer\u2026",
|
|
2565
|
+
rows: 1,
|
|
2566
|
+
disabled: busy,
|
|
2567
|
+
autoFocus: true,
|
|
2568
|
+
style: {
|
|
2569
|
+
flex: 1,
|
|
2570
|
+
minHeight: "42px",
|
|
2571
|
+
maxHeight: "120px",
|
|
2572
|
+
padding: "11px 12px",
|
|
2573
|
+
borderRadius: "10px",
|
|
2574
|
+
border: `1px solid ${t2.inputBorder}`,
|
|
2575
|
+
backgroundColor: t2.inputBg,
|
|
2576
|
+
color: t2.text,
|
|
2577
|
+
fontSize: "13px",
|
|
2578
|
+
lineHeight: 1.4,
|
|
2579
|
+
fontFamily: "inherit",
|
|
2580
|
+
resize: "none",
|
|
2581
|
+
outline: "none",
|
|
2582
|
+
boxSizing: "border-box"
|
|
2533
2583
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2584
|
+
}
|
|
2585
|
+
),
|
|
2586
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2587
|
+
"button",
|
|
2588
|
+
{
|
|
2589
|
+
type: "button",
|
|
2590
|
+
"data-gg-sheet-send": "",
|
|
2591
|
+
onClick: () => send(input),
|
|
2592
|
+
disabled: busy || !input.trim(),
|
|
2593
|
+
"aria-label": "Send message",
|
|
2594
|
+
"data-gg-send-message": "",
|
|
2595
|
+
style: {
|
|
2596
|
+
flexShrink: 0,
|
|
2597
|
+
width: "42px",
|
|
2598
|
+
height: "42px",
|
|
2599
|
+
borderRadius: "10px",
|
|
2600
|
+
border: "none",
|
|
2601
|
+
display: "inline-flex",
|
|
2602
|
+
alignItems: "center",
|
|
2603
|
+
justifyContent: "center",
|
|
2604
|
+
backgroundColor: busy || !input.trim() ? t2.bgSecondary : t2.accent,
|
|
2605
|
+
color: busy || !input.trim() ? t2.textMuted : t2.accentText,
|
|
2606
|
+
cursor: busy || !input.trim() ? "default" : "pointer"
|
|
2607
|
+
},
|
|
2608
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2609
|
+
"path",
|
|
2610
|
+
{
|
|
2611
|
+
d: "M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z",
|
|
2612
|
+
fill: "currentColor"
|
|
2613
|
+
}
|
|
2614
|
+
) })
|
|
2615
|
+
}
|
|
2616
|
+
)
|
|
2617
|
+
] }),
|
|
2618
|
+
phase === "draft" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2619
|
+
validationError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2620
|
+
"p",
|
|
2621
|
+
{
|
|
2622
|
+
style: {
|
|
2623
|
+
margin: "8px 0 0",
|
|
2624
|
+
color: "#ef4444",
|
|
2625
|
+
fontSize: "12px"
|
|
2626
|
+
},
|
|
2627
|
+
children: validationError
|
|
2628
|
+
}
|
|
2629
|
+
),
|
|
2630
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2631
|
+
"button",
|
|
2632
|
+
{
|
|
2633
|
+
type: "button",
|
|
2634
|
+
"data-gg-sheet-send": "",
|
|
2635
|
+
onClick: sendDraft,
|
|
2636
|
+
disabled: isSubmitting || !description.trim(),
|
|
2637
|
+
style: {
|
|
2638
|
+
width: "100%",
|
|
2639
|
+
marginTop: "8px",
|
|
2640
|
+
padding: "12px",
|
|
2641
|
+
borderRadius: "10px",
|
|
2642
|
+
border: "none",
|
|
2643
|
+
backgroundColor: isSubmitting || !description.trim() ? t2.bgSecondary : t2.accent,
|
|
2644
|
+
color: isSubmitting || !description.trim() ? t2.textMuted : t2.accentText,
|
|
2645
|
+
fontSize: "14px",
|
|
2646
|
+
fontWeight: 700,
|
|
2647
|
+
fontFamily: "inherit",
|
|
2648
|
+
cursor: isSubmitting || !description.trim() ? "default" : "pointer"
|
|
2649
|
+
},
|
|
2650
|
+
children: isSubmitting ? "Sending\u2026" : duplicate ? `Add to #${duplicate.number}` : "Send Report"
|
|
2651
|
+
}
|
|
2652
|
+
)
|
|
2653
|
+
] })
|
|
2537
2654
|
] })
|
|
2538
|
-
|
|
2655
|
+
),
|
|
2539
2656
|
phase === "chat" && messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2540
2657
|
"button",
|
|
2541
2658
|
{
|
|
@@ -3194,20 +3311,23 @@ function ReportDialog({
|
|
|
3194
3311
|
e.target.value = "";
|
|
3195
3312
|
};
|
|
3196
3313
|
const addFiles = (files) => {
|
|
3197
|
-
files.
|
|
3314
|
+
const images = files.filter((file) => file.type.startsWith("image/"));
|
|
3315
|
+
if (images.length > 0) {
|
|
3316
|
+
void Promise.all(images.map((file) => encodeImageFile(file).catch(() => null))).then(
|
|
3317
|
+
(encoded) => {
|
|
3318
|
+
const added = encoded.filter((url) => !!url);
|
|
3319
|
+
if (added.length > 0) setScreenshots((prev) => [...prev, ...added]);
|
|
3320
|
+
}
|
|
3321
|
+
);
|
|
3322
|
+
}
|
|
3323
|
+
files.filter((file) => !file.type.startsWith("image/")).forEach((file) => {
|
|
3198
3324
|
const reader = new FileReader();
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
setAttachments((prev) => [
|
|
3206
|
-
...prev,
|
|
3207
|
-
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
3208
|
-
]);
|
|
3209
|
-
};
|
|
3210
|
-
}
|
|
3325
|
+
reader.onload = () => {
|
|
3326
|
+
setAttachments((prev) => [
|
|
3327
|
+
...prev,
|
|
3328
|
+
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
3329
|
+
]);
|
|
3330
|
+
};
|
|
3211
3331
|
reader.readAsDataURL(file);
|
|
3212
3332
|
});
|
|
3213
3333
|
};
|
|
@@ -5447,6 +5567,7 @@ function ReportDialog({
|
|
|
5447
5567
|
screenshots,
|
|
5448
5568
|
pageShot,
|
|
5449
5569
|
onAddImages: addFiles,
|
|
5570
|
+
onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
|
|
5450
5571
|
attachmentCount: screenshots.length + attachments.length,
|
|
5451
5572
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|
|
5452
5573
|
reportTypeLabel: getTypeLabel(reportType),
|