@bbearai/react 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +568 -72
- package/dist/index.mjs +542 -46
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -343,11 +343,80 @@ function BugBearProvider({ config, children, enabled = true }) {
|
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
// src/BugBearPanel.tsx
|
|
346
|
-
var
|
|
346
|
+
var import_react15 = require("react");
|
|
347
347
|
var import_react_dom = require("react-dom");
|
|
348
348
|
|
|
349
349
|
// src/widget/navigation.ts
|
|
350
350
|
var import_react2 = require("react");
|
|
351
|
+
var NAV_STORAGE_KEY = "bugbear-nav-screen";
|
|
352
|
+
function serializeScreen(screen) {
|
|
353
|
+
switch (screen.name) {
|
|
354
|
+
case "HOME":
|
|
355
|
+
case "TEST_LIST":
|
|
356
|
+
case "MESSAGE_LIST":
|
|
357
|
+
case "COMPOSE_MESSAGE":
|
|
358
|
+
case "PROFILE":
|
|
359
|
+
case "REPORT_SUCCESS":
|
|
360
|
+
return JSON.stringify({ name: screen.name });
|
|
361
|
+
case "TEST_DETAIL":
|
|
362
|
+
return JSON.stringify({ name: screen.name, testId: screen.testId });
|
|
363
|
+
case "REPORT":
|
|
364
|
+
return JSON.stringify({ name: screen.name });
|
|
365
|
+
case "ISSUE_LIST":
|
|
366
|
+
return JSON.stringify({ name: screen.name, category: screen.category });
|
|
367
|
+
// Complex screens — save their parent list instead
|
|
368
|
+
case "THREAD_DETAIL":
|
|
369
|
+
return JSON.stringify({ name: "MESSAGE_LIST" });
|
|
370
|
+
case "ISSUE_DETAIL":
|
|
371
|
+
return JSON.stringify({ name: "ISSUE_LIST", category: "open" });
|
|
372
|
+
case "TEST_FEEDBACK":
|
|
373
|
+
return JSON.stringify({ name: "TEST_LIST" });
|
|
374
|
+
default:
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function deserializeScreen(json) {
|
|
379
|
+
try {
|
|
380
|
+
const parsed = JSON.parse(json);
|
|
381
|
+
if (!parsed || !parsed.name) return null;
|
|
382
|
+
switch (parsed.name) {
|
|
383
|
+
case "HOME":
|
|
384
|
+
return { name: "HOME" };
|
|
385
|
+
case "TEST_LIST":
|
|
386
|
+
return { name: "TEST_LIST" };
|
|
387
|
+
case "MESSAGE_LIST":
|
|
388
|
+
return { name: "MESSAGE_LIST" };
|
|
389
|
+
case "COMPOSE_MESSAGE":
|
|
390
|
+
return { name: "COMPOSE_MESSAGE" };
|
|
391
|
+
case "PROFILE":
|
|
392
|
+
return { name: "PROFILE" };
|
|
393
|
+
case "REPORT_SUCCESS":
|
|
394
|
+
return { name: "REPORT_SUCCESS" };
|
|
395
|
+
case "TEST_DETAIL":
|
|
396
|
+
return { name: "TEST_DETAIL", testId: parsed.testId };
|
|
397
|
+
case "REPORT":
|
|
398
|
+
return { name: "REPORT" };
|
|
399
|
+
case "ISSUE_LIST":
|
|
400
|
+
return { name: "ISSUE_LIST", category: parsed.category || "open" };
|
|
401
|
+
default:
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
} catch {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function getInitialScreen() {
|
|
409
|
+
if (typeof window === "undefined") return { name: "HOME" };
|
|
410
|
+
try {
|
|
411
|
+
const saved = localStorage.getItem(NAV_STORAGE_KEY);
|
|
412
|
+
if (saved) {
|
|
413
|
+
const screen = deserializeScreen(saved);
|
|
414
|
+
if (screen) return screen;
|
|
415
|
+
}
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
return { name: "HOME" };
|
|
419
|
+
}
|
|
351
420
|
function navReducer(state, action) {
|
|
352
421
|
switch (action.type) {
|
|
353
422
|
case "PUSH":
|
|
@@ -363,9 +432,21 @@ function navReducer(state, action) {
|
|
|
363
432
|
}
|
|
364
433
|
}
|
|
365
434
|
function useNavigation() {
|
|
366
|
-
const
|
|
435
|
+
const initialScreen = (0, import_react2.useRef)(getInitialScreen());
|
|
436
|
+
const [state, dispatch] = (0, import_react2.useReducer)(navReducer, { stack: [initialScreen.current] });
|
|
437
|
+
const currentScreen = state.stack[state.stack.length - 1];
|
|
438
|
+
(0, import_react2.useEffect)(() => {
|
|
439
|
+
if (typeof window === "undefined") return;
|
|
440
|
+
try {
|
|
441
|
+
const serialized = serializeScreen(currentScreen);
|
|
442
|
+
if (serialized) {
|
|
443
|
+
localStorage.setItem(NAV_STORAGE_KEY, serialized);
|
|
444
|
+
}
|
|
445
|
+
} catch {
|
|
446
|
+
}
|
|
447
|
+
}, [currentScreen]);
|
|
367
448
|
return {
|
|
368
|
-
currentScreen
|
|
449
|
+
currentScreen,
|
|
369
450
|
canGoBack: state.stack.length > 1,
|
|
370
451
|
push: (screen) => dispatch({ type: "PUSH", screen }),
|
|
371
452
|
pop: () => dispatch({ type: "POP" }),
|
|
@@ -459,6 +540,36 @@ function getThreadTypeIcon(type) {
|
|
|
459
540
|
}
|
|
460
541
|
}
|
|
461
542
|
|
|
543
|
+
// src/widget/useScreenCapture.ts
|
|
544
|
+
var import_modern_screenshot = require("modern-screenshot");
|
|
545
|
+
async function capturePageScreenshot(options = {}) {
|
|
546
|
+
const { excludeElement, timeout = 3e3 } = options;
|
|
547
|
+
try {
|
|
548
|
+
const blob = await Promise.race([
|
|
549
|
+
(0, import_modern_screenshot.domToBlob)(document.documentElement, {
|
|
550
|
+
filter: (node) => {
|
|
551
|
+
if (excludeElement && node === excludeElement) return false;
|
|
552
|
+
return true;
|
|
553
|
+
},
|
|
554
|
+
scale: 1,
|
|
555
|
+
quality: 0.85
|
|
556
|
+
}),
|
|
557
|
+
new Promise(
|
|
558
|
+
(_, reject) => setTimeout(() => reject(new Error("Screenshot capture timed out")), timeout)
|
|
559
|
+
)
|
|
560
|
+
]);
|
|
561
|
+
if (!blob) return null;
|
|
562
|
+
return new File(
|
|
563
|
+
[blob],
|
|
564
|
+
`screenshot-auto-${Date.now()}.png`,
|
|
565
|
+
{ type: "image/png" }
|
|
566
|
+
);
|
|
567
|
+
} catch (err) {
|
|
568
|
+
console.warn("BugBear: Auto-capture failed, user can attach manually", err);
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
462
573
|
// src/widget/screens/HomeScreen.tsx
|
|
463
574
|
var import_react3 = require("react");
|
|
464
575
|
|
|
@@ -601,8 +712,8 @@ function MessageListScreenSkeleton() {
|
|
|
601
712
|
|
|
602
713
|
// src/widget/screens/HomeScreen.tsx
|
|
603
714
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
604
|
-
function HomeScreen({ nav }) {
|
|
605
|
-
const { assignments, unreadCount, threads, refreshAssignments, refreshThreads, issueCounts, refreshIssueCounts, isLoading } = useBugBear();
|
|
715
|
+
function HomeScreen({ nav, onReportBug }) {
|
|
716
|
+
const { assignments, unreadCount, threads, refreshAssignments, refreshThreads, issueCounts, refreshIssueCounts, dashboardUrl, isLoading } = useBugBear();
|
|
606
717
|
(0, import_react3.useEffect)(() => {
|
|
607
718
|
refreshAssignments();
|
|
608
719
|
refreshThreads();
|
|
@@ -790,9 +901,11 @@ function HomeScreen({ nav }) {
|
|
|
790
901
|
{
|
|
791
902
|
role: "button",
|
|
792
903
|
tabIndex: 0,
|
|
793
|
-
onClick: () => nav.push({ name: "REPORT", prefill: { type: "bug" } }),
|
|
904
|
+
onClick: () => onReportBug ? onReportBug() : nav.push({ name: "REPORT", prefill: { type: "bug" } }),
|
|
794
905
|
onKeyDown: (e) => {
|
|
795
|
-
if (e.key === "Enter" || e.key === " ")
|
|
906
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
907
|
+
onReportBug ? onReportBug() : nav.push({ name: "REPORT", prefill: { type: "bug" } });
|
|
908
|
+
}
|
|
796
909
|
},
|
|
797
910
|
style: {
|
|
798
911
|
backgroundColor: colors.card,
|
|
@@ -1007,6 +1120,33 @@ function HomeScreen({ nav }) {
|
|
|
1007
1120
|
" tests completed"
|
|
1008
1121
|
] })
|
|
1009
1122
|
] }),
|
|
1123
|
+
dashboardUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1124
|
+
"a",
|
|
1125
|
+
{
|
|
1126
|
+
href: dashboardUrl,
|
|
1127
|
+
target: "_blank",
|
|
1128
|
+
rel: "noopener noreferrer",
|
|
1129
|
+
style: {
|
|
1130
|
+
display: "flex",
|
|
1131
|
+
alignItems: "center",
|
|
1132
|
+
backgroundColor: colors.card,
|
|
1133
|
+
border: `1px solid ${colors.border}`,
|
|
1134
|
+
borderRadius: 12,
|
|
1135
|
+
padding: 14,
|
|
1136
|
+
marginBottom: 16,
|
|
1137
|
+
textDecoration: "none",
|
|
1138
|
+
cursor: "pointer"
|
|
1139
|
+
},
|
|
1140
|
+
children: [
|
|
1141
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: 22, marginRight: 12 }, children: "\u{1F310}" }),
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { flex: 1 }, children: [
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { display: "block", fontSize: 14, fontWeight: 600, color: colors.textPrimary }, children: "Open Dashboard" }),
|
|
1144
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { display: "block", fontSize: 12, color: colors.textMuted, marginTop: 2 }, children: "View analytics, history & more" })
|
|
1145
|
+
] }),
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: 16, color: colors.textMuted, marginLeft: 8 }, children: "\u2192" })
|
|
1147
|
+
]
|
|
1148
|
+
}
|
|
1149
|
+
),
|
|
1010
1150
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "8px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1011
1151
|
"button",
|
|
1012
1152
|
{
|
|
@@ -1097,6 +1237,37 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
1097
1237
|
setIsSubmitting(false);
|
|
1098
1238
|
}
|
|
1099
1239
|
}, [client, displayedAssignment, refreshAssignments, nav, isSubmitting]);
|
|
1240
|
+
const handleReopen = (0, import_react4.useCallback)(async () => {
|
|
1241
|
+
if (!client || !displayedAssignment || isSubmitting) return;
|
|
1242
|
+
setIsSubmitting(true);
|
|
1243
|
+
try {
|
|
1244
|
+
await client.reopenAssignment(displayedAssignment.id);
|
|
1245
|
+
await refreshAssignments();
|
|
1246
|
+
} finally {
|
|
1247
|
+
setIsSubmitting(false);
|
|
1248
|
+
}
|
|
1249
|
+
}, [client, displayedAssignment, refreshAssignments, isSubmitting]);
|
|
1250
|
+
const handleChangeResult = (0, import_react4.useCallback)(async (newStatus) => {
|
|
1251
|
+
if (!client || !displayedAssignment || isSubmitting) return;
|
|
1252
|
+
setIsSubmitting(true);
|
|
1253
|
+
try {
|
|
1254
|
+
await client.reopenAssignment(displayedAssignment.id);
|
|
1255
|
+
await client.updateAssignmentStatus(displayedAssignment.id, newStatus);
|
|
1256
|
+
await refreshAssignments();
|
|
1257
|
+
if (newStatus === "failed") {
|
|
1258
|
+
nav.replace({
|
|
1259
|
+
name: "REPORT",
|
|
1260
|
+
prefill: {
|
|
1261
|
+
type: "test_fail",
|
|
1262
|
+
assignmentId: displayedAssignment.id,
|
|
1263
|
+
testCaseId: displayedAssignment.testCase.id
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
} finally {
|
|
1268
|
+
setIsSubmitting(false);
|
|
1269
|
+
}
|
|
1270
|
+
}, [client, displayedAssignment, refreshAssignments, nav, isSubmitting]);
|
|
1100
1271
|
const handleSkip = (0, import_react4.useCallback)(async () => {
|
|
1101
1272
|
if (!client || !displayedAssignment || !selectedSkipReason) return;
|
|
1102
1273
|
setSkipping(true);
|
|
@@ -1604,6 +1775,11 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
1604
1775
|
]
|
|
1605
1776
|
}
|
|
1606
1777
|
),
|
|
1778
|
+
testCase.track && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: 12, color: colors.textSecondary, marginBottom: 6 }, children: [
|
|
1779
|
+
testCase.track.icon,
|
|
1780
|
+
" ",
|
|
1781
|
+
testCase.track.name
|
|
1782
|
+
] }),
|
|
1607
1783
|
testCase.description && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: 13, color: colors.textSecondary, lineHeight: "18px" }, children: testCase.description }),
|
|
1608
1784
|
testCase.group && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { fontSize: 12, color: colors.textMuted }, children: [
|
|
1609
1785
|
"\u{1F4C1} ",
|
|
@@ -1612,7 +1788,113 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
1612
1788
|
]
|
|
1613
1789
|
}
|
|
1614
1790
|
),
|
|
1615
|
-
|
|
1791
|
+
displayedAssignment.status === "passed" || displayedAssignment.status === "failed" || displayedAssignment.status === "skipped" || displayedAssignment.status === "blocked" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1792
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1793
|
+
"div",
|
|
1794
|
+
{
|
|
1795
|
+
style: {
|
|
1796
|
+
display: "flex",
|
|
1797
|
+
alignItems: "center",
|
|
1798
|
+
justifyContent: "center",
|
|
1799
|
+
gap: 6,
|
|
1800
|
+
padding: "8px 12px",
|
|
1801
|
+
borderRadius: 8,
|
|
1802
|
+
marginTop: 8,
|
|
1803
|
+
marginBottom: 8,
|
|
1804
|
+
backgroundColor: displayedAssignment.status === "passed" ? colors.greenDark : displayedAssignment.status === "failed" ? colors.redDark : colors.card,
|
|
1805
|
+
border: `1px solid ${displayedAssignment.status === "passed" ? colors.green : displayedAssignment.status === "failed" ? colors.red : colors.border}`
|
|
1806
|
+
},
|
|
1807
|
+
children: [
|
|
1808
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: 14 }, children: displayedAssignment.status === "passed" ? "\u2705" : displayedAssignment.status === "failed" ? "\u274C" : displayedAssignment.status === "skipped" ? "\u23ED" : "\u{1F6AB}" }),
|
|
1809
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1810
|
+
"span",
|
|
1811
|
+
{
|
|
1812
|
+
style: {
|
|
1813
|
+
fontSize: 13,
|
|
1814
|
+
fontWeight: 600,
|
|
1815
|
+
color: displayedAssignment.status === "passed" ? colors.green : displayedAssignment.status === "failed" ? "#fca5a5" : colors.textSecondary
|
|
1816
|
+
},
|
|
1817
|
+
children: [
|
|
1818
|
+
"Marked as ",
|
|
1819
|
+
displayedAssignment.status.charAt(0).toUpperCase() + displayedAssignment.status.slice(1)
|
|
1820
|
+
]
|
|
1821
|
+
}
|
|
1822
|
+
)
|
|
1823
|
+
]
|
|
1824
|
+
}
|
|
1825
|
+
),
|
|
1826
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: 10, marginTop: 4 }, children: [
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1828
|
+
"button",
|
|
1829
|
+
{
|
|
1830
|
+
type: "button",
|
|
1831
|
+
onClick: handleReopen,
|
|
1832
|
+
disabled: isSubmitting,
|
|
1833
|
+
style: {
|
|
1834
|
+
flex: 1,
|
|
1835
|
+
paddingTop: 14,
|
|
1836
|
+
paddingBottom: 14,
|
|
1837
|
+
borderRadius: 12,
|
|
1838
|
+
textAlign: "center",
|
|
1839
|
+
backgroundColor: colors.card,
|
|
1840
|
+
border: `1px solid ${colors.blue}`,
|
|
1841
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
1842
|
+
fontSize: 14,
|
|
1843
|
+
fontWeight: 600,
|
|
1844
|
+
color: colors.blue,
|
|
1845
|
+
opacity: isSubmitting ? 0.5 : 1
|
|
1846
|
+
},
|
|
1847
|
+
children: isSubmitting ? "Reopening..." : "\u{1F504} Reopen Test"
|
|
1848
|
+
}
|
|
1849
|
+
),
|
|
1850
|
+
displayedAssignment.status === "passed" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1851
|
+
"button",
|
|
1852
|
+
{
|
|
1853
|
+
type: "button",
|
|
1854
|
+
onClick: () => handleChangeResult("failed"),
|
|
1855
|
+
disabled: isSubmitting,
|
|
1856
|
+
style: {
|
|
1857
|
+
flex: 1,
|
|
1858
|
+
paddingTop: 14,
|
|
1859
|
+
paddingBottom: 14,
|
|
1860
|
+
borderRadius: 12,
|
|
1861
|
+
textAlign: "center",
|
|
1862
|
+
backgroundColor: colors.redDark,
|
|
1863
|
+
border: `1px solid ${colors.red}`,
|
|
1864
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
1865
|
+
fontSize: 14,
|
|
1866
|
+
fontWeight: 600,
|
|
1867
|
+
color: "#fca5a5",
|
|
1868
|
+
opacity: isSubmitting ? 0.5 : 1
|
|
1869
|
+
},
|
|
1870
|
+
children: "Change to Fail"
|
|
1871
|
+
}
|
|
1872
|
+
),
|
|
1873
|
+
displayedAssignment.status === "failed" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1874
|
+
"button",
|
|
1875
|
+
{
|
|
1876
|
+
type: "button",
|
|
1877
|
+
onClick: () => handleChangeResult("passed"),
|
|
1878
|
+
disabled: isSubmitting,
|
|
1879
|
+
style: {
|
|
1880
|
+
flex: 1,
|
|
1881
|
+
paddingTop: 14,
|
|
1882
|
+
paddingBottom: 14,
|
|
1883
|
+
borderRadius: 12,
|
|
1884
|
+
textAlign: "center",
|
|
1885
|
+
backgroundColor: colors.greenDark,
|
|
1886
|
+
border: `1px solid ${colors.green}`,
|
|
1887
|
+
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
1888
|
+
fontSize: 14,
|
|
1889
|
+
fontWeight: 600,
|
|
1890
|
+
color: "#86efac",
|
|
1891
|
+
opacity: isSubmitting ? 0.5 : 1
|
|
1892
|
+
},
|
|
1893
|
+
children: "Change to Pass"
|
|
1894
|
+
}
|
|
1895
|
+
)
|
|
1896
|
+
] })
|
|
1897
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: 10, marginTop: 8 }, children: [
|
|
1616
1898
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1617
1899
|
"button",
|
|
1618
1900
|
{
|
|
@@ -1831,10 +2113,11 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
1831
2113
|
var import_react5 = require("react");
|
|
1832
2114
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1833
2115
|
function TestListScreen({ nav }) {
|
|
1834
|
-
const { assignments, currentAssignment, refreshAssignments, isLoading } = useBugBear();
|
|
2116
|
+
const { assignments, currentAssignment, refreshAssignments, dashboardUrl, isLoading } = useBugBear();
|
|
1835
2117
|
const [filter, setFilter] = (0, import_react5.useState)("all");
|
|
1836
2118
|
const [roleFilter, setRoleFilter] = (0, import_react5.useState)(null);
|
|
1837
2119
|
const [trackFilter, setTrackFilter] = (0, import_react5.useState)(null);
|
|
2120
|
+
const [platformFilter, setPlatformFilter] = (0, import_react5.useState)("web");
|
|
1838
2121
|
const [searchQuery, setSearchQuery] = (0, import_react5.useState)("");
|
|
1839
2122
|
const [sortMode, setSortMode] = (0, import_react5.useState)("priority");
|
|
1840
2123
|
const [collapsedFolders, setCollapsedFolders] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
|
|
@@ -1912,6 +2195,7 @@ function TestListScreen({ nav }) {
|
|
|
1912
2195
|
});
|
|
1913
2196
|
}, []);
|
|
1914
2197
|
const filterAssignment = (0, import_react5.useCallback)((a) => {
|
|
2198
|
+
if (platformFilter && a.testCase.platforms && !a.testCase.platforms.includes(platformFilter)) return false;
|
|
1915
2199
|
if (roleFilter && a.testCase.role?.id !== roleFilter) return false;
|
|
1916
2200
|
if (trackFilter && a.testCase.track?.id !== trackFilter) return false;
|
|
1917
2201
|
if (searchQuery) {
|
|
@@ -1924,7 +2208,7 @@ function TestListScreen({ nav }) {
|
|
|
1924
2208
|
if (filter === "done") return a.status === "passed";
|
|
1925
2209
|
if (filter === "reopened") return a.status === "failed";
|
|
1926
2210
|
return true;
|
|
1927
|
-
}, [roleFilter, trackFilter, searchQuery, filter]);
|
|
2211
|
+
}, [platformFilter, roleFilter, trackFilter, searchQuery, filter]);
|
|
1928
2212
|
const pendingCount = assignments.filter(
|
|
1929
2213
|
(a) => a.status === "pending" || a.status === "in_progress"
|
|
1930
2214
|
).length;
|
|
@@ -2058,6 +2342,61 @@ function TestListScreen({ nav }) {
|
|
|
2058
2342
|
}
|
|
2059
2343
|
}
|
|
2060
2344
|
) }),
|
|
2345
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: 4, marginBottom: 8 }, children: [
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2347
|
+
"button",
|
|
2348
|
+
{
|
|
2349
|
+
type: "button",
|
|
2350
|
+
onClick: () => setPlatformFilter(null),
|
|
2351
|
+
style: {
|
|
2352
|
+
padding: "3px 8px",
|
|
2353
|
+
borderRadius: 6,
|
|
2354
|
+
backgroundColor: !platformFilter ? colors.card : "transparent",
|
|
2355
|
+
border: !platformFilter ? `1px solid ${colors.border}` : "1px solid transparent",
|
|
2356
|
+
cursor: "pointer",
|
|
2357
|
+
fontSize: 11,
|
|
2358
|
+
color: !platformFilter ? colors.textPrimary : colors.textMuted,
|
|
2359
|
+
fontWeight: !platformFilter ? 600 : 400,
|
|
2360
|
+
whiteSpace: "nowrap"
|
|
2361
|
+
},
|
|
2362
|
+
children: "All"
|
|
2363
|
+
}
|
|
2364
|
+
),
|
|
2365
|
+
[
|
|
2366
|
+
{ key: "web", label: "Web", icon: "\u{1F310}" },
|
|
2367
|
+
{ key: "ios", label: "iOS", icon: "\u{1F4F1}" },
|
|
2368
|
+
{ key: "android", label: "Android", icon: "\u{1F916}" }
|
|
2369
|
+
].map((p) => {
|
|
2370
|
+
const isActive = platformFilter === p.key;
|
|
2371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2372
|
+
"button",
|
|
2373
|
+
{
|
|
2374
|
+
type: "button",
|
|
2375
|
+
onClick: () => setPlatformFilter(isActive ? null : p.key),
|
|
2376
|
+
style: {
|
|
2377
|
+
display: "flex",
|
|
2378
|
+
alignItems: "center",
|
|
2379
|
+
gap: 4,
|
|
2380
|
+
padding: "3px 8px",
|
|
2381
|
+
borderRadius: 6,
|
|
2382
|
+
backgroundColor: isActive ? colors.blue + "20" : "transparent",
|
|
2383
|
+
border: isActive ? `1px solid ${colors.blue}60` : "1px solid transparent",
|
|
2384
|
+
cursor: "pointer",
|
|
2385
|
+
fontSize: 11,
|
|
2386
|
+
color: isActive ? colors.blue : colors.textMuted,
|
|
2387
|
+
fontWeight: isActive ? 600 : 400,
|
|
2388
|
+
whiteSpace: "nowrap"
|
|
2389
|
+
},
|
|
2390
|
+
children: [
|
|
2391
|
+
p.icon,
|
|
2392
|
+
" ",
|
|
2393
|
+
p.label
|
|
2394
|
+
]
|
|
2395
|
+
},
|
|
2396
|
+
p.key
|
|
2397
|
+
);
|
|
2398
|
+
})
|
|
2399
|
+
] }),
|
|
2061
2400
|
(availableTracks.length >= 2 || true) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, marginBottom: 12 }, children: [
|
|
2062
2401
|
availableTracks.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: 4, flex: 1, overflow: "auto" }, children: [
|
|
2063
2402
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
@@ -2371,7 +2710,27 @@ function TestListScreen({ nav }) {
|
|
|
2371
2710
|
]
|
|
2372
2711
|
}
|
|
2373
2712
|
),
|
|
2374
|
-
|
|
2713
|
+
dashboardUrl && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2714
|
+
"a",
|
|
2715
|
+
{
|
|
2716
|
+
href: `${dashboardUrl}/test-cases`,
|
|
2717
|
+
target: "_blank",
|
|
2718
|
+
rel: "noopener noreferrer",
|
|
2719
|
+
style: {
|
|
2720
|
+
display: "flex",
|
|
2721
|
+
alignItems: "center",
|
|
2722
|
+
justifyContent: "center",
|
|
2723
|
+
gap: 6,
|
|
2724
|
+
paddingTop: 12,
|
|
2725
|
+
fontSize: 13,
|
|
2726
|
+
fontWeight: 500,
|
|
2727
|
+
color: colors.blue,
|
|
2728
|
+
textDecoration: "none"
|
|
2729
|
+
},
|
|
2730
|
+
children: "\u{1F310} Manage on Dashboard \u2192"
|
|
2731
|
+
}
|
|
2732
|
+
),
|
|
2733
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", justifyContent: "center", paddingTop: 8, paddingBottom: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2375
2734
|
"button",
|
|
2376
2735
|
{
|
|
2377
2736
|
type: "button",
|
|
@@ -2442,6 +2801,25 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
2442
2801
|
const pickFromCamera = (0, import_react6.useCallback)(() => {
|
|
2443
2802
|
triggerFilePicker("environment");
|
|
2444
2803
|
}, [triggerFilePicker]);
|
|
2804
|
+
const addFile = (0, import_react6.useCallback)((file) => {
|
|
2805
|
+
const id = `img-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
2806
|
+
const localUri = URL.createObjectURL(file);
|
|
2807
|
+
const name = file.name || `image-${id}.png`;
|
|
2808
|
+
setImages((prev) => {
|
|
2809
|
+
if (prev.length >= maxImages) return prev;
|
|
2810
|
+
return [...prev, { id, localUri, remoteUrl: null, name, status: "uploading" }];
|
|
2811
|
+
});
|
|
2812
|
+
uploadFn(file, bucket).then((url) => {
|
|
2813
|
+
setImages((prev) => prev.map(
|
|
2814
|
+
(img) => img.id === id ? { ...img, remoteUrl: url, status: url ? "done" : "error" } : img
|
|
2815
|
+
));
|
|
2816
|
+
}).catch((err) => {
|
|
2817
|
+
console.error("BugBear: Image upload failed", err);
|
|
2818
|
+
setImages((prev) => prev.map(
|
|
2819
|
+
(img) => img.id === id ? { ...img, status: "error" } : img
|
|
2820
|
+
));
|
|
2821
|
+
});
|
|
2822
|
+
}, [maxImages, uploadFn, bucket]);
|
|
2445
2823
|
const removeImage = (0, import_react6.useCallback)((id) => {
|
|
2446
2824
|
setImages((prev) => {
|
|
2447
2825
|
const img = prev.find((i) => i.id === id);
|
|
@@ -2463,7 +2841,7 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
2463
2841
|
const getScreenshotUrls = (0, import_react6.useCallback)(() => {
|
|
2464
2842
|
return images.filter((img) => img.status === "done" && img.remoteUrl).map((img) => img.remoteUrl);
|
|
2465
2843
|
}, [images]);
|
|
2466
|
-
return { images, pickFromGallery, pickFromCamera, removeImage, clear, isUploading, hasError, getAttachments, getScreenshotUrls };
|
|
2844
|
+
return { images, pickFromGallery, pickFromCamera, addFile, removeImage, clear, isUploading, hasError, getAttachments, getScreenshotUrls };
|
|
2467
2845
|
}
|
|
2468
2846
|
|
|
2469
2847
|
// src/widget/ImagePreviewStrip.tsx
|
|
@@ -2584,7 +2962,12 @@ function ImagePickerButtons({ images, maxImages, onPickGallery, onPickCamera, on
|
|
|
2584
2962
|
maxImages
|
|
2585
2963
|
] })
|
|
2586
2964
|
] }),
|
|
2587
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ImagePreviewStrip, { images, onRemove })
|
|
2965
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ImagePreviewStrip, { images, onRemove }),
|
|
2966
|
+
typeof navigator !== "undefined" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { fontSize: 11, color: colors.textDim, display: "block", marginTop: 4 }, children: [
|
|
2967
|
+
"Paste images with ",
|
|
2968
|
+
typeof navigator !== "undefined" && navigator.platform?.includes("Mac") ? "\u2318" : "Ctrl",
|
|
2969
|
+
"+V"
|
|
2970
|
+
] })
|
|
2588
2971
|
] });
|
|
2589
2972
|
}
|
|
2590
2973
|
|
|
@@ -2882,7 +3265,7 @@ var styles = {
|
|
|
2882
3265
|
};
|
|
2883
3266
|
|
|
2884
3267
|
// src/widget/screens/ReportScreen.tsx
|
|
2885
|
-
var
|
|
3268
|
+
var import_react9 = __toESM(require("react"));
|
|
2886
3269
|
|
|
2887
3270
|
// src/widget/CategoryDropdown.tsx
|
|
2888
3271
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
@@ -2928,27 +3311,79 @@ function CategoryDropdown({ value, onChange, optional = true, disabled = false }
|
|
|
2928
3311
|
);
|
|
2929
3312
|
}
|
|
2930
3313
|
|
|
3314
|
+
// src/widget/useClipboardPaste.ts
|
|
3315
|
+
var import_react8 = require("react");
|
|
3316
|
+
function useClipboardPaste({
|
|
3317
|
+
containerRef,
|
|
3318
|
+
enabled,
|
|
3319
|
+
currentCount,
|
|
3320
|
+
maxImages,
|
|
3321
|
+
addFile
|
|
3322
|
+
}) {
|
|
3323
|
+
const handlePaste = (0, import_react8.useCallback)((event) => {
|
|
3324
|
+
if (!enabled || currentCount >= maxImages) return;
|
|
3325
|
+
const items = event.clipboardData?.items;
|
|
3326
|
+
if (!items) return;
|
|
3327
|
+
const imageFiles = [];
|
|
3328
|
+
for (let i = 0; i < items.length; i++) {
|
|
3329
|
+
const item = items[i];
|
|
3330
|
+
if (item.type.startsWith("image/")) {
|
|
3331
|
+
const file = item.getAsFile();
|
|
3332
|
+
if (file) imageFiles.push(file);
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
if (imageFiles.length === 0) return;
|
|
3336
|
+
event.preventDefault();
|
|
3337
|
+
const remaining = maxImages - currentCount;
|
|
3338
|
+
for (const file of imageFiles.slice(0, remaining)) {
|
|
3339
|
+
addFile(file);
|
|
3340
|
+
}
|
|
3341
|
+
}, [enabled, currentCount, maxImages, addFile]);
|
|
3342
|
+
(0, import_react8.useEffect)(() => {
|
|
3343
|
+
const container = containerRef.current;
|
|
3344
|
+
if (!container || !enabled) return;
|
|
3345
|
+
container.addEventListener("paste", handlePaste);
|
|
3346
|
+
return () => container.removeEventListener("paste", handlePaste);
|
|
3347
|
+
}, [containerRef, enabled, handlePaste]);
|
|
3348
|
+
}
|
|
3349
|
+
|
|
2931
3350
|
// src/widget/screens/ReportScreen.tsx
|
|
2932
3351
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2933
|
-
function ReportScreen({ nav, prefill }) {
|
|
3352
|
+
function ReportScreen({ nav, prefill, autoCapture, onAutoCaptureConsumed }) {
|
|
2934
3353
|
const { client, refreshAssignments, uploadImage } = useBugBear();
|
|
2935
3354
|
const images = useImageAttachments(uploadImage, 5, "screenshots");
|
|
2936
|
-
const
|
|
2937
|
-
const
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
3355
|
+
const formRef = (0, import_react9.useRef)(null);
|
|
3356
|
+
const hasConsumedCapture = (0, import_react9.useRef)(false);
|
|
3357
|
+
(0, import_react9.useEffect)(() => {
|
|
3358
|
+
if (autoCapture && !hasConsumedCapture.current) {
|
|
3359
|
+
hasConsumedCapture.current = true;
|
|
3360
|
+
images.addFile(autoCapture);
|
|
3361
|
+
onAutoCaptureConsumed?.();
|
|
3362
|
+
}
|
|
3363
|
+
}, [autoCapture, onAutoCaptureConsumed]);
|
|
3364
|
+
useClipboardPaste({
|
|
3365
|
+
containerRef: formRef,
|
|
3366
|
+
enabled: true,
|
|
3367
|
+
currentCount: images.images.length,
|
|
3368
|
+
maxImages: 5,
|
|
3369
|
+
addFile: images.addFile
|
|
3370
|
+
});
|
|
3371
|
+
const [reportType, setReportType] = (0, import_react9.useState)(prefill?.type || "bug");
|
|
3372
|
+
const [severity, setSeverity] = (0, import_react9.useState)("medium");
|
|
3373
|
+
const [category, setCategory] = (0, import_react9.useState)(null);
|
|
3374
|
+
const [description, setDescription] = (0, import_react9.useState)("");
|
|
3375
|
+
const [affectedRoute, setAffectedRoute] = (0, import_react9.useState)("");
|
|
3376
|
+
const [submitting, setSubmitting] = (0, import_react9.useState)(false);
|
|
3377
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
3378
|
+
const submittingRef = (0, import_react9.useRef)(false);
|
|
3379
|
+
import_react9.default.useEffect(() => {
|
|
2945
3380
|
if (reportType === "feedback" || reportType === "suggestion") {
|
|
2946
3381
|
setCategory("other");
|
|
2947
3382
|
} else {
|
|
2948
3383
|
setCategory(null);
|
|
2949
3384
|
}
|
|
2950
3385
|
}, [reportType]);
|
|
2951
|
-
const observedRoute = (0,
|
|
3386
|
+
const observedRoute = (0, import_react9.useRef)(
|
|
2952
3387
|
typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
2953
3388
|
);
|
|
2954
3389
|
const isRetestFailure = prefill?.type === "test_fail";
|
|
@@ -3004,7 +3439,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
3004
3439
|
{ sev: "medium", color: "#eab308" },
|
|
3005
3440
|
{ sev: "low", color: "#6b7280" }
|
|
3006
3441
|
];
|
|
3007
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { children: isRetestFailure ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: formRef, tabIndex: -1, style: { outline: "none" }, children: isRetestFailure ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3008
3443
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles2.retestBanner, children: [
|
|
3009
3444
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontSize: 16 }, children: "\u{1F504}" }),
|
|
3010
3445
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
@@ -3332,10 +3767,10 @@ var styles2 = {
|
|
|
3332
3767
|
};
|
|
3333
3768
|
|
|
3334
3769
|
// src/widget/screens/ReportSuccessScreen.tsx
|
|
3335
|
-
var
|
|
3770
|
+
var import_react10 = require("react");
|
|
3336
3771
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
3337
3772
|
function ReportSuccessScreen({ nav }) {
|
|
3338
|
-
(0,
|
|
3773
|
+
(0, import_react10.useEffect)(() => {
|
|
3339
3774
|
const timer = setTimeout(() => nav.reset(), 2e3);
|
|
3340
3775
|
return () => clearTimeout(timer);
|
|
3341
3776
|
}, [nav]);
|
|
@@ -3373,7 +3808,7 @@ var styles3 = {
|
|
|
3373
3808
|
// src/widget/screens/MessageListScreen.tsx
|
|
3374
3809
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3375
3810
|
function MessageListScreen({ nav }) {
|
|
3376
|
-
const { threads, unreadCount, refreshThreads, isLoading } = useBugBear();
|
|
3811
|
+
const { threads, unreadCount, refreshThreads, dashboardUrl, isLoading } = useBugBear();
|
|
3377
3812
|
if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageListScreenSkeleton, {});
|
|
3378
3813
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
3379
3814
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
@@ -3562,6 +3997,26 @@ function MessageListScreen({ nav }) {
|
|
|
3562
3997
|
},
|
|
3563
3998
|
thread.id
|
|
3564
3999
|
)) }),
|
|
4000
|
+
dashboardUrl && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
4001
|
+
"a",
|
|
4002
|
+
{
|
|
4003
|
+
href: `${dashboardUrl}/discussions`,
|
|
4004
|
+
target: "_blank",
|
|
4005
|
+
rel: "noopener noreferrer",
|
|
4006
|
+
style: {
|
|
4007
|
+
display: "flex",
|
|
4008
|
+
alignItems: "center",
|
|
4009
|
+
justifyContent: "center",
|
|
4010
|
+
gap: 6,
|
|
4011
|
+
paddingTop: 12,
|
|
4012
|
+
fontSize: 13,
|
|
4013
|
+
fontWeight: 500,
|
|
4014
|
+
color: colors.blue,
|
|
4015
|
+
textDecoration: "none"
|
|
4016
|
+
},
|
|
4017
|
+
children: "\u{1F310} View on Dashboard \u2192"
|
|
4018
|
+
}
|
|
4019
|
+
),
|
|
3565
4020
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
3566
4021
|
"div",
|
|
3567
4022
|
{
|
|
@@ -3569,7 +4024,7 @@ function MessageListScreen({ nav }) {
|
|
|
3569
4024
|
display: "flex",
|
|
3570
4025
|
justifyContent: "space-between",
|
|
3571
4026
|
alignItems: "center",
|
|
3572
|
-
paddingTop:
|
|
4027
|
+
paddingTop: 8,
|
|
3573
4028
|
paddingLeft: 4,
|
|
3574
4029
|
paddingRight: 4
|
|
3575
4030
|
},
|
|
@@ -3605,7 +4060,7 @@ function MessageListScreen({ nav }) {
|
|
|
3605
4060
|
}
|
|
3606
4061
|
|
|
3607
4062
|
// src/widget/screens/ThreadDetailScreen.tsx
|
|
3608
|
-
var
|
|
4063
|
+
var import_react11 = require("react");
|
|
3609
4064
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
3610
4065
|
var inputStyle = {
|
|
3611
4066
|
backgroundColor: "#27272a",
|
|
@@ -3622,12 +4077,12 @@ function ThreadDetailScreen({
|
|
|
3622
4077
|
}) {
|
|
3623
4078
|
const { getThreadMessages, sendMessage, markAsRead, uploadImage } = useBugBear();
|
|
3624
4079
|
const replyImages = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
3625
|
-
const [messages, setMessages] = (0,
|
|
3626
|
-
const [loading, setLoading] = (0,
|
|
3627
|
-
const [replyText, setReplyText] = (0,
|
|
3628
|
-
const [sending, setSending] = (0,
|
|
3629
|
-
const [sendError, setSendError] = (0,
|
|
3630
|
-
(0,
|
|
4080
|
+
const [messages, setMessages] = (0, import_react11.useState)([]);
|
|
4081
|
+
const [loading, setLoading] = (0, import_react11.useState)(true);
|
|
4082
|
+
const [replyText, setReplyText] = (0, import_react11.useState)("");
|
|
4083
|
+
const [sending, setSending] = (0, import_react11.useState)(false);
|
|
4084
|
+
const [sendError, setSendError] = (0, import_react11.useState)(false);
|
|
4085
|
+
(0, import_react11.useEffect)(() => {
|
|
3631
4086
|
let cancelled = false;
|
|
3632
4087
|
setLoading(true);
|
|
3633
4088
|
(async () => {
|
|
@@ -3894,7 +4349,7 @@ function ThreadDetailScreen({
|
|
|
3894
4349
|
}
|
|
3895
4350
|
|
|
3896
4351
|
// src/widget/screens/ComposeMessageScreen.tsx
|
|
3897
|
-
var
|
|
4352
|
+
var import_react12 = require("react");
|
|
3898
4353
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3899
4354
|
var inputStyle2 = {
|
|
3900
4355
|
backgroundColor: "#27272a",
|
|
@@ -3908,9 +4363,9 @@ var inputStyle2 = {
|
|
|
3908
4363
|
function ComposeMessageScreen({ nav }) {
|
|
3909
4364
|
const { createThread, uploadImage } = useBugBear();
|
|
3910
4365
|
const images = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
3911
|
-
const [subject, setSubject] = (0,
|
|
3912
|
-
const [message, setMessage] = (0,
|
|
3913
|
-
const [sending, setSending] = (0,
|
|
4366
|
+
const [subject, setSubject] = (0, import_react12.useState)("");
|
|
4367
|
+
const [message, setMessage] = (0, import_react12.useState)("");
|
|
4368
|
+
const [sending, setSending] = (0, import_react12.useState)(false);
|
|
3914
4369
|
const canSend = subject.trim().length > 0 && message.trim().length > 0 && !sending && !images.isUploading;
|
|
3915
4370
|
const handleSend = async () => {
|
|
3916
4371
|
if (!canSend) return;
|
|
@@ -4052,20 +4507,20 @@ function ComposeMessageScreen({ nav }) {
|
|
|
4052
4507
|
}
|
|
4053
4508
|
|
|
4054
4509
|
// src/widget/screens/ProfileScreen.tsx
|
|
4055
|
-
var
|
|
4510
|
+
var import_react13 = require("react");
|
|
4056
4511
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
4057
4512
|
function ProfileScreen({ nav }) {
|
|
4058
4513
|
const { testerInfo, assignments, updateTesterProfile, refreshTesterInfo } = useBugBear();
|
|
4059
|
-
const [editing, setEditing] = (0,
|
|
4060
|
-
const [name, setName] = (0,
|
|
4061
|
-
const [additionalEmails, setAdditionalEmails] = (0,
|
|
4062
|
-
const [newEmailInput, setNewEmailInput] = (0,
|
|
4063
|
-
const [platforms, setPlatforms] = (0,
|
|
4064
|
-
const [saving, setSaving] = (0,
|
|
4065
|
-
const [saved, setSaved] = (0,
|
|
4066
|
-
const [showDetails, setShowDetails] = (0,
|
|
4514
|
+
const [editing, setEditing] = (0, import_react13.useState)(false);
|
|
4515
|
+
const [name, setName] = (0, import_react13.useState)(testerInfo?.name || "");
|
|
4516
|
+
const [additionalEmails, setAdditionalEmails] = (0, import_react13.useState)(testerInfo?.additionalEmails || []);
|
|
4517
|
+
const [newEmailInput, setNewEmailInput] = (0, import_react13.useState)("");
|
|
4518
|
+
const [platforms, setPlatforms] = (0, import_react13.useState)(testerInfo?.platforms || []);
|
|
4519
|
+
const [saving, setSaving] = (0, import_react13.useState)(false);
|
|
4520
|
+
const [saved, setSaved] = (0, import_react13.useState)(false);
|
|
4521
|
+
const [showDetails, setShowDetails] = (0, import_react13.useState)(false);
|
|
4067
4522
|
const completedCount = assignments.filter((a) => a.status === "passed" || a.status === "failed").length;
|
|
4068
|
-
(0,
|
|
4523
|
+
(0, import_react13.useEffect)(() => {
|
|
4069
4524
|
if (testerInfo) {
|
|
4070
4525
|
setName(testerInfo.name);
|
|
4071
4526
|
setAdditionalEmails(testerInfo.additionalEmails || []);
|
|
@@ -4529,7 +4984,7 @@ var styles4 = {
|
|
|
4529
4984
|
};
|
|
4530
4985
|
|
|
4531
4986
|
// src/widget/screens/IssueListScreen.tsx
|
|
4532
|
-
var
|
|
4987
|
+
var import_react14 = require("react");
|
|
4533
4988
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
4534
4989
|
var CATEGORY_CONFIG = {
|
|
4535
4990
|
open: { label: "Open Issues", accent: "#f97316", emptyIcon: "\u2705", emptyText: "No open issues" },
|
|
@@ -4544,10 +4999,10 @@ var SEVERITY_COLORS = {
|
|
|
4544
4999
|
};
|
|
4545
5000
|
function IssueListScreen({ nav, category }) {
|
|
4546
5001
|
const { client } = useBugBear();
|
|
4547
|
-
const [issues, setIssues] = (0,
|
|
4548
|
-
const [loading, setLoading] = (0,
|
|
5002
|
+
const [issues, setIssues] = (0, import_react14.useState)([]);
|
|
5003
|
+
const [loading, setLoading] = (0, import_react14.useState)(true);
|
|
4549
5004
|
const config = CATEGORY_CONFIG[category];
|
|
4550
|
-
(0,
|
|
5005
|
+
(0, import_react14.useEffect)(() => {
|
|
4551
5006
|
let cancelled = false;
|
|
4552
5007
|
setLoading(true);
|
|
4553
5008
|
(async () => {
|
|
@@ -4693,6 +5148,7 @@ var SEVERITY_CONFIG = {
|
|
|
4693
5148
|
low: { label: "Low", color: "#71717a", bg: "#27272a" }
|
|
4694
5149
|
};
|
|
4695
5150
|
function IssueDetailScreen({ nav, issue }) {
|
|
5151
|
+
const { dashboardUrl } = useBugBear();
|
|
4696
5152
|
const statusConfig = STATUS_LABELS[issue.status] || { label: issue.status, bg: "#27272a", color: "#a1a1aa" };
|
|
4697
5153
|
const severityConfig = issue.severity ? SEVERITY_CONFIG[issue.severity] : null;
|
|
4698
5154
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
@@ -4810,7 +5266,29 @@ function IssueDetailScreen({ nav, issue }) {
|
|
|
4810
5266
|
" \xB7 Updated ",
|
|
4811
5267
|
formatRelativeTime(issue.updatedAt)
|
|
4812
5268
|
] })
|
|
4813
|
-
] })
|
|
5269
|
+
] }),
|
|
5270
|
+
dashboardUrl && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5271
|
+
"a",
|
|
5272
|
+
{
|
|
5273
|
+
href: `${dashboardUrl}/reports`,
|
|
5274
|
+
target: "_blank",
|
|
5275
|
+
rel: "noopener noreferrer",
|
|
5276
|
+
style: {
|
|
5277
|
+
display: "flex",
|
|
5278
|
+
alignItems: "center",
|
|
5279
|
+
justifyContent: "center",
|
|
5280
|
+
gap: 6,
|
|
5281
|
+
marginTop: 12,
|
|
5282
|
+
padding: "10px 0",
|
|
5283
|
+
fontSize: 13,
|
|
5284
|
+
fontWeight: 500,
|
|
5285
|
+
color: colors.blue,
|
|
5286
|
+
textDecoration: "none",
|
|
5287
|
+
borderTop: `1px solid ${colors.border}`
|
|
5288
|
+
},
|
|
5289
|
+
children: "\u{1F310} View on Dashboard \u2192"
|
|
5290
|
+
}
|
|
5291
|
+
)
|
|
4814
5292
|
] });
|
|
4815
5293
|
}
|
|
4816
5294
|
|
|
@@ -4865,12 +5343,13 @@ function BugBearPanel({
|
|
|
4865
5343
|
}) {
|
|
4866
5344
|
const { shouldShowWidget, testerInfo, assignments, isLoading, unreadCount } = useBugBear();
|
|
4867
5345
|
const { currentScreen, canGoBack, push, pop, replace, reset } = useNavigation();
|
|
4868
|
-
const [collapsed, setCollapsed] = (0,
|
|
4869
|
-
const
|
|
4870
|
-
const [
|
|
4871
|
-
const
|
|
4872
|
-
const
|
|
4873
|
-
(0,
|
|
5346
|
+
const [collapsed, setCollapsed] = (0, import_react15.useState)(defaultCollapsed);
|
|
5347
|
+
const autoCaptureRef = (0, import_react15.useRef)(null);
|
|
5348
|
+
const [panelPosition, setPanelPosition] = (0, import_react15.useState)(null);
|
|
5349
|
+
const [isDragging, setIsDragging] = (0, import_react15.useState)(false);
|
|
5350
|
+
const dragStartRef = (0, import_react15.useRef)(null);
|
|
5351
|
+
const panelRef = (0, import_react15.useRef)(null);
|
|
5352
|
+
(0, import_react15.useEffect)(() => {
|
|
4874
5353
|
if (typeof window === "undefined") return;
|
|
4875
5354
|
try {
|
|
4876
5355
|
const saved = localStorage.getItem(STORAGE_KEY);
|
|
@@ -4884,7 +5363,7 @@ function BugBearPanel({
|
|
|
4884
5363
|
setPanelPosition(getDefaultPosition(position));
|
|
4885
5364
|
}
|
|
4886
5365
|
}, [position]);
|
|
4887
|
-
(0,
|
|
5366
|
+
(0, import_react15.useEffect)(() => {
|
|
4888
5367
|
if (panelPosition && typeof window !== "undefined") {
|
|
4889
5368
|
try {
|
|
4890
5369
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(panelPosition));
|
|
@@ -4892,7 +5371,7 @@ function BugBearPanel({
|
|
|
4892
5371
|
}
|
|
4893
5372
|
}
|
|
4894
5373
|
}, [panelPosition]);
|
|
4895
|
-
(0,
|
|
5374
|
+
(0, import_react15.useEffect)(() => {
|
|
4896
5375
|
if (typeof window === "undefined") return;
|
|
4897
5376
|
const handleResize = () => {
|
|
4898
5377
|
setPanelPosition((prev) => prev ? clampPosition(prev) : getDefaultPosition(position));
|
|
@@ -4900,7 +5379,7 @@ function BugBearPanel({
|
|
|
4900
5379
|
window.addEventListener("resize", handleResize);
|
|
4901
5380
|
return () => window.removeEventListener("resize", handleResize);
|
|
4902
5381
|
}, [position]);
|
|
4903
|
-
const handleMouseDown = (0,
|
|
5382
|
+
const handleMouseDown = (0, import_react15.useCallback)((e) => {
|
|
4904
5383
|
if (!draggable || !panelPosition) return;
|
|
4905
5384
|
const target = e.target;
|
|
4906
5385
|
if (!target.closest("[data-drag-handle]")) return;
|
|
@@ -4913,7 +5392,7 @@ function BugBearPanel({
|
|
|
4913
5392
|
panelY: panelPosition.y
|
|
4914
5393
|
};
|
|
4915
5394
|
}, [draggable, panelPosition]);
|
|
4916
|
-
(0,
|
|
5395
|
+
(0, import_react15.useEffect)(() => {
|
|
4917
5396
|
if (!isDragging) return;
|
|
4918
5397
|
const handleMouseMove = (e) => {
|
|
4919
5398
|
if (!dragStartRef.current) return;
|
|
@@ -4935,7 +5414,7 @@ function BugBearPanel({
|
|
|
4935
5414
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
4936
5415
|
};
|
|
4937
5416
|
}, [isDragging]);
|
|
4938
|
-
const handleDoubleClick = (0,
|
|
5417
|
+
const handleDoubleClick = (0, import_react15.useCallback)(() => {
|
|
4939
5418
|
if (!draggable) return;
|
|
4940
5419
|
setPanelPosition(getDefaultPosition(position));
|
|
4941
5420
|
try {
|
|
@@ -4943,6 +5422,14 @@ function BugBearPanel({
|
|
|
4943
5422
|
} catch {
|
|
4944
5423
|
}
|
|
4945
5424
|
}, [draggable, position]);
|
|
5425
|
+
const handleReportBug = (0, import_react15.useCallback)(async () => {
|
|
5426
|
+
const file = await capturePageScreenshot({
|
|
5427
|
+
excludeElement: panelRef.current,
|
|
5428
|
+
timeout: 3e3
|
|
5429
|
+
});
|
|
5430
|
+
autoCaptureRef.current = file;
|
|
5431
|
+
push({ name: "REPORT", prefill: { type: "bug" } });
|
|
5432
|
+
}, [push]);
|
|
4946
5433
|
if (isLoading || !shouldShowWidget) return null;
|
|
4947
5434
|
if (!panelPosition) return null;
|
|
4948
5435
|
const pendingCount = assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length;
|
|
@@ -4979,13 +5466,12 @@ function BugBearPanel({
|
|
|
4979
5466
|
};
|
|
4980
5467
|
const handleClose = () => {
|
|
4981
5468
|
setCollapsed(true);
|
|
4982
|
-
reset();
|
|
4983
5469
|
};
|
|
4984
5470
|
const nav = { push, pop, replace, reset, canGoBack };
|
|
4985
5471
|
const renderScreen = () => {
|
|
4986
5472
|
switch (currentScreen.name) {
|
|
4987
5473
|
case "HOME":
|
|
4988
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HomeScreen, { nav });
|
|
5474
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HomeScreen, { nav, onReportBug: handleReportBug });
|
|
4989
5475
|
case "TEST_DETAIL":
|
|
4990
5476
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TestDetailScreen, { testId: currentScreen.testId, nav });
|
|
4991
5477
|
case "TEST_LIST":
|
|
@@ -4993,7 +5479,17 @@ function BugBearPanel({
|
|
|
4993
5479
|
case "TEST_FEEDBACK":
|
|
4994
5480
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TestFeedbackScreen, { status: currentScreen.status, assignmentId: currentScreen.assignmentId, nav });
|
|
4995
5481
|
case "REPORT":
|
|
4996
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5482
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5483
|
+
ReportScreen,
|
|
5484
|
+
{
|
|
5485
|
+
nav,
|
|
5486
|
+
prefill: currentScreen.prefill,
|
|
5487
|
+
autoCapture: autoCaptureRef.current,
|
|
5488
|
+
onAutoCaptureConsumed: () => {
|
|
5489
|
+
autoCaptureRef.current = null;
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
);
|
|
4997
5493
|
case "REPORT_SUCCESS":
|
|
4998
5494
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportSuccessScreen, { nav });
|
|
4999
5495
|
case "MESSAGE_LIST":
|
|
@@ -5190,10 +5686,10 @@ function BugBearPanel({
|
|
|
5190
5686
|
}
|
|
5191
5687
|
|
|
5192
5688
|
// src/BugBearErrorBoundary.tsx
|
|
5193
|
-
var
|
|
5689
|
+
var import_react16 = require("react");
|
|
5194
5690
|
var import_core2 = require("@bbearai/core");
|
|
5195
5691
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
5196
|
-
var BugBearErrorBoundary = class extends
|
|
5692
|
+
var BugBearErrorBoundary = class extends import_react16.Component {
|
|
5197
5693
|
constructor(props) {
|
|
5198
5694
|
super(props);
|
|
5199
5695
|
this.reset = () => {
|