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.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",
|
|
@@ -1314,7 +1364,9 @@ function AssistSheet({
|
|
|
1314
1364
|
assist,
|
|
1315
1365
|
theme: t2,
|
|
1316
1366
|
screenshots,
|
|
1367
|
+
pageShot = null,
|
|
1317
1368
|
onAddImages,
|
|
1369
|
+
onRemoveImage,
|
|
1318
1370
|
attachmentCount,
|
|
1319
1371
|
context,
|
|
1320
1372
|
reportTypeLabel,
|
|
@@ -1356,9 +1408,37 @@ function AssistSheet({
|
|
|
1356
1408
|
!typePicked ? "type" : currentTile === "RATING" ? "rating" : "chat"
|
|
1357
1409
|
);
|
|
1358
1410
|
const scrollRef = (0, import_react3.useRef)(null);
|
|
1359
|
-
const inputRef = (0, import_react3.useRef)(null);
|
|
1360
1411
|
const draftRef = (0, import_react3.useRef)(null);
|
|
1361
1412
|
const seededRef = (0, import_react3.useRef)(false);
|
|
1413
|
+
const eventsRef = (0, import_react3.useRef)([]);
|
|
1414
|
+
const aiDraftRef = (0, import_react3.useRef)(null);
|
|
1415
|
+
function logEvent(type, detail) {
|
|
1416
|
+
eventsRef.current.push({ type, at: Date.now(), ...detail ? { detail } : {} });
|
|
1417
|
+
}
|
|
1418
|
+
function takeEvents() {
|
|
1419
|
+
if (eventsRef.current.length === 0) return void 0;
|
|
1420
|
+
const events = eventsRef.current;
|
|
1421
|
+
eventsRef.current = [];
|
|
1422
|
+
return events;
|
|
1423
|
+
}
|
|
1424
|
+
function flushEvents() {
|
|
1425
|
+
if (!conversationId) return;
|
|
1426
|
+
const events = takeEvents();
|
|
1427
|
+
if (!events) return;
|
|
1428
|
+
try {
|
|
1429
|
+
void Promise.resolve(
|
|
1430
|
+
assist({ messages: [], conversationId, events, screenshots: [], context: null })
|
|
1431
|
+
).catch(() => {
|
|
1432
|
+
});
|
|
1433
|
+
} catch (e) {
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
const readShots = new Set(pickAssistImages(screenshots));
|
|
1437
|
+
function leave(type, detail) {
|
|
1438
|
+
logEvent(type, detail);
|
|
1439
|
+
flushEvents();
|
|
1440
|
+
onClose();
|
|
1441
|
+
}
|
|
1362
1442
|
(0, import_react3.useEffect)(() => {
|
|
1363
1443
|
const el = scrollRef.current;
|
|
1364
1444
|
if (el) el.scrollTop = el.scrollHeight;
|
|
@@ -1367,35 +1447,52 @@ function AssistSheet({
|
|
|
1367
1447
|
var _a;
|
|
1368
1448
|
if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
|
|
1369
1449
|
}, [phase]);
|
|
1450
|
+
function degradeKeepingEvents(events, message) {
|
|
1451
|
+
if (events) eventsRef.current = [...events, ...eventsRef.current];
|
|
1452
|
+
flushEvents();
|
|
1453
|
+
onDegrade(message);
|
|
1454
|
+
}
|
|
1370
1455
|
async function runTurn(history2) {
|
|
1371
|
-
var _a, _b, _c, _d
|
|
1456
|
+
var _a, _b, _c, _d;
|
|
1372
1457
|
setBusy(true);
|
|
1373
1458
|
let result;
|
|
1459
|
+
const events = takeEvents();
|
|
1374
1460
|
try {
|
|
1375
|
-
const sent = screenshots
|
|
1461
|
+
const sent = pickAssistImages(screenshots);
|
|
1376
1462
|
result = await assist({
|
|
1377
|
-
|
|
1463
|
+
// `kind` only on drafts, so an older server sees the exact shape it
|
|
1464
|
+
// always did — it just learns the draft text now instead of a
|
|
1465
|
+
// placeholder line.
|
|
1466
|
+
messages: history2.map(
|
|
1467
|
+
(m) => m.kind ? { role: m.role, content: m.content, kind: m.kind } : m
|
|
1468
|
+
),
|
|
1378
1469
|
conversationId,
|
|
1379
1470
|
screenshots: sent,
|
|
1380
|
-
|
|
1381
|
-
|
|
1471
|
+
context: {
|
|
1472
|
+
...context != null ? context : {},
|
|
1473
|
+
imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached")
|
|
1474
|
+
},
|
|
1475
|
+
events
|
|
1382
1476
|
});
|
|
1383
1477
|
} catch (e) {
|
|
1384
|
-
|
|
1478
|
+
degradeKeepingEvents(
|
|
1479
|
+
events,
|
|
1480
|
+
"The assistant is unavailable \u2014 write your report below and send it as normal."
|
|
1481
|
+
);
|
|
1385
1482
|
return;
|
|
1386
1483
|
} finally {
|
|
1387
1484
|
setBusy(false);
|
|
1388
1485
|
}
|
|
1389
1486
|
if (result.degraded) {
|
|
1390
|
-
|
|
1487
|
+
degradeKeepingEvents(events, result.degraded);
|
|
1391
1488
|
return;
|
|
1392
1489
|
}
|
|
1393
1490
|
if (result.conversationId) {
|
|
1394
1491
|
setConversationId(result.conversationId);
|
|
1395
1492
|
onConversationChange == null ? void 0 : onConversationChange(result.conversationId);
|
|
1396
1493
|
}
|
|
1397
|
-
setDuplicate((
|
|
1398
|
-
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);
|
|
1399
1496
|
if (result.solved) {
|
|
1400
1497
|
setSolved(result.solved);
|
|
1401
1498
|
setOptions([]);
|
|
@@ -1404,14 +1501,16 @@ function AssistSheet({
|
|
|
1404
1501
|
}
|
|
1405
1502
|
if (result.report) {
|
|
1406
1503
|
onDescriptionChange(result.report);
|
|
1407
|
-
|
|
1504
|
+
aiDraftRef.current = result.report;
|
|
1505
|
+
logEvent("draft_shown");
|
|
1506
|
+
setMessages([...history2, { role: "assistant", content: result.report, kind: "report" }]);
|
|
1408
1507
|
setOptions([]);
|
|
1409
1508
|
setPhase("draft");
|
|
1410
1509
|
return;
|
|
1411
1510
|
}
|
|
1412
1511
|
if (result.question) {
|
|
1413
1512
|
setMessages([...history2, { role: "assistant", content: result.question }]);
|
|
1414
|
-
setOptions((
|
|
1513
|
+
setOptions((_d = result.options) != null ? _d : []);
|
|
1415
1514
|
return;
|
|
1416
1515
|
}
|
|
1417
1516
|
onDegrade("The assistant had nothing to add \u2014 write your report below and send it as normal.");
|
|
@@ -1430,7 +1529,14 @@ function AssistSheet({
|
|
|
1430
1529
|
const value = text.trim();
|
|
1431
1530
|
if (!value || busy) return;
|
|
1432
1531
|
setOptions([]);
|
|
1433
|
-
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 }];
|
|
1434
1540
|
setMessages(history2);
|
|
1435
1541
|
setInput("");
|
|
1436
1542
|
void runTurn(history2);
|
|
@@ -1439,7 +1545,56 @@ function AssistSheet({
|
|
|
1439
1545
|
onPickType(tile);
|
|
1440
1546
|
setPhase(tile === "RATING" ? "rating" : "chat");
|
|
1441
1547
|
}
|
|
1548
|
+
function withCurrentDraft(history2) {
|
|
1549
|
+
const current = description.trim();
|
|
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;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return next;
|
|
1558
|
+
}
|
|
1559
|
+
function sendDraft() {
|
|
1560
|
+
const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
|
|
1561
|
+
logEvent("draft_sent", edited ? "edited" : "as drafted");
|
|
1562
|
+
flushEvents();
|
|
1563
|
+
onSend();
|
|
1564
|
+
}
|
|
1442
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
|
+
}
|
|
1443
1598
|
const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
|
|
1444
1599
|
var _a, _b;
|
|
1445
1600
|
return (_b = (_a = w[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
|
|
@@ -1464,7 +1619,7 @@ function AssistSheet({
|
|
|
1464
1619
|
@keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}
|
|
1465
1620
|
@keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}
|
|
1466
1621
|
@keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}
|
|
1467
|
-
[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}
|
|
1468
1623
|
` }),
|
|
1469
1624
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1470
1625
|
"div",
|
|
@@ -1484,7 +1639,7 @@ function AssistSheet({
|
|
|
1484
1639
|
animation: "gg-sheet-fade .18s ease",
|
|
1485
1640
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
1486
1641
|
},
|
|
1487
|
-
onClick:
|
|
1642
|
+
onClick: () => leave("closed"),
|
|
1488
1643
|
onPointerDown: (e) => e.stopPropagation(),
|
|
1489
1644
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1490
1645
|
"div",
|
|
@@ -1564,7 +1719,7 @@ function AssistSheet({
|
|
|
1564
1719
|
{
|
|
1565
1720
|
type: "button",
|
|
1566
1721
|
"data-gg-write-myself": "",
|
|
1567
|
-
onClick:
|
|
1722
|
+
onClick: () => leave("write_myself", `header, ${phase}`),
|
|
1568
1723
|
"aria-label": "Write it myself instead",
|
|
1569
1724
|
style: {
|
|
1570
1725
|
flexShrink: 0,
|
|
@@ -1820,7 +1975,10 @@ function AssistSheet({
|
|
|
1820
1975
|
{
|
|
1821
1976
|
type: "button",
|
|
1822
1977
|
"data-gg-chip": "",
|
|
1823
|
-
onClick: () =>
|
|
1978
|
+
onClick: () => {
|
|
1979
|
+
logEvent("starter_tap", s);
|
|
1980
|
+
send(s);
|
|
1981
|
+
},
|
|
1824
1982
|
style: {
|
|
1825
1983
|
border: `1px solid ${t2.inputBorder}`,
|
|
1826
1984
|
background: "transparent",
|
|
@@ -1840,6 +1998,60 @@ function AssistSheet({
|
|
|
1840
1998
|
] }),
|
|
1841
1999
|
messages.map((m, i) => {
|
|
1842
2000
|
const mine = m.role === "user";
|
|
2001
|
+
if (m.kind === "report") {
|
|
2002
|
+
const live = phase === "draft" && i === messages.length - 1;
|
|
2003
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", minWidth: 0 }, children: [
|
|
2004
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { who: "assistant", theme: t2 }),
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2006
|
+
"div",
|
|
2007
|
+
{
|
|
2008
|
+
"data-gg-draft-bubble": "",
|
|
2009
|
+
style: {
|
|
2010
|
+
maxWidth: "82%",
|
|
2011
|
+
minWidth: 0,
|
|
2012
|
+
padding: "9px 12px",
|
|
2013
|
+
borderRadius: "12px 12px 12px 4px",
|
|
2014
|
+
fontSize: "13px",
|
|
2015
|
+
lineHeight: 1.55,
|
|
2016
|
+
backgroundColor: t2.bgSecondary,
|
|
2017
|
+
color: t2.text,
|
|
2018
|
+
border: live ? "none" : `1px solid ${t2.accent}66`
|
|
2019
|
+
},
|
|
2020
|
+
children: live ? "Here's your report \u2014 have a read." : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2021
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2022
|
+
"span",
|
|
2023
|
+
{
|
|
2024
|
+
style: {
|
|
2025
|
+
display: "block",
|
|
2026
|
+
fontSize: "10px",
|
|
2027
|
+
fontWeight: 700,
|
|
2028
|
+
letterSpacing: ".06em",
|
|
2029
|
+
textTransform: "uppercase",
|
|
2030
|
+
color: t2.accent,
|
|
2031
|
+
marginBottom: "4px"
|
|
2032
|
+
},
|
|
2033
|
+
children: "Draft so far"
|
|
2034
|
+
}
|
|
2035
|
+
),
|
|
2036
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2037
|
+
"span",
|
|
2038
|
+
{
|
|
2039
|
+
style: {
|
|
2040
|
+
display: "block",
|
|
2041
|
+
whiteSpace: "pre-wrap",
|
|
2042
|
+
wordBreak: "break-word",
|
|
2043
|
+
maxHeight: "160px",
|
|
2044
|
+
overflowY: "auto",
|
|
2045
|
+
color: t2.textMuted
|
|
2046
|
+
},
|
|
2047
|
+
children: m.content
|
|
2048
|
+
}
|
|
2049
|
+
)
|
|
2050
|
+
] })
|
|
2051
|
+
}
|
|
2052
|
+
)
|
|
2053
|
+
] }, i);
|
|
2054
|
+
}
|
|
1843
2055
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1844
2056
|
"div",
|
|
1845
2057
|
{
|
|
@@ -1873,6 +2085,7 @@ function AssistSheet({
|
|
|
1873
2085
|
i
|
|
1874
2086
|
);
|
|
1875
2087
|
}),
|
|
2088
|
+
duplicate && !busy && phase === "chat" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: renderKnownIssue({ title: false }) }),
|
|
1876
2089
|
options.length > 0 && !busy && phase === "chat" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1877
2090
|
"div",
|
|
1878
2091
|
{
|
|
@@ -1894,7 +2107,10 @@ function AssistSheet({
|
|
|
1894
2107
|
type: "button",
|
|
1895
2108
|
"data-gg-chip": "",
|
|
1896
2109
|
"data-gg-option": "",
|
|
1897
|
-
onClick: () =>
|
|
2110
|
+
onClick: () => {
|
|
2111
|
+
logEvent("option_tap", option);
|
|
2112
|
+
send(option);
|
|
2113
|
+
},
|
|
1898
2114
|
style: {
|
|
1899
2115
|
border: `1px solid ${t2.inputBorder}`,
|
|
1900
2116
|
background: "transparent",
|
|
@@ -1968,35 +2184,13 @@ function AssistSheet({
|
|
|
1968
2184
|
textTransform: "uppercase",
|
|
1969
2185
|
color: t2.accent
|
|
1970
2186
|
},
|
|
1971
|
-
children: "Your report \xB7 edit anything"
|
|
1972
|
-
}
|
|
1973
|
-
),
|
|
1974
|
-
duplicate && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1975
|
-
"div",
|
|
1976
|
-
{
|
|
1977
|
-
style: {
|
|
1978
|
-
display: "flex",
|
|
1979
|
-
flexDirection: "column",
|
|
1980
|
-
gap: "3px",
|
|
1981
|
-
padding: "9px 10px",
|
|
1982
|
-
borderRadius: "8px",
|
|
1983
|
-
border: "1px solid rgba(245,158,11,0.4)",
|
|
1984
|
-
backgroundColor: "rgba(245,158,11,0.08)",
|
|
1985
|
-
fontSize: "12px",
|
|
1986
|
-
lineHeight: 1.5
|
|
1987
|
-
},
|
|
1988
|
-
children: [
|
|
1989
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: "Our team is already on this" }),
|
|
1990
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
|
|
1991
|
-
"#",
|
|
1992
|
-
duplicate.number,
|
|
1993
|
-
" ",
|
|
1994
|
-
duplicate.title
|
|
1995
|
-
] }),
|
|
1996
|
-
/* @__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." })
|
|
1997
|
-
]
|
|
2187
|
+
children: duplicate ? `What we'll add to #${duplicate.number} \xB7 edit anything` : "Your report \xB7 edit anything"
|
|
1998
2188
|
}
|
|
1999
2189
|
),
|
|
2190
|
+
renderKnownIssue({
|
|
2191
|
+
title: true,
|
|
2192
|
+
footer: "Your details will be added to it instead of opening a new issue."
|
|
2193
|
+
}),
|
|
2000
2194
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2001
2195
|
"textarea",
|
|
2002
2196
|
{
|
|
@@ -2091,26 +2285,7 @@ function AssistSheet({
|
|
|
2091
2285
|
" ",
|
|
2092
2286
|
attachmentCount === 1 ? "attachment" : "attachments",
|
|
2093
2287
|
" will be sent with this."
|
|
2094
|
-
] })
|
|
2095
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2096
|
-
"button",
|
|
2097
|
-
{
|
|
2098
|
-
type: "button",
|
|
2099
|
-
onClick: () => setPhase("chat"),
|
|
2100
|
-
style: {
|
|
2101
|
-
alignSelf: "flex-start",
|
|
2102
|
-
border: "none",
|
|
2103
|
-
background: "transparent",
|
|
2104
|
-
color: t2.textMuted,
|
|
2105
|
-
fontSize: "12px",
|
|
2106
|
-
fontFamily: "inherit",
|
|
2107
|
-
padding: "9px 0",
|
|
2108
|
-
cursor: "pointer",
|
|
2109
|
-
textDecoration: "underline"
|
|
2110
|
-
},
|
|
2111
|
-
children: "Not quite \u2014 keep chatting"
|
|
2112
|
-
}
|
|
2113
|
-
)
|
|
2288
|
+
] })
|
|
2114
2289
|
]
|
|
2115
2290
|
}
|
|
2116
2291
|
),
|
|
@@ -2214,192 +2389,276 @@ function AssistSheet({
|
|
|
2214
2389
|
},
|
|
2215
2390
|
children: isSubmitting ? "Sending\u2026" : rating < 1 ? "Pick a star first" : "Send Rating"
|
|
2216
2391
|
}
|
|
2217
|
-
) :
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
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
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
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",
|
|
2267
2504
|
{
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
"data-gg-assist-thumb": "",
|
|
2505
|
+
"data-gg-assist-attach": "",
|
|
2506
|
+
title: "Attach an image \u2014 or just paste one",
|
|
2271
2507
|
style: {
|
|
2272
2508
|
width: "40px",
|
|
2273
2509
|
height: "40px",
|
|
2274
|
-
objectFit: "cover",
|
|
2275
2510
|
borderRadius: "8px",
|
|
2276
|
-
border: `1px
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
style: { display: "none" }
|
|
2316
|
-
}
|
|
2317
|
-
)
|
|
2318
|
-
]
|
|
2319
|
-
}
|
|
2320
|
-
),
|
|
2321
|
-
screenshots.length > MAX_ASSIST_IMAGES && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
|
|
2322
|
-
"newest ",
|
|
2323
|
-
MAX_ASSIST_IMAGES,
|
|
2324
|
-
" read"
|
|
2325
|
-
] })
|
|
2326
|
-
]
|
|
2327
|
-
}
|
|
2328
|
-
),
|
|
2329
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
|
|
2330
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2331
|
-
"textarea",
|
|
2332
|
-
{
|
|
2333
|
-
ref: inputRef,
|
|
2334
|
-
value: input,
|
|
2335
|
-
onChange: (e) => setInput(e.target.value),
|
|
2336
|
-
onKeyDown: (e) => {
|
|
2337
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
2338
|
-
e.preventDefault();
|
|
2339
|
-
send(input);
|
|
2340
|
-
}
|
|
2341
|
-
},
|
|
2342
|
-
placeholder: "Type your answer\u2026",
|
|
2343
|
-
rows: 1,
|
|
2344
|
-
disabled: busy,
|
|
2345
|
-
autoFocus: true,
|
|
2346
|
-
style: {
|
|
2347
|
-
flex: 1,
|
|
2348
|
-
minHeight: "42px",
|
|
2349
|
-
maxHeight: "120px",
|
|
2350
|
-
padding: "11px 12px",
|
|
2351
|
-
borderRadius: "10px",
|
|
2352
|
-
border: `1px solid ${t2.inputBorder}`,
|
|
2353
|
-
backgroundColor: t2.inputBg,
|
|
2354
|
-
color: t2.text,
|
|
2355
|
-
fontSize: "13px",
|
|
2356
|
-
lineHeight: 1.4,
|
|
2357
|
-
fontFamily: "inherit",
|
|
2358
|
-
resize: "none",
|
|
2359
|
-
outline: "none",
|
|
2360
|
-
boxSizing: "border-box"
|
|
2361
|
-
}
|
|
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
|
+
]
|
|
2362
2550
|
}
|
|
2363
2551
|
),
|
|
2364
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
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
|
-
|
|
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"
|
|
2391
2583
|
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
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
|
+
] })
|
|
2395
2654
|
] })
|
|
2396
|
-
|
|
2655
|
+
),
|
|
2397
2656
|
phase === "chat" && messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2398
2657
|
"button",
|
|
2399
2658
|
{
|
|
2400
2659
|
type: "button",
|
|
2401
2660
|
"data-gg-write-myself": "",
|
|
2402
|
-
onClick:
|
|
2661
|
+
onClick: () => leave("write_myself", "footer"),
|
|
2403
2662
|
style: {
|
|
2404
2663
|
display: "block",
|
|
2405
2664
|
margin: "8px auto 0",
|
|
@@ -2471,6 +2730,107 @@ var ATTACHMENT_ACCEPT = [
|
|
|
2471
2730
|
".xlsx",
|
|
2472
2731
|
".zip"
|
|
2473
2732
|
].join(",");
|
|
2733
|
+
var MAX_SCALE = 2;
|
|
2734
|
+
var FRAME_TIMEOUT_MS = 3e3;
|
|
2735
|
+
function canCaptureTabPixels() {
|
|
2736
|
+
var _a;
|
|
2737
|
+
try {
|
|
2738
|
+
return typeof navigator !== "undefined" && typeof ((_a = navigator.mediaDevices) == null ? void 0 : _a.getDisplayMedia) === "function" && typeof globalThis.CaptureController !== "undefined";
|
|
2739
|
+
} catch (e) {
|
|
2740
|
+
return false;
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
var HAVE_CURRENT_DATA = 2;
|
|
2744
|
+
function waitForFrame(video) {
|
|
2745
|
+
if (video.readyState >= HAVE_CURRENT_DATA && video.videoWidth > 0) {
|
|
2746
|
+
return Promise.resolve(true);
|
|
2747
|
+
}
|
|
2748
|
+
return new Promise((resolve) => {
|
|
2749
|
+
const timer = setTimeout(() => resolve(false), FRAME_TIMEOUT_MS);
|
|
2750
|
+
const done = () => {
|
|
2751
|
+
clearTimeout(timer);
|
|
2752
|
+
resolve(true);
|
|
2753
|
+
};
|
|
2754
|
+
if (typeof video.requestVideoFrameCallback === "function") {
|
|
2755
|
+
video.requestVideoFrameCallback(done);
|
|
2756
|
+
} else if (video.readyState >= 2) {
|
|
2757
|
+
done();
|
|
2758
|
+
} else {
|
|
2759
|
+
video.addEventListener("loadeddata", done, { once: true });
|
|
2760
|
+
}
|
|
2761
|
+
});
|
|
2762
|
+
}
|
|
2763
|
+
async function grabFrame(stream) {
|
|
2764
|
+
const video = document.createElement("video");
|
|
2765
|
+
video.muted = true;
|
|
2766
|
+
video.playsInline = true;
|
|
2767
|
+
video.srcObject = stream;
|
|
2768
|
+
try {
|
|
2769
|
+
await video.play();
|
|
2770
|
+
if (!await waitForFrame(video)) return null;
|
|
2771
|
+
if (!video.videoWidth || !video.videoHeight) return null;
|
|
2772
|
+
const maxWidth = Math.max(1, window.innerWidth) * MAX_SCALE;
|
|
2773
|
+
const factor = Math.min(1, maxWidth / video.videoWidth);
|
|
2774
|
+
const canvas = document.createElement("canvas");
|
|
2775
|
+
canvas.width = Math.round(video.videoWidth * factor);
|
|
2776
|
+
canvas.height = Math.round(video.videoHeight * factor);
|
|
2777
|
+
const ctx = canvas.getContext("2d");
|
|
2778
|
+
if (!ctx) return null;
|
|
2779
|
+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
2780
|
+
return canvas;
|
|
2781
|
+
} finally {
|
|
2782
|
+
video.srcObject = null;
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
async function captureViaTabPixels() {
|
|
2786
|
+
var _a, _b;
|
|
2787
|
+
if (!canCaptureTabPixels()) return null;
|
|
2788
|
+
let stream = null;
|
|
2789
|
+
try {
|
|
2790
|
+
const options = {
|
|
2791
|
+
video: { displaySurface: "browser" },
|
|
2792
|
+
audio: false,
|
|
2793
|
+
preferCurrentTab: true,
|
|
2794
|
+
selfBrowserSurface: "include",
|
|
2795
|
+
surfaceSwitching: "exclude",
|
|
2796
|
+
monitorTypeSurfaces: "exclude"
|
|
2797
|
+
};
|
|
2798
|
+
stream = await navigator.mediaDevices.getDisplayMedia(options);
|
|
2799
|
+
const surface = (_b = (_a = stream.getVideoTracks()[0]) == null ? void 0 : _a.getSettings()) == null ? void 0 : _b.displaySurface;
|
|
2800
|
+
if (surface && surface !== "browser") return null;
|
|
2801
|
+
const canvas = await grabFrame(stream);
|
|
2802
|
+
return canvas ? encodeScreenshot(canvas) : null;
|
|
2803
|
+
} catch (e) {
|
|
2804
|
+
return null;
|
|
2805
|
+
} finally {
|
|
2806
|
+
stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop());
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
async function captureViaHtml2Canvas() {
|
|
2810
|
+
try {
|
|
2811
|
+
const { default: html2canvas } = await import("html2canvas-pro");
|
|
2812
|
+
const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), MAX_SCALE);
|
|
2813
|
+
const canvas = await html2canvas(document.body, {
|
|
2814
|
+
scale,
|
|
2815
|
+
logging: false,
|
|
2816
|
+
useCORS: true,
|
|
2817
|
+
allowTaint: true,
|
|
2818
|
+
x: window.scrollX,
|
|
2819
|
+
y: window.scrollY,
|
|
2820
|
+
width: window.innerWidth,
|
|
2821
|
+
height: window.innerHeight,
|
|
2822
|
+
windowWidth: window.innerWidth,
|
|
2823
|
+
windowHeight: window.innerHeight
|
|
2824
|
+
});
|
|
2825
|
+
return encodeScreenshot(canvas);
|
|
2826
|
+
} catch (e) {
|
|
2827
|
+
return null;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
async function captureDefaultScreenshot() {
|
|
2831
|
+
var _a;
|
|
2832
|
+
return (_a = await captureViaTabPixels()) != null ? _a : await captureViaHtml2Canvas();
|
|
2833
|
+
}
|
|
2474
2834
|
var SEVERITY_REQUIRED = "Pick how bad it is before sending.";
|
|
2475
2835
|
function useIsDark() {
|
|
2476
2836
|
if (typeof window === "undefined") return true;
|
|
@@ -2745,27 +3105,6 @@ function isLowQualityText(text) {
|
|
|
2745
3105
|
}
|
|
2746
3106
|
return null;
|
|
2747
3107
|
}
|
|
2748
|
-
async function captureViaHtml2Canvas() {
|
|
2749
|
-
try {
|
|
2750
|
-
const { default: html2canvas } = await import("html2canvas-pro");
|
|
2751
|
-
const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), 2);
|
|
2752
|
-
const canvas = await html2canvas(document.body, {
|
|
2753
|
-
scale,
|
|
2754
|
-
logging: false,
|
|
2755
|
-
useCORS: true,
|
|
2756
|
-
allowTaint: true,
|
|
2757
|
-
x: window.scrollX,
|
|
2758
|
-
y: window.scrollY,
|
|
2759
|
-
width: window.innerWidth,
|
|
2760
|
-
height: window.innerHeight,
|
|
2761
|
-
windowWidth: window.innerWidth,
|
|
2762
|
-
windowHeight: window.innerHeight
|
|
2763
|
-
});
|
|
2764
|
-
return encodeScreenshot(canvas);
|
|
2765
|
-
} catch (e) {
|
|
2766
|
-
return null;
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
3108
|
var MIC_MESSAGES = {
|
|
2770
3109
|
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.",
|
|
2771
3110
|
notFound: "No microphone found. Connect one and try again, or type your report instead.",
|
|
@@ -2803,7 +3142,7 @@ function ReportDialog({
|
|
|
2803
3142
|
transcribeAudio: transcribeAudio2,
|
|
2804
3143
|
types,
|
|
2805
3144
|
showSeverity = true,
|
|
2806
|
-
captureScreenshot =
|
|
3145
|
+
captureScreenshot = captureDefaultScreenshot,
|
|
2807
3146
|
reporter,
|
|
2808
3147
|
onClose,
|
|
2809
3148
|
headerSlot
|
|
@@ -2833,6 +3172,7 @@ function ReportDialog({
|
|
|
2833
3172
|
const [isSubmitting, setIsSubmitting] = (0, import_react.useState)(false);
|
|
2834
3173
|
const [submitted, setSubmitted] = (0, import_react.useState)(false);
|
|
2835
3174
|
const [screenshots, setScreenshots] = (0, import_react.useState)([]);
|
|
3175
|
+
const [pageShot, setPageShot] = (0, import_react.useState)(null);
|
|
2836
3176
|
const [attachments, setAttachments] = (0, import_react.useState)([]);
|
|
2837
3177
|
const [previewIndex, setPreviewIndex] = (0, import_react.useState)(null);
|
|
2838
3178
|
const [annotatingIndex, setAnnotatingIndex] = (0, import_react.useState)(null);
|
|
@@ -2971,20 +3311,23 @@ function ReportDialog({
|
|
|
2971
3311
|
e.target.value = "";
|
|
2972
3312
|
};
|
|
2973
3313
|
const addFiles = (files) => {
|
|
2974
|
-
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) => {
|
|
2975
3324
|
const reader = new FileReader();
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
setAttachments((prev) => [
|
|
2983
|
-
...prev,
|
|
2984
|
-
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
2985
|
-
]);
|
|
2986
|
-
};
|
|
2987
|
-
}
|
|
3325
|
+
reader.onload = () => {
|
|
3326
|
+
setAttachments((prev) => [
|
|
3327
|
+
...prev,
|
|
3328
|
+
{ name: file.name, size: file.size, dataUrl: reader.result }
|
|
3329
|
+
]);
|
|
3330
|
+
};
|
|
2988
3331
|
reader.readAsDataURL(file);
|
|
2989
3332
|
});
|
|
2990
3333
|
};
|
|
@@ -2998,6 +3341,7 @@ function ReportDialog({
|
|
|
2998
3341
|
setStep(2);
|
|
2999
3342
|
}
|
|
3000
3343
|
const shot = await captureScreenshot();
|
|
3344
|
+
setPageShot(shot != null ? shot : null);
|
|
3001
3345
|
if (shot) setScreenshots([shot]);
|
|
3002
3346
|
if (assist && !assistUsed) setAssistOpen(true);
|
|
3003
3347
|
setIsOpen(true);
|
|
@@ -5195,6 +5539,7 @@ function ReportDialog({
|
|
|
5195
5539
|
imageSrc: screenshots[annotatingIndex],
|
|
5196
5540
|
onCancel: () => setAnnotatingIndex(null),
|
|
5197
5541
|
onSave: (dataUrl) => {
|
|
5542
|
+
if (screenshots[annotatingIndex] === pageShot) setPageShot(dataUrl);
|
|
5198
5543
|
setScreenshots(
|
|
5199
5544
|
(prev) => prev.map((s, i) => i === annotatingIndex ? dataUrl : s)
|
|
5200
5545
|
);
|
|
@@ -5220,7 +5565,9 @@ function ReportDialog({
|
|
|
5220
5565
|
accentText: t2.accentText
|
|
5221
5566
|
},
|
|
5222
5567
|
screenshots,
|
|
5568
|
+
pageShot,
|
|
5223
5569
|
onAddImages: addFiles,
|
|
5570
|
+
onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
|
|
5224
5571
|
attachmentCount: screenshots.length + attachments.length,
|
|
5225
5572
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|
|
5226
5573
|
reportTypeLabel: getTypeLabel(reportType),
|