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.mjs
CHANGED
|
@@ -849,6 +849,7 @@ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-run
|
|
|
849
849
|
var MAX_SCREENSHOT_DATA_URL_LENGTH = 18e5;
|
|
850
850
|
var QUALITY_LADDER = [0.92, 0.85, 0.75];
|
|
851
851
|
var DOWNSCALE_FACTOR = 0.7;
|
|
852
|
+
var MAX_ROUNDS = 4;
|
|
852
853
|
function downscale(canvas, factor) {
|
|
853
854
|
const next = document.createElement("canvas");
|
|
854
855
|
next.width = Math.max(1, Math.round(canvas.width * factor));
|
|
@@ -862,18 +863,55 @@ function downscale(canvas, factor) {
|
|
|
862
863
|
}
|
|
863
864
|
function encodeScreenshot(canvas, maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH) {
|
|
864
865
|
let current = canvas;
|
|
865
|
-
|
|
866
|
-
|
|
866
|
+
let encoded = "";
|
|
867
|
+
for (let round = 0; round < MAX_ROUNDS; round++) {
|
|
867
868
|
for (const quality of QUALITY_LADDER) {
|
|
868
869
|
encoded = current.toDataURL("image/jpeg", quality);
|
|
869
870
|
if (encoded.length <= maxLength) return encoded;
|
|
870
871
|
}
|
|
871
|
-
if (round === 1)
|
|
872
|
+
if (round === MAX_ROUNDS - 1) break;
|
|
872
873
|
const smaller = downscale(current, DOWNSCALE_FACTOR);
|
|
873
|
-
if (!smaller)
|
|
874
|
+
if (!smaller) break;
|
|
874
875
|
current = smaller;
|
|
875
876
|
}
|
|
876
|
-
return
|
|
877
|
+
return encoded;
|
|
878
|
+
}
|
|
879
|
+
function readAsDataUrl(file) {
|
|
880
|
+
return new Promise((resolve, reject) => {
|
|
881
|
+
const reader = new FileReader();
|
|
882
|
+
reader.onload = () => resolve(reader.result);
|
|
883
|
+
reader.onerror = () => reject(reader.error);
|
|
884
|
+
reader.readAsDataURL(file);
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
async function reencodeImageFile(file, maxLength) {
|
|
888
|
+
var _a;
|
|
889
|
+
if (typeof createImageBitmap !== "function") return null;
|
|
890
|
+
const bitmap = await createImageBitmap(file);
|
|
891
|
+
try {
|
|
892
|
+
const canvas = document.createElement("canvas");
|
|
893
|
+
canvas.width = bitmap.width;
|
|
894
|
+
canvas.height = bitmap.height;
|
|
895
|
+
const ctx = canvas.getContext("2d");
|
|
896
|
+
if (!ctx) return null;
|
|
897
|
+
ctx.fillStyle = "#ffffff";
|
|
898
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
899
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
900
|
+
return encodeScreenshot(canvas, maxLength);
|
|
901
|
+
} finally {
|
|
902
|
+
(_a = bitmap.close) == null ? void 0 : _a.call(bitmap);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
async function encodeImageFile(file, maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH) {
|
|
906
|
+
const rawLength = Math.ceil(file.size / 3) * 4 + 64;
|
|
907
|
+
if (rawLength > maxLength) {
|
|
908
|
+
try {
|
|
909
|
+
const shrunk = await reencodeImageFile(file, maxLength);
|
|
910
|
+
if (shrunk && shrunk.length < rawLength) return shrunk;
|
|
911
|
+
} catch (e) {
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return readAsDataUrl(file);
|
|
877
915
|
}
|
|
878
916
|
var PALETTE = ["#ef4444", "#f59e0b", "#22c55e", "#3b82f6", "#a855f7", "#ffffff"];
|
|
879
917
|
function drawStroke(ctx, s) {
|
|
@@ -1164,6 +1202,7 @@ var SEVERITY_LABELS = {
|
|
|
1164
1202
|
critical: "Critical"
|
|
1165
1203
|
};
|
|
1166
1204
|
var MAX_ASSIST_IMAGES = 3;
|
|
1205
|
+
var MAX_ASSIST_IMAGE_CHARS = 35e5;
|
|
1167
1206
|
function getTypeLabel(type) {
|
|
1168
1207
|
switch (type) {
|
|
1169
1208
|
case "RATING":
|
|
@@ -1184,6 +1223,17 @@ function getTypeLabel(type) {
|
|
|
1184
1223
|
return "Other";
|
|
1185
1224
|
}
|
|
1186
1225
|
}
|
|
1226
|
+
function pickAssistImages(all) {
|
|
1227
|
+
const picked = [];
|
|
1228
|
+
let total = 0;
|
|
1229
|
+
for (let i = all.length - 1; i >= 0 && picked.length < MAX_ASSIST_IMAGES; i--) {
|
|
1230
|
+
const shot = all[i];
|
|
1231
|
+
if (total + shot.length > MAX_ASSIST_IMAGE_CHARS) continue;
|
|
1232
|
+
picked.unshift(shot);
|
|
1233
|
+
total += shot.length;
|
|
1234
|
+
}
|
|
1235
|
+
return picked;
|
|
1236
|
+
}
|
|
1187
1237
|
var STARTERS = [
|
|
1188
1238
|
"Something on this page is broken",
|
|
1189
1239
|
"It did the wrong thing",
|
|
@@ -1261,6 +1311,7 @@ function AssistSheet({
|
|
|
1261
1311
|
screenshots,
|
|
1262
1312
|
pageShot = null,
|
|
1263
1313
|
onAddImages,
|
|
1314
|
+
onRemoveImage,
|
|
1264
1315
|
attachmentCount,
|
|
1265
1316
|
context,
|
|
1266
1317
|
reportTypeLabel,
|
|
@@ -1302,7 +1353,6 @@ function AssistSheet({
|
|
|
1302
1353
|
!typePicked ? "type" : currentTile === "RATING" ? "rating" : "chat"
|
|
1303
1354
|
);
|
|
1304
1355
|
const scrollRef = useRef2(null);
|
|
1305
|
-
const inputRef = useRef2(null);
|
|
1306
1356
|
const draftRef = useRef2(null);
|
|
1307
1357
|
const seededRef = useRef2(false);
|
|
1308
1358
|
const eventsRef = useRef2([]);
|
|
@@ -1328,6 +1378,7 @@ function AssistSheet({
|
|
|
1328
1378
|
} catch (e) {
|
|
1329
1379
|
}
|
|
1330
1380
|
}
|
|
1381
|
+
const readShots = new Set(pickAssistImages(screenshots));
|
|
1331
1382
|
function leave(type, detail) {
|
|
1332
1383
|
logEvent(type, detail);
|
|
1333
1384
|
flushEvents();
|
|
@@ -1347,12 +1398,12 @@ function AssistSheet({
|
|
|
1347
1398
|
onDegrade(message);
|
|
1348
1399
|
}
|
|
1349
1400
|
async function runTurn(history2) {
|
|
1350
|
-
var _a, _b, _c, _d
|
|
1401
|
+
var _a, _b, _c, _d;
|
|
1351
1402
|
setBusy(true);
|
|
1352
1403
|
let result;
|
|
1353
1404
|
const events = takeEvents();
|
|
1354
1405
|
try {
|
|
1355
|
-
const sent = screenshots
|
|
1406
|
+
const sent = pickAssistImages(screenshots);
|
|
1356
1407
|
result = await assist({
|
|
1357
1408
|
// `kind` only on drafts, so an older server sees the exact shape it
|
|
1358
1409
|
// always did — it just learns the draft text now instead of a
|
|
@@ -1362,7 +1413,6 @@ function AssistSheet({
|
|
|
1362
1413
|
),
|
|
1363
1414
|
conversationId,
|
|
1364
1415
|
screenshots: sent,
|
|
1365
|
-
screenshot: (_a = sent[sent.length - 1]) != null ? _a : null,
|
|
1366
1416
|
context: {
|
|
1367
1417
|
...context != null ? context : {},
|
|
1368
1418
|
imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached")
|
|
@@ -1386,8 +1436,8 @@ function AssistSheet({
|
|
|
1386
1436
|
setConversationId(result.conversationId);
|
|
1387
1437
|
onConversationChange == null ? void 0 : onConversationChange(result.conversationId);
|
|
1388
1438
|
}
|
|
1389
|
-
setDuplicate((
|
|
1390
|
-
onDuplicateChange == null ? void 0 : onDuplicateChange((
|
|
1439
|
+
setDuplicate((_a = result.duplicate) != null ? _a : null);
|
|
1440
|
+
onDuplicateChange == null ? void 0 : onDuplicateChange((_c = (_b = result.duplicate) == null ? void 0 : _b.number) != null ? _c : null);
|
|
1391
1441
|
if (result.solved) {
|
|
1392
1442
|
setSolved(result.solved);
|
|
1393
1443
|
setOptions([]);
|
|
@@ -1405,7 +1455,7 @@ function AssistSheet({
|
|
|
1405
1455
|
}
|
|
1406
1456
|
if (result.question) {
|
|
1407
1457
|
setMessages([...history2, { role: "assistant", content: result.question }]);
|
|
1408
|
-
setOptions((
|
|
1458
|
+
setOptions((_d = result.options) != null ? _d : []);
|
|
1409
1459
|
return;
|
|
1410
1460
|
}
|
|
1411
1461
|
onDegrade("The assistant had nothing to add \u2014 write your report below and send it as normal.");
|
|
@@ -1424,7 +1474,14 @@ function AssistSheet({
|
|
|
1424
1474
|
const value = text.trim();
|
|
1425
1475
|
if (!value || busy) return;
|
|
1426
1476
|
setOptions([]);
|
|
1427
|
-
const
|
|
1477
|
+
const underDraft = phase === "draft";
|
|
1478
|
+
if (underDraft) {
|
|
1479
|
+
const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
|
|
1480
|
+
logEvent("keep_chatting", edited ? "after editing" : void 0);
|
|
1481
|
+
setPhase("chat");
|
|
1482
|
+
}
|
|
1483
|
+
const base = underDraft ? withCurrentDraft(messages) : messages;
|
|
1484
|
+
const history2 = [...base, { role: "user", content: value }];
|
|
1428
1485
|
setMessages(history2);
|
|
1429
1486
|
setInput("");
|
|
1430
1487
|
void runTurn(history2);
|
|
@@ -1433,27 +1490,16 @@ function AssistSheet({
|
|
|
1433
1490
|
onPickType(tile);
|
|
1434
1491
|
setPhase(tile === "RATING" ? "rating" : "chat");
|
|
1435
1492
|
}
|
|
1436
|
-
function
|
|
1493
|
+
function withCurrentDraft(history2) {
|
|
1437
1494
|
const current = description.trim();
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
const next = [...prev];
|
|
1444
|
-
for (let i = next.length - 1; i >= 0; i--) {
|
|
1445
|
-
if (next[i].kind === "report") {
|
|
1446
|
-
if (current) next[i] = { ...next[i], content: current };
|
|
1447
|
-
break;
|
|
1448
|
-
}
|
|
1495
|
+
const next = [...history2];
|
|
1496
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
1497
|
+
if (next[i].kind === "report") {
|
|
1498
|
+
if (current) next[i] = { ...next[i], content: current };
|
|
1499
|
+
break;
|
|
1449
1500
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
setPhase("chat");
|
|
1453
|
-
requestAnimationFrame(() => {
|
|
1454
|
-
var _a;
|
|
1455
|
-
return (_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1456
|
-
});
|
|
1501
|
+
}
|
|
1502
|
+
return next;
|
|
1457
1503
|
}
|
|
1458
1504
|
function sendDraft() {
|
|
1459
1505
|
const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
|
|
@@ -1461,9 +1507,39 @@ function AssistSheet({
|
|
|
1461
1507
|
flushEvents();
|
|
1462
1508
|
onSend();
|
|
1463
1509
|
}
|
|
1464
|
-
const lastMessage = messages[messages.length - 1];
|
|
1465
|
-
const correcting = phase === "chat" && (lastMessage == null ? void 0 : lastMessage.kind) === "report";
|
|
1466
1510
|
const empty = phase === "chat" && messages.length === 0 && !busy;
|
|
1511
|
+
function renderKnownIssue({ title, footer }) {
|
|
1512
|
+
if (!duplicate) return null;
|
|
1513
|
+
return /* @__PURE__ */ jsxs2(
|
|
1514
|
+
"div",
|
|
1515
|
+
{
|
|
1516
|
+
"data-gg-known-issue": "",
|
|
1517
|
+
style: {
|
|
1518
|
+
display: "flex",
|
|
1519
|
+
flexDirection: "column",
|
|
1520
|
+
gap: "3px",
|
|
1521
|
+
padding: "9px 10px",
|
|
1522
|
+
borderRadius: "8px",
|
|
1523
|
+
border: "1px solid rgba(245,158,11,0.4)",
|
|
1524
|
+
backgroundColor: "rgba(245,158,11,0.08)",
|
|
1525
|
+
fontSize: "12px",
|
|
1526
|
+
lineHeight: 1.5,
|
|
1527
|
+
minWidth: 0
|
|
1528
|
+
},
|
|
1529
|
+
children: [
|
|
1530
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: title ? "Our team is already on this" : `Our team is already on #${duplicate.number}` }),
|
|
1531
|
+
title && /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
|
|
1532
|
+
"#",
|
|
1533
|
+
duplicate.number,
|
|
1534
|
+
" ",
|
|
1535
|
+
duplicate.title
|
|
1536
|
+
] }),
|
|
1537
|
+
duplicate.status && /* @__PURE__ */ jsx2("span", { style: { color: t2.text, fontWeight: 600 }, children: duplicate.status }),
|
|
1538
|
+
footer && /* @__PURE__ */ jsx2("span", { style: { color: t2.textMuted }, children: footer })
|
|
1539
|
+
]
|
|
1540
|
+
}
|
|
1541
|
+
);
|
|
1542
|
+
}
|
|
1467
1543
|
const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
|
|
1468
1544
|
var _a, _b;
|
|
1469
1545
|
return (_b = (_a = w[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
|
|
@@ -1488,7 +1564,7 @@ function AssistSheet({
|
|
|
1488
1564
|
@keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}
|
|
1489
1565
|
@keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}
|
|
1490
1566
|
@keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}
|
|
1491
|
-
[data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible{outline:2px solid currentColor;outline-offset:2px}
|
|
1567
|
+
[data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible,[data-gg-assist-remove]:focus-visible{outline:2px solid currentColor;outline-offset:2px}
|
|
1492
1568
|
` }),
|
|
1493
1569
|
/* @__PURE__ */ jsx2(
|
|
1494
1570
|
"div",
|
|
@@ -1954,6 +2030,7 @@ function AssistSheet({
|
|
|
1954
2030
|
i
|
|
1955
2031
|
);
|
|
1956
2032
|
}),
|
|
2033
|
+
duplicate && !busy && phase === "chat" && /* @__PURE__ */ jsx2("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: renderKnownIssue({ title: false }) }),
|
|
1957
2034
|
options.length > 0 && !busy && phase === "chat" && /* @__PURE__ */ jsx2(
|
|
1958
2035
|
"div",
|
|
1959
2036
|
{
|
|
@@ -2052,35 +2129,13 @@ function AssistSheet({
|
|
|
2052
2129
|
textTransform: "uppercase",
|
|
2053
2130
|
color: t2.accent
|
|
2054
2131
|
},
|
|
2055
|
-
children: "Your report \xB7 edit anything"
|
|
2056
|
-
}
|
|
2057
|
-
),
|
|
2058
|
-
duplicate && /* @__PURE__ */ jsxs2(
|
|
2059
|
-
"div",
|
|
2060
|
-
{
|
|
2061
|
-
style: {
|
|
2062
|
-
display: "flex",
|
|
2063
|
-
flexDirection: "column",
|
|
2064
|
-
gap: "3px",
|
|
2065
|
-
padding: "9px 10px",
|
|
2066
|
-
borderRadius: "8px",
|
|
2067
|
-
border: "1px solid rgba(245,158,11,0.4)",
|
|
2068
|
-
backgroundColor: "rgba(245,158,11,0.08)",
|
|
2069
|
-
fontSize: "12px",
|
|
2070
|
-
lineHeight: 1.5
|
|
2071
|
-
},
|
|
2072
|
-
children: [
|
|
2073
|
-
/* @__PURE__ */ jsx2("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: "Our team is already on this" }),
|
|
2074
|
-
/* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
|
|
2075
|
-
"#",
|
|
2076
|
-
duplicate.number,
|
|
2077
|
-
" ",
|
|
2078
|
-
duplicate.title
|
|
2079
|
-
] }),
|
|
2080
|
-
/* @__PURE__ */ jsx2("span", { style: { color: t2.textMuted }, children: "Your details will be added to it instead of opening a new issue." })
|
|
2081
|
-
]
|
|
2132
|
+
children: duplicate ? `What we'll add to #${duplicate.number} \xB7 edit anything` : "Your report \xB7 edit anything"
|
|
2082
2133
|
}
|
|
2083
2134
|
),
|
|
2135
|
+
renderKnownIssue({
|
|
2136
|
+
title: true,
|
|
2137
|
+
footer: "Your details will be added to it instead of opening a new issue."
|
|
2138
|
+
}),
|
|
2084
2139
|
/* @__PURE__ */ jsx2(
|
|
2085
2140
|
"textarea",
|
|
2086
2141
|
{
|
|
@@ -2175,26 +2230,7 @@ function AssistSheet({
|
|
|
2175
2230
|
" ",
|
|
2176
2231
|
attachmentCount === 1 ? "attachment" : "attachments",
|
|
2177
2232
|
" will be sent with this."
|
|
2178
|
-
] })
|
|
2179
|
-
/* @__PURE__ */ jsx2(
|
|
2180
|
-
"button",
|
|
2181
|
-
{
|
|
2182
|
-
type: "button",
|
|
2183
|
-
onClick: keepChatting,
|
|
2184
|
-
style: {
|
|
2185
|
-
alignSelf: "flex-start",
|
|
2186
|
-
border: "none",
|
|
2187
|
-
background: "transparent",
|
|
2188
|
-
color: t2.textMuted,
|
|
2189
|
-
fontSize: "12px",
|
|
2190
|
-
fontFamily: "inherit",
|
|
2191
|
-
padding: "9px 0",
|
|
2192
|
-
cursor: "pointer",
|
|
2193
|
-
textDecoration: "underline"
|
|
2194
|
-
},
|
|
2195
|
-
children: "Not quite \u2014 keep chatting"
|
|
2196
|
-
}
|
|
2197
|
-
)
|
|
2233
|
+
] })
|
|
2198
2234
|
]
|
|
2199
2235
|
}
|
|
2200
2236
|
),
|
|
@@ -2298,189 +2334,270 @@ function AssistSheet({
|
|
|
2298
2334
|
},
|
|
2299
2335
|
children: isSubmitting ? "Sending\u2026" : rating < 1 ? "Pick a star first" : "Send Rating"
|
|
2300
2336
|
}
|
|
2301
|
-
) :
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2337
|
+
) : (
|
|
2338
|
+
// Chat AND draft share this branch, so the chat box is the same
|
|
2339
|
+
// element on both sides of a draft landing — it stays put
|
|
2340
|
+
// instead of remounting, and a draft is something you can
|
|
2341
|
+
// still reply to (#360), not a form that replaced the chat.
|
|
2342
|
+
/* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
2343
|
+
(screenshots.length > 0 || onAddImages) && /* @__PURE__ */ jsxs2(
|
|
2344
|
+
"div",
|
|
2345
|
+
{
|
|
2346
|
+
style: {
|
|
2347
|
+
display: "flex",
|
|
2348
|
+
gap: "8px",
|
|
2349
|
+
alignItems: "center",
|
|
2350
|
+
flexWrap: "wrap",
|
|
2351
|
+
marginBottom: "8px"
|
|
2352
|
+
},
|
|
2353
|
+
children: [
|
|
2354
|
+
screenshots.map((shot, i) => {
|
|
2355
|
+
const read = readShots.has(shot);
|
|
2356
|
+
return /* @__PURE__ */ jsxs2(
|
|
2357
|
+
"div",
|
|
2358
|
+
{
|
|
2359
|
+
style: {
|
|
2360
|
+
position: "relative",
|
|
2361
|
+
width: "40px",
|
|
2362
|
+
height: "40px",
|
|
2363
|
+
flexShrink: 0
|
|
2364
|
+
},
|
|
2365
|
+
children: [
|
|
2366
|
+
/* @__PURE__ */ jsx2(
|
|
2367
|
+
"img",
|
|
2368
|
+
{
|
|
2369
|
+
src: shot,
|
|
2370
|
+
alt: read ? "Attached image the assistant reads" : "Attached image",
|
|
2371
|
+
"data-gg-assist-thumb": "",
|
|
2372
|
+
style: {
|
|
2373
|
+
display: "block",
|
|
2374
|
+
width: "100%",
|
|
2375
|
+
height: "100%",
|
|
2376
|
+
objectFit: "cover",
|
|
2377
|
+
borderRadius: "8px",
|
|
2378
|
+
border: `1px solid ${read ? t2.accent : t2.inputBorder}`,
|
|
2379
|
+
opacity: read ? 1 : 0.45,
|
|
2380
|
+
boxSizing: "border-box"
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
),
|
|
2384
|
+
onRemoveImage && /* @__PURE__ */ jsx2(
|
|
2385
|
+
"button",
|
|
2386
|
+
{
|
|
2387
|
+
type: "button",
|
|
2388
|
+
"data-gg-assist-remove": "",
|
|
2389
|
+
"aria-label": `Remove image ${i + 1}`,
|
|
2390
|
+
title: "Remove this image",
|
|
2391
|
+
onClick: () => {
|
|
2392
|
+
logEvent(
|
|
2393
|
+
"image_removed",
|
|
2394
|
+
pageShot && shot === pageShot ? "page capture" : "attached"
|
|
2395
|
+
);
|
|
2396
|
+
onRemoveImage(i);
|
|
2397
|
+
},
|
|
2398
|
+
style: {
|
|
2399
|
+
position: "absolute",
|
|
2400
|
+
top: "-13px",
|
|
2401
|
+
right: "-13px",
|
|
2402
|
+
width: "32px",
|
|
2403
|
+
height: "32px",
|
|
2404
|
+
border: "none",
|
|
2405
|
+
background: "transparent",
|
|
2406
|
+
padding: 0,
|
|
2407
|
+
cursor: "pointer",
|
|
2408
|
+
display: "flex",
|
|
2409
|
+
alignItems: "center",
|
|
2410
|
+
justifyContent: "center",
|
|
2411
|
+
borderRadius: "50%"
|
|
2412
|
+
},
|
|
2413
|
+
children: /* @__PURE__ */ jsx2(
|
|
2414
|
+
"span",
|
|
2415
|
+
{
|
|
2416
|
+
"aria-hidden": "true",
|
|
2417
|
+
style: {
|
|
2418
|
+
width: "20px",
|
|
2419
|
+
height: "20px",
|
|
2420
|
+
boxSizing: "border-box",
|
|
2421
|
+
borderRadius: "50%",
|
|
2422
|
+
border: `2px solid ${t2.bg}`,
|
|
2423
|
+
background: "#ef4444",
|
|
2424
|
+
color: "#fff",
|
|
2425
|
+
display: "flex",
|
|
2426
|
+
alignItems: "center",
|
|
2427
|
+
justifyContent: "center"
|
|
2428
|
+
},
|
|
2429
|
+
children: /* @__PURE__ */ jsx2("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx2(
|
|
2430
|
+
"path",
|
|
2431
|
+
{
|
|
2432
|
+
d: "M1 1L9 9M9 1L1 9",
|
|
2433
|
+
stroke: "currentColor",
|
|
2434
|
+
strokeWidth: "1.6",
|
|
2435
|
+
strokeLinecap: "round"
|
|
2436
|
+
}
|
|
2437
|
+
) })
|
|
2438
|
+
}
|
|
2439
|
+
)
|
|
2440
|
+
}
|
|
2441
|
+
)
|
|
2442
|
+
]
|
|
2443
|
+
},
|
|
2444
|
+
`${i}-${shot.slice(-16)}`
|
|
2445
|
+
);
|
|
2446
|
+
}),
|
|
2447
|
+
onAddImages && /* @__PURE__ */ jsxs2(
|
|
2448
|
+
"label",
|
|
2351
2449
|
{
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
"data-gg-assist-thumb": "",
|
|
2450
|
+
"data-gg-assist-attach": "",
|
|
2451
|
+
title: "Attach an image \u2014 or just paste one",
|
|
2355
2452
|
style: {
|
|
2356
2453
|
width: "40px",
|
|
2357
2454
|
height: "40px",
|
|
2358
|
-
objectFit: "cover",
|
|
2359
2455
|
borderRadius: "8px",
|
|
2360
|
-
border: `1px
|
|
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
|
-
e.target.value = "";
|
|
2401
|
-
},
|
|
2402
|
-
style: { display: "none" }
|
|
2403
|
-
}
|
|
2404
|
-
)
|
|
2405
|
-
]
|
|
2406
|
-
}
|
|
2407
|
-
),
|
|
2408
|
-
screenshots.length > MAX_ASSIST_IMAGES && /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
|
|
2409
|
-
"newest ",
|
|
2410
|
-
MAX_ASSIST_IMAGES,
|
|
2411
|
-
" read"
|
|
2412
|
-
] })
|
|
2413
|
-
]
|
|
2414
|
-
}
|
|
2415
|
-
),
|
|
2416
|
-
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
2417
|
-
/* @__PURE__ */ jsx2(
|
|
2418
|
-
"textarea",
|
|
2419
|
-
{
|
|
2420
|
-
ref: inputRef,
|
|
2421
|
-
value: input,
|
|
2422
|
-
onChange: (e) => setInput(e.target.value),
|
|
2423
|
-
onKeyDown: (e) => {
|
|
2424
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
2425
|
-
e.preventDefault();
|
|
2426
|
-
send(input);
|
|
2427
|
-
}
|
|
2428
|
-
},
|
|
2429
|
-
placeholder: correcting ? "What should change in the draft?" : "Type your answer\u2026",
|
|
2430
|
-
rows: 1,
|
|
2431
|
-
disabled: busy,
|
|
2432
|
-
autoFocus: true,
|
|
2433
|
-
style: {
|
|
2434
|
-
flex: 1,
|
|
2435
|
-
minHeight: "42px",
|
|
2436
|
-
maxHeight: "120px",
|
|
2437
|
-
padding: "11px 12px",
|
|
2438
|
-
borderRadius: "10px",
|
|
2439
|
-
border: `1px solid ${t2.inputBorder}`,
|
|
2440
|
-
backgroundColor: t2.inputBg,
|
|
2441
|
-
color: t2.text,
|
|
2442
|
-
fontSize: "13px",
|
|
2443
|
-
lineHeight: 1.4,
|
|
2444
|
-
fontFamily: "inherit",
|
|
2445
|
-
resize: "none",
|
|
2446
|
-
outline: "none",
|
|
2447
|
-
boxSizing: "border-box"
|
|
2448
|
-
}
|
|
2456
|
+
border: `1px dashed ${t2.inputBorder}`,
|
|
2457
|
+
display: "inline-flex",
|
|
2458
|
+
alignItems: "center",
|
|
2459
|
+
justifyContent: "center",
|
|
2460
|
+
color: t2.textMuted,
|
|
2461
|
+
fontSize: "18px",
|
|
2462
|
+
cursor: "pointer",
|
|
2463
|
+
flexShrink: 0
|
|
2464
|
+
},
|
|
2465
|
+
children: [
|
|
2466
|
+
"+",
|
|
2467
|
+
/* @__PURE__ */ jsx2(
|
|
2468
|
+
"input",
|
|
2469
|
+
{
|
|
2470
|
+
type: "file",
|
|
2471
|
+
accept: "image/*",
|
|
2472
|
+
multiple: true,
|
|
2473
|
+
onChange: (e) => {
|
|
2474
|
+
var _a;
|
|
2475
|
+
const files = Array.from((_a = e.target.files) != null ? _a : []);
|
|
2476
|
+
if (files.length) {
|
|
2477
|
+
logEvent("image_added", String(files.length));
|
|
2478
|
+
onAddImages(files);
|
|
2479
|
+
}
|
|
2480
|
+
e.target.value = "";
|
|
2481
|
+
},
|
|
2482
|
+
style: { display: "none" }
|
|
2483
|
+
}
|
|
2484
|
+
)
|
|
2485
|
+
]
|
|
2486
|
+
}
|
|
2487
|
+
),
|
|
2488
|
+
readShots.size < screenshots.length && /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
|
|
2489
|
+
readShots.size,
|
|
2490
|
+
" of ",
|
|
2491
|
+
screenshots.length,
|
|
2492
|
+
" read"
|
|
2493
|
+
] })
|
|
2494
|
+
]
|
|
2449
2495
|
}
|
|
2450
2496
|
),
|
|
2451
|
-
/* @__PURE__ */
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2497
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
2498
|
+
/* @__PURE__ */ jsx2(
|
|
2499
|
+
"textarea",
|
|
2500
|
+
{
|
|
2501
|
+
value: input,
|
|
2502
|
+
onChange: (e) => setInput(e.target.value),
|
|
2503
|
+
onKeyDown: (e) => {
|
|
2504
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2505
|
+
e.preventDefault();
|
|
2506
|
+
send(input);
|
|
2507
|
+
}
|
|
2508
|
+
},
|
|
2509
|
+
placeholder: phase === "draft" ? "Anything to change? Tell me here\u2026" : "Type your answer\u2026",
|
|
2510
|
+
rows: 1,
|
|
2511
|
+
disabled: busy,
|
|
2512
|
+
autoFocus: true,
|
|
2513
|
+
style: {
|
|
2514
|
+
flex: 1,
|
|
2515
|
+
minHeight: "42px",
|
|
2516
|
+
maxHeight: "120px",
|
|
2517
|
+
padding: "11px 12px",
|
|
2518
|
+
borderRadius: "10px",
|
|
2519
|
+
border: `1px solid ${t2.inputBorder}`,
|
|
2520
|
+
backgroundColor: t2.inputBg,
|
|
2521
|
+
color: t2.text,
|
|
2522
|
+
fontSize: "13px",
|
|
2523
|
+
lineHeight: 1.4,
|
|
2524
|
+
fontFamily: "inherit",
|
|
2525
|
+
resize: "none",
|
|
2526
|
+
outline: "none",
|
|
2527
|
+
boxSizing: "border-box"
|
|
2478
2528
|
}
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2529
|
+
}
|
|
2530
|
+
),
|
|
2531
|
+
/* @__PURE__ */ jsx2(
|
|
2532
|
+
"button",
|
|
2533
|
+
{
|
|
2534
|
+
type: "button",
|
|
2535
|
+
"data-gg-sheet-send": "",
|
|
2536
|
+
onClick: () => send(input),
|
|
2537
|
+
disabled: busy || !input.trim(),
|
|
2538
|
+
"aria-label": "Send message",
|
|
2539
|
+
"data-gg-send-message": "",
|
|
2540
|
+
style: {
|
|
2541
|
+
flexShrink: 0,
|
|
2542
|
+
width: "42px",
|
|
2543
|
+
height: "42px",
|
|
2544
|
+
borderRadius: "10px",
|
|
2545
|
+
border: "none",
|
|
2546
|
+
display: "inline-flex",
|
|
2547
|
+
alignItems: "center",
|
|
2548
|
+
justifyContent: "center",
|
|
2549
|
+
backgroundColor: busy || !input.trim() ? t2.bgSecondary : t2.accent,
|
|
2550
|
+
color: busy || !input.trim() ? t2.textMuted : t2.accentText,
|
|
2551
|
+
cursor: busy || !input.trim() ? "default" : "pointer"
|
|
2552
|
+
},
|
|
2553
|
+
children: /* @__PURE__ */ jsx2("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(
|
|
2554
|
+
"path",
|
|
2555
|
+
{
|
|
2556
|
+
d: "M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z",
|
|
2557
|
+
fill: "currentColor"
|
|
2558
|
+
}
|
|
2559
|
+
) })
|
|
2560
|
+
}
|
|
2561
|
+
)
|
|
2562
|
+
] }),
|
|
2563
|
+
phase === "draft" && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
2564
|
+
validationError && /* @__PURE__ */ jsx2(
|
|
2565
|
+
"p",
|
|
2566
|
+
{
|
|
2567
|
+
style: {
|
|
2568
|
+
margin: "8px 0 0",
|
|
2569
|
+
color: "#ef4444",
|
|
2570
|
+
fontSize: "12px"
|
|
2571
|
+
},
|
|
2572
|
+
children: validationError
|
|
2573
|
+
}
|
|
2574
|
+
),
|
|
2575
|
+
/* @__PURE__ */ jsx2(
|
|
2576
|
+
"button",
|
|
2577
|
+
{
|
|
2578
|
+
type: "button",
|
|
2579
|
+
"data-gg-sheet-send": "",
|
|
2580
|
+
onClick: sendDraft,
|
|
2581
|
+
disabled: isSubmitting || !description.trim(),
|
|
2582
|
+
style: {
|
|
2583
|
+
width: "100%",
|
|
2584
|
+
marginTop: "8px",
|
|
2585
|
+
padding: "12px",
|
|
2586
|
+
borderRadius: "10px",
|
|
2587
|
+
border: "none",
|
|
2588
|
+
backgroundColor: isSubmitting || !description.trim() ? t2.bgSecondary : t2.accent,
|
|
2589
|
+
color: isSubmitting || !description.trim() ? t2.textMuted : t2.accentText,
|
|
2590
|
+
fontSize: "14px",
|
|
2591
|
+
fontWeight: 700,
|
|
2592
|
+
fontFamily: "inherit",
|
|
2593
|
+
cursor: isSubmitting || !description.trim() ? "default" : "pointer"
|
|
2594
|
+
},
|
|
2595
|
+
children: isSubmitting ? "Sending\u2026" : duplicate ? `Add to #${duplicate.number}` : "Send Report"
|
|
2596
|
+
}
|
|
2597
|
+
)
|
|
2598
|
+
] })
|
|
2482
2599
|
] })
|
|
2483
|
-
|
|
2600
|
+
),
|
|
2484
2601
|
phase === "chat" && messages.length > 0 && /* @__PURE__ */ jsx2(
|
|
2485
2602
|
"button",
|
|
2486
2603
|
{
|
|
@@ -3139,20 +3256,23 @@ function ReportDialog({
|
|
|
3139
3256
|
e.target.value = "";
|
|
3140
3257
|
};
|
|
3141
3258
|
const addFiles = (files) => {
|
|
3142
|
-
files.
|
|
3259
|
+
const images = files.filter((file) => file.type.startsWith("image/"));
|
|
3260
|
+
if (images.length > 0) {
|
|
3261
|
+
void Promise.all(images.map((file) => encodeImageFile(file).catch(() => null))).then(
|
|
3262
|
+
(encoded) => {
|
|
3263
|
+
const added = encoded.filter((url) => !!url);
|
|
3264
|
+
if (added.length > 0) setScreenshots((prev) => [...prev, ...added]);
|
|
3265
|
+
}
|
|
3266
|
+
);
|
|
3267
|
+
}
|
|
3268
|
+
files.filter((file) => !file.type.startsWith("image/")).forEach((file) => {
|
|
3143
3269
|
const reader = new FileReader();
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
setAttachments((prev) => [
|
|
3151
|
-
...prev,
|
|
3152
|
-
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
3153
|
-
]);
|
|
3154
|
-
};
|
|
3155
|
-
}
|
|
3270
|
+
reader.onload = () => {
|
|
3271
|
+
setAttachments((prev) => [
|
|
3272
|
+
...prev,
|
|
3273
|
+
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
3274
|
+
]);
|
|
3275
|
+
};
|
|
3156
3276
|
reader.readAsDataURL(file);
|
|
3157
3277
|
});
|
|
3158
3278
|
};
|
|
@@ -5392,6 +5512,7 @@ function ReportDialog({
|
|
|
5392
5512
|
screenshots,
|
|
5393
5513
|
pageShot,
|
|
5394
5514
|
onAddImages: addFiles,
|
|
5515
|
+
onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
|
|
5395
5516
|
attachmentCount: screenshots.length + attachments.length,
|
|
5396
5517
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|
|
5397
5518
|
reportTypeLabel: getTypeLabel(reportType),
|