glitchgrab 1.35.0 → 1.36.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.mjs CHANGED
@@ -588,7 +588,7 @@ async function enhanceText(text, token, baseUrl, screenshot, context) {
588
588
  }
589
589
  }
590
590
  async function assistTurn(params, token, baseUrl) {
591
- var _a, _b, _c, _d, _e, _f, _g;
591
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
592
592
  const offline = {
593
593
  conversationId: null,
594
594
  question: null,
@@ -617,7 +617,10 @@ async function assistTurn(params, token, baseUrl) {
617
617
  return {
618
618
  conversationId: (_c = (_b = envelope.data) == null ? void 0 : _b.conversationId) != null ? _c : null,
619
619
  question: (_e = (_d = envelope.data) == null ? void 0 : _d.question) != null ? _e : null,
620
- report: (_g = (_f = envelope.data) == null ? void 0 : _f.report) != null ? _g : null,
620
+ options: (_g = (_f = envelope.data) == null ? void 0 : _f.options) != null ? _g : [],
621
+ report: (_i = (_h = envelope.data) == null ? void 0 : _h.report) != null ? _i : null,
622
+ duplicate: (_k = (_j = envelope.data) == null ? void 0 : _j.duplicate) != null ? _k : null,
623
+ solved: (_m = (_l = envelope.data) == null ? void 0 : _l.solved) != null ? _m : null,
621
624
  degraded: null
622
625
  };
623
626
  } catch (e) {
@@ -1148,6 +1151,26 @@ function AnnotationCanvas({ imageSrc, onSave, onCancel }) {
1148
1151
  }
1149
1152
  );
1150
1153
  }
1154
+ function getTypeLabel(type) {
1155
+ switch (type) {
1156
+ case "RATING":
1157
+ return "Rating";
1158
+ case "BUG":
1159
+ return "Bug Report";
1160
+ case "FEATURE_REQUEST":
1161
+ return "Feature Request";
1162
+ case "UI_IMPROVEMENT":
1163
+ return "UI Improvement";
1164
+ case "PERFORMANCE":
1165
+ return "Performance";
1166
+ case "SECURITY":
1167
+ return "Security";
1168
+ case "QUESTION":
1169
+ return "Question";
1170
+ case "OTHER":
1171
+ return "Other";
1172
+ }
1173
+ }
1151
1174
  var STARTERS = [
1152
1175
  "Something on this page is broken",
1153
1176
  "It did the wrong thing",
@@ -1226,6 +1249,12 @@ function AssistSheet({
1226
1249
  attachmentCount,
1227
1250
  context,
1228
1251
  reportTypeLabel,
1252
+ typePicked,
1253
+ currentTile,
1254
+ tiles,
1255
+ onPickType,
1256
+ rating,
1257
+ onRatingChange,
1229
1258
  projectSlot,
1230
1259
  reporterName,
1231
1260
  description,
@@ -1233,18 +1262,26 @@ function AssistSheet({
1233
1262
  severity,
1234
1263
  onSeverityChange,
1235
1264
  showSeverity,
1265
+ onDuplicateChange,
1236
1266
  isSubmitting,
1237
1267
  submitted,
1238
1268
  onSend,
1239
1269
  onDegrade,
1240
- onClose
1270
+ onClose,
1271
+ onFinish
1241
1272
  }) {
1242
1273
  const narrow = useIsNarrow();
1243
1274
  const [messages, setMessages] = useState2([]);
1244
1275
  const [input, setInput] = useState2("");
1245
1276
  const [busy, setBusy] = useState2(false);
1246
1277
  const [conversationId, setConversationId] = useState2(null);
1247
- const [phase, setPhase] = useState2("chat");
1278
+ const [hoveredStar, setHoveredStar] = useState2(0);
1279
+ const [options, setOptions] = useState2([]);
1280
+ const [duplicate, setDuplicate] = useState2(null);
1281
+ const [solved, setSolved] = useState2(null);
1282
+ const [phase, setPhase] = useState2(
1283
+ !typePicked ? "type" : currentTile === "RATING" ? "rating" : "chat"
1284
+ );
1248
1285
  const scrollRef = useRef2(null);
1249
1286
  const inputRef = useRef2(null);
1250
1287
  const draftRef = useRef2(null);
@@ -1258,6 +1295,7 @@ function AssistSheet({
1258
1295
  if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
1259
1296
  }, [phase]);
1260
1297
  async function runTurn(history2) {
1298
+ var _a, _b, _c, _d;
1261
1299
  setBusy(true);
1262
1300
  let result;
1263
1301
  try {
@@ -1273,14 +1311,24 @@ function AssistSheet({
1273
1311
  return;
1274
1312
  }
1275
1313
  if (result.conversationId) setConversationId(result.conversationId);
1314
+ setDuplicate((_a = result.duplicate) != null ? _a : null);
1315
+ onDuplicateChange == null ? void 0 : onDuplicateChange((_c = (_b = result.duplicate) == null ? void 0 : _b.number) != null ? _c : null);
1316
+ if (result.solved) {
1317
+ setSolved(result.solved);
1318
+ setOptions([]);
1319
+ setPhase("solved");
1320
+ return;
1321
+ }
1276
1322
  if (result.report) {
1277
1323
  onDescriptionChange(result.report);
1278
1324
  setMessages([...history2, { role: "assistant", content: "Here's your report \u2014 have a read." }]);
1325
+ setOptions([]);
1279
1326
  setPhase("draft");
1280
1327
  return;
1281
1328
  }
1282
1329
  if (result.question) {
1283
1330
  setMessages([...history2, { role: "assistant", content: result.question }]);
1331
+ setOptions((_d = result.options) != null ? _d : []);
1284
1332
  return;
1285
1333
  }
1286
1334
  onDegrade("The assistant had nothing to add \u2014 write your report below and send it as normal.");
@@ -1288,6 +1336,7 @@ function AssistSheet({
1288
1336
  useEffect2(() => {
1289
1337
  if (seededRef.current) return;
1290
1338
  seededRef.current = true;
1339
+ if (!typePicked || currentTile === "RATING") return;
1291
1340
  const seed = description.trim();
1292
1341
  if (!seed) return;
1293
1342
  const history2 = [{ role: "user", content: seed }];
@@ -1297,12 +1346,17 @@ function AssistSheet({
1297
1346
  function send(text) {
1298
1347
  const value = text.trim();
1299
1348
  if (!value || busy) return;
1349
+ setOptions([]);
1300
1350
  const history2 = [...messages, { role: "user", content: value }];
1301
1351
  setMessages(history2);
1302
1352
  setInput("");
1303
1353
  void runTurn(history2);
1304
1354
  }
1305
- const empty = messages.length === 0 && !busy;
1355
+ function pickType(tile) {
1356
+ onPickType(tile);
1357
+ setPhase(tile === "RATING" ? "rating" : "chat");
1358
+ }
1359
+ const empty = phase === "chat" && messages.length === 0 && !busy;
1306
1360
  const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
1307
1361
  var _a, _b;
1308
1362
  return (_b = (_a = w[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
@@ -1418,7 +1472,7 @@ function AssistSheet({
1418
1472
  }
1419
1473
  ),
1420
1474
  /* @__PURE__ */ jsxs2("div", { style: { fontSize: "11.5px", color: t2.textMuted, marginTop: "3px" }, children: [
1421
- reportTypeLabel,
1475
+ phase === "type" ? null : reportTypeLabel,
1422
1476
  projectSlot ? /* @__PURE__ */ jsx2("span", { style: { marginLeft: "6px" }, children: projectSlot }) : null
1423
1477
  ] })
1424
1478
  ] }),
@@ -1468,6 +1522,182 @@ function AssistSheet({
1468
1522
  minWidth: 0
1469
1523
  },
1470
1524
  children: [
1525
+ phase === "type" && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
1526
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
1527
+ /* @__PURE__ */ jsx2(Avatar, { who: "assistant", theme: t2 }),
1528
+ /* @__PURE__ */ jsxs2(
1529
+ "div",
1530
+ {
1531
+ style: {
1532
+ padding: "9px 12px",
1533
+ borderRadius: "12px 12px 12px 4px",
1534
+ backgroundColor: t2.bgSecondary,
1535
+ fontSize: "13px",
1536
+ lineHeight: 1.55,
1537
+ maxWidth: "88%"
1538
+ },
1539
+ children: [
1540
+ reporterName ? `Hi ${reporterName.split(" ")[0]} \u2014 w` : "W",
1541
+ "hat do you want to do? Pick one and I'll take it from there."
1542
+ ]
1543
+ }
1544
+ )
1545
+ ] }),
1546
+ /* @__PURE__ */ jsx2(
1547
+ "div",
1548
+ {
1549
+ style: {
1550
+ display: "flex",
1551
+ flexWrap: "wrap",
1552
+ gap: "6px",
1553
+ paddingLeft: "32px"
1554
+ },
1555
+ children: tiles.map((tile) => {
1556
+ const rate = tile === "RATING";
1557
+ return /* @__PURE__ */ jsx2(
1558
+ "button",
1559
+ {
1560
+ type: "button",
1561
+ "data-gg-chip": "",
1562
+ "data-gg-tile": tile,
1563
+ onClick: () => pickType(tile),
1564
+ style: {
1565
+ display: "inline-flex",
1566
+ alignItems: "center",
1567
+ gap: "5px",
1568
+ // The rating is the only tile that isn't a report, so
1569
+ // it wears the star colour the dialog's hero row uses
1570
+ // rather than hiding among the report types.
1571
+ border: `1px solid ${rate ? "rgba(245,158,11,0.5)" : t2.inputBorder}`,
1572
+ background: rate ? "rgba(245,158,11,0.08)" : "transparent",
1573
+ color: rate ? "#f59e0b" : t2.textMuted,
1574
+ borderRadius: "999px",
1575
+ // 8px vertical keeps the tap target at ~32px.
1576
+ padding: "8px 12px",
1577
+ fontSize: "12px",
1578
+ fontWeight: rate ? 600 : 400,
1579
+ fontFamily: "inherit",
1580
+ cursor: "pointer"
1581
+ },
1582
+ children: rate ? "\u2605 Rate us" : getTypeLabel(tile)
1583
+ },
1584
+ tile
1585
+ );
1586
+ })
1587
+ }
1588
+ )
1589
+ ] }),
1590
+ phase === "rating" && !submitted && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
1591
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
1592
+ /* @__PURE__ */ jsx2(Avatar, { who: "assistant", theme: t2 }),
1593
+ /* @__PURE__ */ jsx2(
1594
+ "div",
1595
+ {
1596
+ style: {
1597
+ padding: "9px 12px",
1598
+ borderRadius: "12px 12px 12px 4px",
1599
+ backgroundColor: t2.bgSecondary,
1600
+ fontSize: "13px",
1601
+ lineHeight: 1.55,
1602
+ maxWidth: "88%"
1603
+ },
1604
+ children: "How are we doing? Tap a star \u2014 the words are optional."
1605
+ }
1606
+ )
1607
+ ] }),
1608
+ /* @__PURE__ */ jsxs2(
1609
+ "div",
1610
+ {
1611
+ style: {
1612
+ display: "flex",
1613
+ flexDirection: "column",
1614
+ gap: "10px",
1615
+ marginLeft: "32px",
1616
+ padding: "12px",
1617
+ borderRadius: "12px",
1618
+ border: "1px solid rgba(245,158,11,0.4)",
1619
+ backgroundColor: "rgba(245,158,11,0.06)"
1620
+ },
1621
+ children: [
1622
+ /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: "4px" }, role: "group", "aria-label": "Rating", children: [1, 2, 3, 4, 5].map((star) => {
1623
+ const filled = star <= (hoveredStar || rating);
1624
+ return /* @__PURE__ */ jsx2(
1625
+ "button",
1626
+ {
1627
+ type: "button",
1628
+ "aria-label": `${star} star${star > 1 ? "s" : ""}`,
1629
+ "aria-pressed": star <= rating,
1630
+ onClick: () => onRatingChange(star),
1631
+ onMouseEnter: () => setHoveredStar(star),
1632
+ onMouseLeave: () => setHoveredStar(0),
1633
+ style: {
1634
+ border: "none",
1635
+ background: "transparent",
1636
+ padding: 0,
1637
+ cursor: "pointer",
1638
+ lineHeight: 0
1639
+ },
1640
+ children: /* @__PURE__ */ jsx2("svg", { width: "30", height: "30", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(
1641
+ "path",
1642
+ {
1643
+ d: "M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z",
1644
+ fill: filled ? "#f59e0b" : "transparent",
1645
+ stroke: filled ? "#f59e0b" : t2.inputBorder,
1646
+ strokeWidth: "1.5",
1647
+ strokeLinejoin: "round"
1648
+ }
1649
+ ) })
1650
+ },
1651
+ star
1652
+ );
1653
+ }) }),
1654
+ /* @__PURE__ */ jsx2(
1655
+ "textarea",
1656
+ {
1657
+ value: description,
1658
+ onChange: (e) => onDescriptionChange(e.target.value),
1659
+ rows: 3,
1660
+ placeholder: "What made it good \u2014 or what let you down? (optional)",
1661
+ style: {
1662
+ width: "100%",
1663
+ padding: "10px",
1664
+ borderRadius: "8px",
1665
+ border: `1px solid ${t2.inputBorder}`,
1666
+ backgroundColor: t2.inputBg,
1667
+ color: t2.text,
1668
+ fontSize: "13px",
1669
+ lineHeight: 1.5,
1670
+ fontFamily: "inherit",
1671
+ resize: "vertical",
1672
+ outline: "none",
1673
+ boxSizing: "border-box"
1674
+ }
1675
+ }
1676
+ ),
1677
+ /* @__PURE__ */ jsx2(
1678
+ "button",
1679
+ {
1680
+ type: "button",
1681
+ onClick: () => setPhase("type"),
1682
+ style: {
1683
+ alignSelf: "flex-start",
1684
+ border: "none",
1685
+ background: "transparent",
1686
+ color: t2.textMuted,
1687
+ fontSize: "12px",
1688
+ fontFamily: "inherit",
1689
+ // A bare text link is ~14px tall — half a thumb.
1690
+ padding: "9px 0",
1691
+ cursor: "pointer",
1692
+ textDecoration: "underline"
1693
+ },
1694
+ children: "Report something instead"
1695
+ }
1696
+ )
1697
+ ]
1698
+ }
1699
+ )
1700
+ ] }),
1471
1701
  empty && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
1472
1702
  /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
1473
1703
  /* @__PURE__ */ jsx2(Avatar, { who: "assistant", theme: t2 }),
@@ -1556,6 +1786,47 @@ function AssistSheet({
1556
1786
  i
1557
1787
  );
1558
1788
  }),
