glitchgrab 1.40.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/README.md +1 -1
- package/dist/index.js +624 -277
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +624 -277
- package/dist/index.mjs.map +1 -1
- package/dist/server.js.map +1 -1
- package/dist/server.mjs.map +1 -1
- package/package.json +2 -2
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",
|
|
@@ -1259,7 +1309,9 @@ function AssistSheet({
|
|
|
1259
1309
|
assist,
|
|
1260
1310
|
theme: t2,
|
|
1261
1311
|
screenshots,
|
|
1312
|
+
pageShot = null,
|
|
1262
1313
|
onAddImages,
|
|
1314
|
+
onRemoveImage,
|
|
1263
1315
|
attachmentCount,
|
|
1264
1316
|
context,
|
|
1265
1317
|
reportTypeLabel,
|
|
@@ -1301,9 +1353,37 @@ function AssistSheet({
|
|
|
1301
1353
|
!typePicked ? "type" : currentTile === "RATING" ? "rating" : "chat"
|
|
1302
1354
|
);
|
|
1303
1355
|
const scrollRef = useRef2(null);
|
|
1304
|
-
const inputRef = useRef2(null);
|
|
1305
1356
|
const draftRef = useRef2(null);
|
|
1306
1357
|
const seededRef = useRef2(false);
|
|
1358
|
+
const eventsRef = useRef2([]);
|
|
1359
|
+
const aiDraftRef = useRef2(null);
|
|
1360
|
+
function logEvent(type, detail) {
|
|
1361
|
+
eventsRef.current.push({ type, at: Date.now(), ...detail ? { detail } : {} });
|
|
1362
|
+
}
|
|
1363
|
+
function takeEvents() {
|
|
1364
|
+
if (eventsRef.current.length === 0) return void 0;
|
|
1365
|
+
const events = eventsRef.current;
|
|
1366
|
+
eventsRef.current = [];
|
|
1367
|
+
return events;
|
|
1368
|
+
}
|
|
1369
|
+
function flushEvents() {
|
|
1370
|
+
if (!conversationId) return;
|
|
1371
|
+
const events = takeEvents();
|
|
1372
|
+
if (!events) return;
|
|
1373
|
+
try {
|
|
1374
|
+
void Promise.resolve(
|
|
1375
|
+
assist({ messages: [], conversationId, events, screenshots: [], context: null })
|
|
1376
|
+
).catch(() => {
|
|
1377
|
+
});
|
|
1378
|
+
} catch (e) {
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
const readShots = new Set(pickAssistImages(screenshots));
|
|
1382
|
+
function leave(type, detail) {
|
|
1383
|
+
logEvent(type, detail);
|
|
1384
|
+
flushEvents();
|
|
1385
|
+
onClose();
|
|
1386
|
+
}
|
|
1307
1387
|
useEffect2(() => {
|
|
1308
1388
|
const el = scrollRef.current;
|
|
1309
1389
|
if (el) el.scrollTop = el.scrollHeight;
|
|
@@ -1312,35 +1392,52 @@ function AssistSheet({
|
|
|
1312
1392
|
var _a;
|
|
1313
1393
|
if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
|
|
1314
1394
|
}, [phase]);
|
|
1395
|
+
function degradeKeepingEvents(events, message) {
|
|
1396
|
+
if (events) eventsRef.current = [...events, ...eventsRef.current];
|
|
1397
|
+
flushEvents();
|
|
1398
|
+
onDegrade(message);
|
|
1399
|
+
}
|
|
1315
1400
|
async function runTurn(history2) {
|
|
1316
|
-
var _a, _b, _c, _d
|
|
1401
|
+
var _a, _b, _c, _d;
|
|
1317
1402
|
setBusy(true);
|
|
1318
1403
|
let result;
|
|
1404
|
+
const events = takeEvents();
|
|
1319
1405
|
try {
|
|
1320
|
-
const sent = screenshots
|
|
1406
|
+
const sent = pickAssistImages(screenshots);
|
|
1321
1407
|
result = await assist({
|
|
1322
|
-
|
|
1408
|
+
// `kind` only on drafts, so an older server sees the exact shape it
|
|
1409
|
+
// always did — it just learns the draft text now instead of a
|
|
1410
|
+
// placeholder line.
|
|
1411
|
+
messages: history2.map(
|
|
1412
|
+
(m) => m.kind ? { role: m.role, content: m.content, kind: m.kind } : m
|
|
1413
|
+
),
|
|
1323
1414
|
conversationId,
|
|
1324
1415
|
screenshots: sent,
|
|
1325
|
-
|
|
1326
|
-
|
|
1416
|
+
context: {
|
|
1417
|
+
...context != null ? context : {},
|
|
1418
|
+
imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached")
|
|
1419
|
+
},
|
|
1420
|
+
events
|
|
1327
1421
|
});
|
|
1328
1422
|
} catch (e) {
|
|
1329
|
-
|
|
1423
|
+
degradeKeepingEvents(
|
|
1424
|
+
events,
|
|
1425
|
+
"The assistant is unavailable \u2014 write your report below and send it as normal."
|
|
1426
|
+
);
|
|
1330
1427
|
return;
|
|
1331
1428
|
} finally {
|
|
1332
1429
|
setBusy(false);
|
|
1333
1430
|
}
|
|
1334
1431
|
if (result.degraded) {
|
|
1335
|
-
|
|
1432
|
+
degradeKeepingEvents(events, result.degraded);
|
|
1336
1433
|
return;
|
|
1337
1434
|
}
|
|
1338
1435
|
if (result.conversationId) {
|
|
1339
1436
|
setConversationId(result.conversationId);
|
|
1340
1437
|
onConversationChange == null ? void 0 : onConversationChange(result.conversationId);
|
|
1341
1438
|
}
|
|
1342
|
-
setDuplicate((
|
|
1343
|
-
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);
|
|
1344
1441
|
if (result.solved) {
|
|
1345
1442
|
setSolved(result.solved);
|
|
1346
1443
|
setOptions([]);
|
|
@@ -1349,14 +1446,16 @@ function AssistSheet({
|
|
|
1349
1446
|
}
|
|
1350
1447
|
if (result.report) {
|
|
1351
1448
|
onDescriptionChange(result.report);
|
|
1352
|
-
|
|
1449
|
+
aiDraftRef.current = result.report;
|
|
1450
|
+
logEvent("draft_shown");
|
|
1451
|
+
setMessages([...history2, { role: "assistant", content: result.report, kind: "report" }]);
|
|
1353
1452
|
setOptions([]);
|
|
1354
1453
|
setPhase("draft");
|
|
1355
1454
|
return;
|
|
1356
1455
|
}
|
|
1357
1456
|
if (result.question) {
|
|
1358
1457
|
setMessages([...history2, { role: "assistant", content: result.question }]);
|
|
1359
|
-
setOptions((
|
|
1458
|
+
setOptions((_d = result.options) != null ? _d : []);
|
|
1360
1459
|
return;
|
|
1361
1460
|
}
|
|
1362
1461
|
onDegrade("The assistant had nothing to add \u2014 write your report below and send it as normal.");
|
|
@@ -1375,7 +1474,14 @@ function AssistSheet({
|
|
|
1375
1474
|
const value = text.trim();
|
|
1376
1475
|
if (!value || busy) return;
|
|
1377
1476
|
setOptions([]);
|
|
1378
|
-
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 }];
|
|
1379
1485
|
setMessages(history2);
|
|
1380
1486
|
setInput("");
|
|
1381
1487
|
void runTurn(history2);
|
|
@@ -1384,7 +1490,56 @@ function AssistSheet({
|
|
|
1384
1490
|
onPickType(tile);
|
|
1385
1491
|
setPhase(tile === "RATING" ? "rating" : "chat");
|
|
1386
1492
|
}
|
|
1493
|
+
function withCurrentDraft(history2) {
|
|
1494
|
+
const current = description.trim();
|
|
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;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
return next;
|
|
1503
|
+
}
|
|
1504
|
+
function sendDraft() {
|
|
1505
|
+
const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
|
|
1506
|
+
logEvent("draft_sent", edited ? "edited" : "as drafted");
|
|
1507
|
+
flushEvents();
|
|
1508
|
+
onSend();
|
|
1509
|
+
}
|
|
1387
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
|
+
}
|
|
1388
1543
|
const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
|
|
1389
1544
|
var _a, _b;
|
|
1390
1545
|
return (_b = (_a = w[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
|
|
@@ -1409,7 +1564,7 @@ function AssistSheet({
|
|
|
1409
1564
|
@keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}
|
|
1410
1565
|
@keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}
|
|
1411
1566
|
@keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}
|
|
1412
|
-
[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}
|
|
1413
1568
|
` }),
|
|
1414
1569
|
/* @__PURE__ */ jsx2(
|
|
1415
1570
|
"div",
|
|
@@ -1429,7 +1584,7 @@ function AssistSheet({
|
|
|
1429
1584
|
animation: "gg-sheet-fade .18s ease",
|
|
1430
1585
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
1431
1586
|
},
|
|
1432
|
-
onClick:
|
|
1587
|
+
onClick: () => leave("closed"),
|
|
1433
1588
|
onPointerDown: (e) => e.stopPropagation(),
|
|
1434
1589
|
children: /* @__PURE__ */ jsxs2(
|
|
1435
1590
|
"div",
|
|
@@ -1509,7 +1664,7 @@ function AssistSheet({
|
|
|
1509
1664
|
{
|
|
1510
1665
|
type: "button",
|
|
1511
1666
|
"data-gg-write-myself": "",
|
|
1512
|
-
onClick:
|
|
1667
|
+
onClick: () => leave("write_myself", `header, ${phase}`),
|
|
1513
1668
|
"aria-label": "Write it myself instead",
|
|
1514
1669
|
style: {
|
|
1515
1670
|
flexShrink: 0,
|
|
@@ -1765,7 +1920,10 @@ function AssistSheet({
|
|
|
1765
1920
|
{
|
|
1766
1921
|
type: "button",
|
|
1767
1922
|
"data-gg-chip": "",
|
|
1768
|
-
onClick: () =>
|
|
1923
|
+
onClick: () => {
|
|
1924
|
+
logEvent("starter_tap", s);
|
|
1925
|
+
send(s);
|
|
1926
|
+
},
|
|
1769
1927
|
style: {
|
|
1770
1928
|
border: `1px solid ${t2.inputBorder}`,
|
|
1771
1929
|
background: "transparent",
|
|
@@ -1785,6 +1943,60 @@ function AssistSheet({
|
|
|
1785
1943
|
] }),
|
|
1786
1944
|
messages.map((m, i) => {
|
|
1787
1945
|
const mine = m.role === "user";
|
|
1946
|
+
if (m.kind === "report") {
|
|
1947
|
+
const live = phase === "draft" && i === messages.length - 1;
|
|
1948
|
+
return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px", minWidth: 0 }, children: [
|
|
1949
|
+
/* @__PURE__ */ jsx2(Avatar, { who: "assistant", theme: t2 }),
|
|
1950
|
+
/* @__PURE__ */ jsx2(
|
|
1951
|
+
"div",
|
|
1952
|
+
{
|
|
1953
|
+
"data-gg-draft-bubble": "",
|
|
1954
|
+
style: {
|
|
1955
|
+
maxWidth: "82%",
|
|
1956
|
+
minWidth: 0,
|
|
1957
|
+
padding: "9px 12px",
|
|
1958
|
+
borderRadius: "12px 12px 12px 4px",
|
|
1959
|
+
fontSize: "13px",
|
|
1960
|
+
lineHeight: 1.55,
|
|
1961
|
+
backgroundColor: t2.bgSecondary,
|
|
1962
|
+
color: t2.text,
|
|
1963
|
+
border: live ? "none" : `1px solid ${t2.accent}66`
|
|
1964
|
+
},
|
|
1965
|
+
children: live ? "Here's your report \u2014 have a read." : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1966
|
+
/* @__PURE__ */ jsx2(
|
|
1967
|
+
"span",
|
|
1968
|
+
{
|
|
1969
|
+
style: {
|
|
1970
|
+
display: "block",
|
|
1971
|
+
fontSize: "10px",
|
|
1972
|
+
fontWeight: 700,
|
|
1973
|
+
letterSpacing: ".06em",
|
|
1974
|
+
textTransform: "uppercase",
|
|
1975
|
+
color: t2.accent,
|
|
1976
|
+
marginBottom: "4px"
|
|
1977
|
+
},
|
|
1978
|
+
children: "Draft so far"
|
|
1979
|
+
}
|
|
1980
|
+
),
|
|
1981
|
+
/* @__PURE__ */ jsx2(
|
|
1982
|
+
"span",
|
|
1983
|
+
{
|
|
1984
|
+
style: {
|
|
1985
|
+
display: "block",
|
|
1986
|
+
whiteSpace: "pre-wrap",
|
|
1987
|
+
wordBreak: "break-word",
|
|
1988
|
+
maxHeight: "160px",
|
|
1989
|
+
overflowY: "auto",
|
|
1990
|
+
color: t2.textMuted
|
|
1991
|
+
},
|
|
1992
|
+
children: m.content
|
|
1993
|
+
}
|
|
1994
|
+
)
|
|
1995
|
+
] })
|
|
1996
|
+
}
|
|
1997
|
+
)
|
|
1998
|
+
] }, i);
|
|
1999
|
+
}
|
|
1788
2000
|
return /* @__PURE__ */ jsxs2(
|
|
1789
2001
|
"div",
|
|
1790
2002
|
{
|
|
@@ -1818,6 +2030,7 @@ function AssistSheet({
|
|
|
1818
2030
|
i
|
|
1819
2031
|
);
|
|
1820
2032
|
}),
|
|
2033
|
+
duplicate && !busy && phase === "chat" && /* @__PURE__ */ jsx2("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: renderKnownIssue({ title: false }) }),
|
|
1821
2034
|
options.length > 0 && !busy && phase === "chat" && /* @__PURE__ */ jsx2(
|
|
1822
2035
|
"div",
|
|
1823
2036
|
{
|
|
@@ -1839,7 +2052,10 @@ function AssistSheet({
|
|
|
1839
2052
|
type: "button",
|
|
1840
2053
|
"data-gg-chip": "",
|
|
1841
2054
|
"data-gg-option": "",
|
|
1842
|
-
onClick: () =>
|
|
2055
|
+
onClick: () => {
|
|
2056
|
+
logEvent("option_tap", option);
|
|
2057
|
+
send(option);
|
|
2058
|
+
},
|
|
1843
2059
|
style: {
|
|
1844
2060
|
border: `1px solid ${t2.inputBorder}`,
|
|
1845
2061
|
background: "transparent",
|
|
@@ -1913,35 +2129,13 @@ function AssistSheet({
|
|
|
1913
2129
|
textTransform: "uppercase",
|
|
1914
2130
|
color: t2.accent
|
|
1915
2131
|
},
|
|
1916
|
-
children: "Your report \xB7 edit anything"
|
|
1917
|
-
}
|
|
1918
|
-
),
|
|
1919
|
-
duplicate && /* @__PURE__ */ jsxs2(
|
|
1920
|
-
"div",
|
|
1921
|
-
{
|
|
1922
|
-
style: {
|
|
1923
|
-
display: "flex",
|
|
1924
|
-
flexDirection: "column",
|
|
1925
|
-
gap: "3px",
|
|
1926
|
-
padding: "9px 10px",
|
|
1927
|
-
borderRadius: "8px",
|
|
1928
|
-
border: "1px solid rgba(245,158,11,0.4)",
|
|
1929
|
-
backgroundColor: "rgba(245,158,11,0.08)",
|
|
1930
|
-
fontSize: "12px",
|
|
1931
|
-
lineHeight: 1.5
|
|
1932
|
-
},
|
|
1933
|
-
children: [
|
|
1934
|
-
/* @__PURE__ */ jsx2("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: "Our team is already on this" }),
|
|
1935
|
-
/* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
|
|
1936
|
-
"#",
|
|
1937
|
-
duplicate.number,
|
|
1938
|
-
" ",
|
|
1939
|
-
duplicate.title
|
|
1940
|
-
] }),
|
|
1941
|
-
/* @__PURE__ */ jsx2("span", { style: { color: t2.textMuted }, children: "Your details will be added to it instead of opening a new issue." })
|
|
1942
|
-
]
|
|
2132
|
+
children: duplicate ? `What we'll add to #${duplicate.number} \xB7 edit anything` : "Your report \xB7 edit anything"
|
|
1943
2133
|
}
|
|
1944
2134
|
),
|
|
2135
|
+
renderKnownIssue({
|
|
2136
|
+
title: true,
|
|
2137
|
+
footer: "Your details will be added to it instead of opening a new issue."
|
|
2138
|
+
}),
|
|
1945
2139
|
/* @__PURE__ */ jsx2(
|
|
1946
2140
|
"textarea",
|
|
1947
2141
|
{
|
|
@@ -2036,26 +2230,7 @@ function AssistSheet({
|
|
|
2036
2230
|
" ",
|
|
2037
2231
|
attachmentCount === 1 ? "attachment" : "attachments",
|
|
2038
2232
|
" will be sent with this."
|
|
2039
|
-
] })
|
|
2040
|
-
/* @__PURE__ */ jsx2(
|
|
2041
|
-
"button",
|
|
2042
|
-
{
|
|
2043
|
-
type: "button",
|
|
2044
|
-
onClick: () => setPhase("chat"),
|
|
2045
|
-
style: {
|
|
2046
|
-
alignSelf: "flex-start",
|
|
2047
|
-
border: "none",
|
|
2048
|
-
background: "transparent",
|
|
2049
|
-
color: t2.textMuted,
|
|
2050
|
-
fontSize: "12px",
|
|
2051
|
-
fontFamily: "inherit",
|
|
2052
|
-
padding: "9px 0",
|
|
2053
|
-
cursor: "pointer",
|
|
2054
|
-
textDecoration: "underline"
|
|
2055
|
-
},
|
|
2056
|
-
children: "Not quite \u2014 keep chatting"
|
|
2057
|
-
}
|
|
2058
|
-
)
|
|
2233
|
+
] })
|
|
2059
2234
|
]
|
|
2060
2235
|
}
|
|
2061
2236
|
),
|
|
@@ -2159,192 +2334,276 @@ function AssistSheet({
|
|
|
2159
2334
|
},
|
|
2160
2335
|
children: isSubmitting ? "Sending\u2026" : rating < 1 ? "Pick a star first" : "Send Rating"
|
|
2161
2336
|
}
|
|
2162
|
-
) :
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
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",
|
|
2212
2449
|
{
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
"data-gg-assist-thumb": "",
|
|
2450
|
+
"data-gg-assist-attach": "",
|
|
2451
|
+
title: "Attach an image \u2014 or just paste one",
|
|
2216
2452
|
style: {
|
|
2217
2453
|
width: "40px",
|
|
2218
2454
|
height: "40px",
|
|
2219
|
-
objectFit: "cover",
|
|
2220
2455
|
borderRadius: "8px",
|
|
2221
|
-
border: `1px
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
style: { display: "none" }
|
|
2261
|
-
}
|
|
2262
|
-
)
|
|
2263
|
-
]
|
|
2264
|
-
}
|
|
2265
|
-
),
|
|
2266
|
-
screenshots.length > MAX_ASSIST_IMAGES && /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
|
|
2267
|
-
"newest ",
|
|
2268
|
-
MAX_ASSIST_IMAGES,
|
|
2269
|
-
" read"
|
|
2270
|
-
] })
|
|
2271
|
-
]
|
|
2272
|
-
}
|
|
2273
|
-
),
|
|
2274
|
-
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
2275
|
-
/* @__PURE__ */ jsx2(
|
|
2276
|
-
"textarea",
|
|
2277
|
-
{
|
|
2278
|
-
ref: inputRef,
|
|
2279
|
-
value: input,
|
|
2280
|
-
onChange: (e) => setInput(e.target.value),
|
|
2281
|
-
onKeyDown: (e) => {
|
|
2282
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
2283
|
-
e.preventDefault();
|
|
2284
|
-
send(input);
|
|
2285
|
-
}
|
|
2286
|
-
},
|
|
2287
|
-
placeholder: "Type your answer\u2026",
|
|
2288
|
-
rows: 1,
|
|
2289
|
-
disabled: busy,
|
|
2290
|
-
autoFocus: true,
|
|
2291
|
-
style: {
|
|
2292
|
-
flex: 1,
|
|
2293
|
-
minHeight: "42px",
|
|
2294
|
-
maxHeight: "120px",
|
|
2295
|
-
padding: "11px 12px",
|
|
2296
|
-
borderRadius: "10px",
|
|
2297
|
-
border: `1px solid ${t2.inputBorder}`,
|
|
2298
|
-
backgroundColor: t2.inputBg,
|
|
2299
|
-
color: t2.text,
|
|
2300
|
-
fontSize: "13px",
|
|
2301
|
-
lineHeight: 1.4,
|
|
2302
|
-
fontFamily: "inherit",
|
|
2303
|
-
resize: "none",
|
|
2304
|
-
outline: "none",
|
|
2305
|
-
boxSizing: "border-box"
|
|
2306
|
-
}
|
|
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
|
+
]
|
|
2307
2495
|
}
|
|
2308
2496
|
),
|
|
2309
|
-
/* @__PURE__ */
|
|
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
|
-
|
|
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"
|
|
2336
2528
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
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
|
+
] })
|
|
2340
2599
|
] })
|
|
2341
|
-
|
|
2600
|
+
),
|
|
2342
2601
|
phase === "chat" && messages.length > 0 && /* @__PURE__ */ jsx2(
|
|
2343
2602
|
"button",
|
|
2344
2603
|
{
|
|
2345
2604
|
type: "button",
|
|
2346
2605
|
"data-gg-write-myself": "",
|
|
2347
|
-
onClick:
|
|
2606
|
+
onClick: () => leave("write_myself", "footer"),
|
|
2348
2607
|
style: {
|
|
2349
2608
|
display: "block",
|
|
2350
2609
|
margin: "8px auto 0",
|
|
@@ -2416,6 +2675,107 @@ var ATTACHMENT_ACCEPT = [
|
|
|
2416
2675
|
".xlsx",
|
|
2417
2676
|
".zip"
|
|
2418
2677
|
].join(",");
|
|
2678
|
+
var MAX_SCALE = 2;
|
|
2679
|
+
var FRAME_TIMEOUT_MS = 3e3;
|
|
2680
|
+
function canCaptureTabPixels() {
|
|
2681
|
+
var _a;
|
|
2682
|
+
try {
|
|
2683
|
+
return typeof navigator !== "undefined" && typeof ((_a = navigator.mediaDevices) == null ? void 0 : _a.getDisplayMedia) === "function" && typeof globalThis.CaptureController !== "undefined";
|
|
2684
|
+
} catch (e) {
|
|
2685
|
+
return false;
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
var HAVE_CURRENT_DATA = 2;
|
|
2689
|
+
function waitForFrame(video) {
|
|
2690
|
+
if (video.readyState >= HAVE_CURRENT_DATA && video.videoWidth > 0) {
|
|
2691
|
+
return Promise.resolve(true);
|
|
2692
|
+
}
|
|
2693
|
+
return new Promise((resolve) => {
|
|
2694
|
+
const timer = setTimeout(() => resolve(false), FRAME_TIMEOUT_MS);
|
|
2695
|
+
const done = () => {
|
|
2696
|
+
clearTimeout(timer);
|
|
2697
|
+
resolve(true);
|
|
2698
|
+
};
|
|
2699
|
+
if (typeof video.requestVideoFrameCallback === "function") {
|
|
2700
|
+
video.requestVideoFrameCallback(done);
|
|
2701
|
+
} else if (video.readyState >= 2) {
|
|
2702
|
+
done();
|
|
2703
|
+
} else {
|
|
2704
|
+
video.addEventListener("loadeddata", done, { once: true });
|
|
2705
|
+
}
|
|
2706
|
+
});
|
|
2707
|
+
}
|
|
2708
|
+
async function grabFrame(stream) {
|
|
2709
|
+
const video = document.createElement("video");
|
|
2710
|
+
video.muted = true;
|
|
2711
|
+
video.playsInline = true;
|
|
2712
|
+
video.srcObject = stream;
|
|
2713
|
+
try {
|
|
2714
|
+
await video.play();
|
|
2715
|
+
if (!await waitForFrame(video)) return null;
|
|
2716
|
+
if (!video.videoWidth || !video.videoHeight) return null;
|
|
2717
|
+
const maxWidth = Math.max(1, window.innerWidth) * MAX_SCALE;
|
|
2718
|
+
const factor = Math.min(1, maxWidth / video.videoWidth);
|
|
2719
|
+
const canvas = document.createElement("canvas");
|
|
2720
|
+
canvas.width = Math.round(video.videoWidth * factor);
|
|
2721
|
+
canvas.height = Math.round(video.videoHeight * factor);
|
|
2722
|
+
const ctx = canvas.getContext("2d");
|
|
2723
|
+
if (!ctx) return null;
|
|
2724
|
+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
2725
|
+
return canvas;
|
|
2726
|
+
} finally {
|
|
2727
|
+
video.srcObject = null;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
async function captureViaTabPixels() {
|
|
2731
|
+
var _a, _b;
|
|
2732
|
+
if (!canCaptureTabPixels()) return null;
|
|
2733
|
+
let stream = null;
|
|
2734
|
+
try {
|
|
2735
|
+
const options = {
|
|
2736
|
+
video: { displaySurface: "browser" },
|
|
2737
|
+
audio: false,
|
|
2738
|
+
preferCurrentTab: true,
|
|
2739
|
+
selfBrowserSurface: "include",
|
|
2740
|
+
surfaceSwitching: "exclude",
|
|
2741
|
+
monitorTypeSurfaces: "exclude"
|
|
2742
|
+
};
|
|
2743
|
+
stream = await navigator.mediaDevices.getDisplayMedia(options);
|
|
2744
|
+
const surface = (_b = (_a = stream.getVideoTracks()[0]) == null ? void 0 : _a.getSettings()) == null ? void 0 : _b.displaySurface;
|
|
2745
|
+
if (surface && surface !== "browser") return null;
|
|
2746
|
+
const canvas = await grabFrame(stream);
|
|
2747
|
+
return canvas ? encodeScreenshot(canvas) : null;
|
|
2748
|
+
} catch (e) {
|
|
2749
|
+
return null;
|
|
2750
|
+
} finally {
|
|
2751
|
+
stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop());
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
async function captureViaHtml2Canvas() {
|
|
2755
|
+
try {
|
|
2756
|
+
const { default: html2canvas } = await import("html2canvas-pro");
|
|
2757
|
+
const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), MAX_SCALE);
|
|
2758
|
+
const canvas = await html2canvas(document.body, {
|
|
2759
|
+
scale,
|
|
2760
|
+
logging: false,
|
|
2761
|
+
useCORS: true,
|
|
2762
|
+
allowTaint: true,
|
|
2763
|
+
x: window.scrollX,
|
|
2764
|
+
y: window.scrollY,
|
|
2765
|
+
width: window.innerWidth,
|
|
2766
|
+
height: window.innerHeight,
|
|
2767
|
+
windowWidth: window.innerWidth,
|
|
2768
|
+
windowHeight: window.innerHeight
|
|
2769
|
+
});
|
|
2770
|
+
return encodeScreenshot(canvas);
|
|
2771
|
+
} catch (e) {
|
|
2772
|
+
return null;
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
async function captureDefaultScreenshot() {
|
|
2776
|
+
var _a;
|
|
2777
|
+
return (_a = await captureViaTabPixels()) != null ? _a : await captureViaHtml2Canvas();
|
|
2778
|
+
}
|
|
2419
2779
|
var SEVERITY_REQUIRED = "Pick how bad it is before sending.";
|
|
2420
2780
|
function useIsDark() {
|
|
2421
2781
|
if (typeof window === "undefined") return true;
|
|
@@ -2690,27 +3050,6 @@ function isLowQualityText(text) {
|
|
|
2690
3050
|
}
|
|
2691
3051
|
return null;
|
|
2692
3052
|
}
|
|
2693
|
-
async function captureViaHtml2Canvas() {
|
|
2694
|
-
try {
|
|
2695
|
-
const { default: html2canvas } = await import("html2canvas-pro");
|
|
2696
|
-
const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), 2);
|
|
2697
|
-
const canvas = await html2canvas(document.body, {
|
|
2698
|
-
scale,
|
|
2699
|
-
logging: false,
|
|
2700
|
-
useCORS: true,
|
|
2701
|
-
allowTaint: true,
|
|
2702
|
-
x: window.scrollX,
|
|
2703
|
-
y: window.scrollY,
|
|
2704
|
-
width: window.innerWidth,
|
|
2705
|
-
height: window.innerHeight,
|
|
2706
|
-
windowWidth: window.innerWidth,
|
|
2707
|
-
windowHeight: window.innerHeight
|
|
2708
|
-
});
|
|
2709
|
-
return encodeScreenshot(canvas);
|
|
2710
|
-
} catch (e) {
|
|
2711
|
-
return null;
|
|
2712
|
-
}
|
|
2713
|
-
}
|
|
2714
3053
|
var MIC_MESSAGES = {
|
|
2715
3054
|
blocked: "Microphone is blocked for this site. Allow it in your browser's site settings, then reload this page. You can type your report instead.",
|
|
2716
3055
|
notFound: "No microphone found. Connect one and try again, or type your report instead.",
|
|
@@ -2748,7 +3087,7 @@ function ReportDialog({
|
|
|
2748
3087
|
transcribeAudio: transcribeAudio2,
|
|
2749
3088
|
types,
|
|
2750
3089
|
showSeverity = true,
|
|
2751
|
-
captureScreenshot =
|
|
3090
|
+
captureScreenshot = captureDefaultScreenshot,
|
|
2752
3091
|
reporter,
|
|
2753
3092
|
onClose,
|
|
2754
3093
|
headerSlot
|
|
@@ -2778,6 +3117,7 @@ function ReportDialog({
|
|
|
2778
3117
|
const [isSubmitting, setIsSubmitting] = useState3(false);
|
|
2779
3118
|
const [submitted, setSubmitted] = useState3(false);
|
|
2780
3119
|
const [screenshots, setScreenshots] = useState3([]);
|
|
3120
|
+
const [pageShot, setPageShot] = useState3(null);
|
|
2781
3121
|
const [attachments, setAttachments] = useState3([]);
|
|
2782
3122
|
const [previewIndex, setPreviewIndex] = useState3(null);
|
|
2783
3123
|
const [annotatingIndex, setAnnotatingIndex] = useState3(null);
|
|
@@ -2916,20 +3256,23 @@ function ReportDialog({
|
|
|
2916
3256
|
e.target.value = "";
|
|
2917
3257
|
};
|
|
2918
3258
|
const addFiles = (files) => {
|
|
2919
|
-
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) => {
|
|
2920
3269
|
const reader = new FileReader();
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
setAttachments((prev) => [
|
|
2928
|
-
...prev,
|
|
2929
|
-
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
2930
|
-
]);
|
|
2931
|
-
};
|
|
2932
|
-
}
|
|
3270
|
+
reader.onload = () => {
|
|
3271
|
+
setAttachments((prev) => [
|
|
3272
|
+
...prev,
|
|
3273
|
+
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
3274
|
+
]);
|
|
3275
|
+
};
|
|
2933
3276
|
reader.readAsDataURL(file);
|
|
2934
3277
|
});
|
|
2935
3278
|
};
|
|
@@ -2943,6 +3286,7 @@ function ReportDialog({
|
|
|
2943
3286
|
setStep(2);
|
|
2944
3287
|
}
|
|
2945
3288
|
const shot = await captureScreenshot();
|
|
3289
|
+
setPageShot(shot != null ? shot : null);
|
|
2946
3290
|
if (shot) setScreenshots([shot]);
|
|
2947
3291
|
if (assist && !assistUsed) setAssistOpen(true);
|
|
2948
3292
|
setIsOpen(true);
|
|
@@ -5140,6 +5484,7 @@ function ReportDialog({
|
|
|
5140
5484
|
imageSrc: screenshots[annotatingIndex],
|
|
5141
5485
|
onCancel: () => setAnnotatingIndex(null),
|
|
5142
5486
|
onSave: (dataUrl) => {
|
|
5487
|
+
if (screenshots[annotatingIndex] === pageShot) setPageShot(dataUrl);
|
|
5143
5488
|
setScreenshots(
|
|
5144
5489
|
(prev) => prev.map((s, i) => i === annotatingIndex ? dataUrl : s)
|
|
5145
5490
|
);
|
|
@@ -5165,7 +5510,9 @@ function ReportDialog({
|
|
|
5165
5510
|
accentText: t2.accentText
|
|
5166
5511
|
},
|
|
5167
5512
|
screenshots,
|
|
5513
|
+
pageShot,
|
|
5168
5514
|
onAddImages: addFiles,
|
|
5515
|
+
onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
|
|
5169
5516
|
attachmentCount: screenshots.length + attachments.length,
|
|
5170
5517
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|
|
5171
5518
|
reportTypeLabel: getTypeLabel(reportType),
|