1789
+ options.length > 0 && !busy && phase === "chat" && /* @__PURE__ */ jsx2(
1790
+ "div",
1791
+ {
1792
+ style: {
1793
+ display: "flex",
1794
+ // Long labels wrapped into a ragged row that always stranded
1795
+ // the last chip on a line of its own. Past ~24 characters
1796
+ // these stop being chips and become a choice list, so they
1797
+ // stack full width and read like one.
1798
+ flexDirection: options.some((o) => o.length > 24) ? "column" : "row",
1799
+ alignItems: options.some((o) => o.length > 24) ? "stretch" : "flex-start",
1800
+ flexWrap: "wrap",
1801
+ gap: "6px",
1802
+ paddingLeft: "32px"
1803
+ },
1804
+ children: options.map((option) => /* @__PURE__ */ jsx2(
1805
+ "button",
1806
+ {
1807
+ type: "button",
1808
+ "data-gg-chip": "",
1809
+ "data-gg-option": "",
1810
+ onClick: () => send(option),
1811
+ style: {
1812
+ border: `1px solid ${t2.inputBorder}`,
1813
+ background: "transparent",
1814
+ color: t2.textMuted,
1815
+ borderRadius: "999px",
1816
+ // Same 8px as the picker chips — one tap target size in
1817
+ // this sheet, not two.
1818
+ padding: "8px 12px",
1819
+ fontSize: "12px",
1820
+ fontFamily: "inherit",
1821
+ cursor: "pointer",
1822
+ textAlign: "left"
1823
+ },
1824
+ children: option
1825
+ },
1826
+ option
1827
+ ))
1828
+ }
1829
+ ),
1559
1830
  busy && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, role: "status", "aria-label": "Thinking", children: [
1560
1831
  /* @__PURE__ */ jsx2(Avatar, { who: "assistant", theme: t2 }),
1561
1832
  /* @__PURE__ */ jsx2(
@@ -1613,6 +1884,32 @@ function AssistSheet({
1613
1884
  children: "Your report \xB7 edit anything"
1614
1885
  }
1615
1886
  ),
1887
+ duplicate && /* @__PURE__ */ jsxs2(
1888
+ "div",
1889
+ {
1890
+ style: {
1891
+ display: "flex",
1892
+ flexDirection: "column",
1893
+ gap: "3px",
1894
+ padding: "9px 10px",
1895
+ borderRadius: "8px",
1896
+ border: "1px solid rgba(245,158,11,0.4)",
1897
+ backgroundColor: "rgba(245,158,11,0.08)",
1898
+ fontSize: "12px",
1899
+ lineHeight: 1.5
1900
+ },
1901
+ children: [
1902
+ /* @__PURE__ */ jsx2("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: "Our team is already on this" }),
1903
+ /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
1904
+ "#",
1905
+ duplicate.number,
1906
+ " ",
1907
+ duplicate.title
1908
+ ] }),
1909
+ /* @__PURE__ */ jsx2("span", { style: { color: t2.textMuted }, children: "Your details will be added to it instead of opening a new issue." })
1910
+ ]
1911
+ }
1912
+ ),
1616
1913
  /* @__PURE__ */ jsx2(
1617
1914
  "textarea",
1618
1915
  {
@@ -1696,7 +1993,7 @@ function AssistSheet({
1696
1993
  color: t2.textMuted,
1697
1994
  fontSize: "12px",
1698
1995
  fontFamily: "inherit",
1699
- padding: 0,
1996
+ padding: "9px 0",
1700
1997
  cursor: "pointer",
1701
1998
  textDecoration: "underline"
1702
1999
  },
@@ -1706,6 +2003,33 @@ function AssistSheet({
1706
2003
  ]
1707
2004
  }
1708
2005
  ),
2006
+ phase === "solved" && solved && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
2007
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
2008
+ /* @__PURE__ */ jsx2(Avatar, { who: "assistant", theme: t2 }),
2009
+ /* @__PURE__ */ jsx2(
2010
+ "div",
2011
+ {
2012
+ style: {
2013
+ padding: "9px 12px",
2014
+ borderRadius: "12px 12px 12px 4px",
2015
+ backgroundColor: t2.bgSecondary,
2016
+ fontSize: "13px",
2017
+ lineHeight: 1.55,
2018
+ maxWidth: "88%",
2019
+ whiteSpace: "pre-wrap"
2020
+ },
2021
+ children: solved
2022
+ }
2023
+ )
2024
+ ] }),
2025
+ /* @__PURE__ */ jsx2(
2026
+ "span",
2027
+ {
2028
+ style: { fontSize: "11.5px", color: t2.textMuted, paddingLeft: "32px" },
2029
+ children: "Nothing was filed \u2014 you are all set."
2030
+ }
2031
+ )
2032
+ ] }),
1709
2033
  submitted && /* @__PURE__ */ jsxs2(
1710
2034
  "div",
1711
2035
  {
@@ -1727,7 +2051,7 @@ function AssistSheet({
1727
2051
  )
1728
2052
  }
1729
2053
  ),
1730
- !submitted && /* @__PURE__ */ jsx2(
2054
+ !submitted && phase !== "type" && /* @__PURE__ */ jsx2(
1731
2055
  "div",
1732
2056
  {
1733
2057
  style: {
@@ -1737,7 +2061,48 @@ function AssistSheet({
1737
2061
  paddingBottom: narrow ? "max(12px, env(safe-area-inset-bottom))" : "12px",
1738
2062
  backgroundColor: t2.bg
1739
2063
  },
1740
- children: phase === "draft" ? /* @__PURE__ */ jsx2(
2064
+ children: phase === "solved" ? /* @__PURE__ */ jsx2(
2065
+ "button",
2066
+ {
2067
+ type: "button",
2068
+ "data-gg-sheet-send": "",
2069
+ onClick: () => (onFinish != null ? onFinish : onClose)(),
2070
+ style: {
2071
+ width: "100%",
2072
+ padding: "12px",
2073
+ borderRadius: "10px",
2074
+ border: "none",
2075
+ backgroundColor: t2.accent,
2076
+ color: t2.accentText,
2077
+ fontSize: "14px",
2078
+ fontWeight: 700,
2079
+ fontFamily: "inherit",
2080
+ cursor: "pointer"
2081
+ },
2082
+ children: "Done"
2083
+ }
2084
+ ) : phase === "rating" ? /* @__PURE__ */ jsx2(
2085
+ "button",
2086
+ {
2087
+ type: "button",
2088
+ "data-gg-sheet-send": "",
2089
+ onClick: onSend,
2090
+ disabled: isSubmitting || rating < 1,
2091
+ style: {
2092
+ width: "100%",
2093
+ padding: "12px",
2094
+ borderRadius: "10px",
2095
+ border: "none",
2096
+ backgroundColor: isSubmitting || rating < 1 ? t2.bgSecondary : "#f59e0b",
2097
+ color: isSubmitting || rating < 1 ? t2.textMuted : "#1a1a1a",
2098
+ fontSize: "14px",
2099
+ fontWeight: 700,
2100
+ fontFamily: "inherit",
2101
+ cursor: isSubmitting || rating < 1 ? "default" : "pointer"
2102
+ },
2103
+ children: isSubmitting ? "Sending\u2026" : rating < 1 ? "Pick a star first" : "Send Rating"
2104
+ }
2105
+ ) : phase === "draft" ? /* @__PURE__ */ jsx2(
1741
2106
  "button",
1742
2107
  {
1743
2108
  type: "button",
@@ -1756,7 +2121,7 @@ function AssistSheet({
1756
2121
  fontFamily: "inherit",
1757
2122
  cursor: isSubmitting || !description.trim() ? "default" : "pointer"
1758
2123
  },
1759
- children: isSubmitting ? "Sending\u2026" : "Send Report"
2124
+ children: isSubmitting ? "Sending\u2026" : duplicate ? `Add to #${duplicate.number}` : "Send Report"
1760
2125
  }
1761
2126
  ) : /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
1762
2127
  /* @__PURE__ */ jsx2(
@@ -2193,6 +2558,8 @@ function ReportDialog({
2193
2558
  const [assistOpen, setAssistOpen] = useState3(false);
2194
2559
  const [assistNotice, setAssistNotice] = useState3(null);
2195
2560
  const [assistUsed, setAssistUsed] = useState3(false);
2561
+ const [typeChosen, setTypeChosen] = useState3(false);
2562
+ const [duplicateIssueNumber, setDuplicateIssueNumber] = useState3(null);
2196
2563
  const [isEnhanced, setIsEnhanced] = useState3(false);
2197
2564
  const [originalDescription, setOriginalDescription] = useState3(
2198
2565
  null
@@ -2300,6 +2667,7 @@ function ReportDialog({
2300
2667
  e.preventDefault();
2301
2668
  setRating(Number(e.key));
2302
2669
  setReportType("RATING");
2670
+ setTypeChosen(true);
2303
2671
  setStep(2);
2304
2672
  return;
2305
2673
  }
@@ -2311,6 +2679,7 @@ function ReportDialog({
2311
2679
  if (match) {
2312
2680
  e.preventDefault();
2313
2681
  setReportType(match);
2682
+ setTypeChosen(true);
2314
2683
  setStep(2);
2315
2684
  }
2316
2685
  };
@@ -2364,10 +2733,12 @@ function ReportDialog({
2364
2733
  setAnnotatingIndex(null);
2365
2734
  if (availableTypes.length === 1) {
2366
2735
  setReportType(availableTypes[0]);
2736
+ setTypeChosen(true);
2367
2737
  setStep(2);
2368
2738
  }
2369
2739
  const shot = await captureScreenshot();
2370
2740
  if (shot) setScreenshots([shot]);
2741
+ if (assist && !assistUsed) setAssistOpen(true);
2371
2742
  setIsOpen(true);
2372
2743
  };
2373
2744
  useEffect3(() => {
@@ -2377,6 +2748,7 @@ function ReportDialog({
2377
2748
  if (detail == null ? void 0 : detail.description) setDescription(detail.description);
2378
2749
  if (detail == null ? void 0 : detail.type) {
2379
2750
  setReportType(detail.type);
2751
+ setTypeChosen(true);
2380
2752
  setStep(2);
2381
2753
  }
2382
2754
  handleOpen();
@@ -2528,7 +2900,7 @@ function ReportDialog({
2528
2900
  } catch (e) {
2529
2901
  }
2530
2902
  };
2531
- const sheetUp = !!assist && assistOpen && !isRating;
2903
+ const sheetUp = !!assist && assistOpen;
2532
2904
  useEffect3(() => {
2533
2905
  const el = modalRef.current;
2534
2906
  if (!el) return;
@@ -2550,6 +2922,8 @@ function ReportDialog({
2550
2922
  setRating(0);
2551
2923
  setHoveredStar(0);
2552
2924
  setReportType("BUG");
2925
+ setTypeChosen(false);
2926
+ setDuplicateIssueNumber(null);
2553
2927
  setSeverity("medium");
2554
2928
  setValidationError(null);
2555
2929
  setVoiceError(null);
@@ -2734,6 +3108,9 @@ function ReportDialog({
2734
3108
  if (showSeverity && reportType === "BUG") {
2735
3109
  metadata.severity = severity;
2736
3110
  }
3111
+ if (duplicateIssueNumber) {
3112
+ metadata.duplicateIssueNumber = String(duplicateIssueNumber);
3113
+ }
2737
3114
  const result = await report(
2738
3115
  // The RATING branch returned above, so anything reaching here is a real
2739
3116
  // ReportType — the widened tile union can't leak into the report API.
@@ -3096,6 +3473,7 @@ function ReportDialog({
3096
3473
  onClick: () => {
3097
3474
  setRating(star);
3098
3475
  setReportType("RATING");
3476
+ setTypeChosen(true);
3099
3477
  setStep(2);
3100
3478
  },
3101
3479
  style: {
@@ -3206,6 +3584,7 @@ function ReportDialog({
3206
3584
  "data-gg-type": type,
3207
3585
  onClick: () => {
3208
3586
  setReportType(type);
3587
+ setTypeChosen(true);
3209
3588
  setStep(2);
3210
3589
  },
3211
3590
  style: {
@@ -3325,6 +3704,7 @@ function ReportDialog({
3325
3704
  type: "button",
3326
3705
  onClick: () => {
3327
3706
  setAssistNotice(null);
3707
+ setTypeChosen(true);
3328
3708
  setAssistOpen(true);
3329
3709
  },
3330
3710
  style: {
@@ -4473,6 +4853,21 @@ function ReportDialog({
4473
4853
  attachmentCount: screenshots.length + attachments.length,
4474
4854
  context: { ...assistContext != null ? assistContext : {}, reportType },
4475
4855
  reportTypeLabel: getTypeLabel(reportType),
4856
+ typePicked: typeChosen,
4857
+ currentTile: reportType,
4858
+ tiles: sendFeedback2 ? [...availableTypes, "RATING"] : availableTypes,
4859
+ onPickType: (tile) => {
4860
+ setReportType(tile);
4861
+ setTypeChosen(true);
4862
+ setStep(2);
4863
+ },
4864
+ onDuplicateChange: setDuplicateIssueNumber,
4865
+ onFinish: handleClose,
4866
+ rating,
4867
+ onRatingChange: (value) => {
4868
+ setRating(value);
4869
+ if (validationError) setValidationError(null);
4870
+ },
4476
4871
  projectSlot: headerSlot,
4477
4872
  reporterName: (_b = reporter == null ? void 0 : reporter.name) != null ? _b : null,
4478
4873
  description,
@@ -4502,26 +4897,6 @@ function ReportDialog({
4502
4897
  )
4503
4898
  ] });
4504
4899
  }
4505
- function getTypeLabel(type) {
4506
- switch (type) {
4507
- case "RATING":
4508
- return "Rating";
4509
- case "BUG":
4510
- return "Bug Report";
4511
- case "FEATURE_REQUEST":
4512
- return "Feature Request";
4513
- case "UI_IMPROVEMENT":
4514
- return "UI Improvement";
4515
- case "PERFORMANCE":
4516
- return "Performance";
4517
- case "SECURITY":
4518
- return "Security";
4519
- case "QUESTION":
4520
- return "Question";
4521
- case "OTHER":
4522
- return "Other";
4523
- }
4524
- }
4525
4900
  function getPlaceholder(type, idx = 0, hasVoice = false) {
4526
4901
  if (type === "RATING") return "What made it good \u2014 or what let you down? (optional)";
4527
4902
  if (hasVoice && idx === 1) return "Hold Space to speak \u2014 we'll transcribe it";