@jarve/bug-reporter 0.2.0 → 0.3.1
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 +8 -7
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +226 -149
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +209 -132
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -20,9 +20,10 @@ var __spreadValues = (a, b) => {
|
|
|
20
20
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
21
|
|
|
22
22
|
// src/bug-reporter.tsx
|
|
23
|
-
import { useState as
|
|
23
|
+
import { useState as useState4, useEffect as useEffect3, useCallback as useCallback3 } from "react";
|
|
24
24
|
|
|
25
25
|
// src/floating-button.tsx
|
|
26
|
+
import { useState } from "react";
|
|
26
27
|
import { Bug } from "lucide-react";
|
|
27
28
|
|
|
28
29
|
// src/cn.ts
|
|
@@ -33,27 +34,64 @@ function cn(...inputs) {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
// src/floating-button.tsx
|
|
36
|
-
import { jsx } from "react/jsx-runtime";
|
|
37
|
-
function FloatingButton({ isActive, onClick }) {
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
38
|
+
function FloatingButton({ isActive, onClick, position = "right" }) {
|
|
39
|
+
const [hovered, setHovered] = useState(false);
|
|
40
|
+
const isLeft = position === "left";
|
|
41
|
+
const sideClasses = isLeft ? "left-4 md:left-6" : "right-4 md:right-6";
|
|
42
|
+
return /* @__PURE__ */ jsxs(
|
|
43
|
+
"div",
|
|
40
44
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
className: cn("fixed z-[9999]", "bottom-4 md:bottom-6", sideClasses),
|
|
46
|
+
onMouseEnter: () => setHovered(true),
|
|
47
|
+
onMouseLeave: () => setHovered(false),
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsxs(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
className: cn(
|
|
53
|
+
"pointer-events-none absolute bottom-full mb-2 w-max max-w-[200px] rounded-lg bg-gray-900 px-3 py-2 text-xs leading-relaxed text-white shadow-lg transition-all duration-200",
|
|
54
|
+
isLeft ? "left-0" : "right-0",
|
|
55
|
+
hovered && !isActive ? "translate-y-0 opacity-100" : "translate-y-1 opacity-0"
|
|
56
|
+
),
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold", children: "Report a bug" }),
|
|
59
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
60
|
+
"Click to screenshot an issue and chat with AI to submit a bug report.",
|
|
61
|
+
/* @__PURE__ */ jsx(
|
|
62
|
+
"div",
|
|
63
|
+
{
|
|
64
|
+
className: cn(
|
|
65
|
+
"absolute top-full h-0 w-0 border-x-[6px] border-t-[6px] border-x-transparent border-t-gray-900",
|
|
66
|
+
isLeft ? "left-4" : "right-4"
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
"button",
|
|
75
|
+
{
|
|
76
|
+
onClick,
|
|
77
|
+
className: cn(
|
|
78
|
+
"flex items-center justify-center rounded-full shadow-lg transition-all duration-200",
|
|
79
|
+
"hover:scale-110 focus:ring-2 focus:ring-offset-2 focus:outline-none",
|
|
80
|
+
"h-11 w-11 md:h-12 md:w-12",
|
|
81
|
+
isActive ? "animate-pulse bg-red-500 text-white focus:ring-red-400" : "bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-400"
|
|
82
|
+
),
|
|
83
|
+
title: isActive ? "Cancel bug capture" : "Report a bug",
|
|
84
|
+
"aria-label": isActive ? "Cancel bug capture" : "Report a bug",
|
|
85
|
+
children: /* @__PURE__ */ jsx(Bug, { className: "h-4 w-4 md:h-5 md:w-5" })
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
]
|
|
51
89
|
}
|
|
52
90
|
);
|
|
53
91
|
}
|
|
54
92
|
|
|
55
93
|
// src/capture-overlay.tsx
|
|
56
|
-
import { useEffect, useState, useCallback, useRef } from "react";
|
|
94
|
+
import { useEffect, useState as useState2, useCallback, useRef } from "react";
|
|
57
95
|
import { toPng } from "html-to-image";
|
|
58
96
|
|
|
59
97
|
// src/utils.ts
|
|
@@ -173,8 +211,7 @@ var errorListener = null;
|
|
|
173
211
|
var rejectionListener = null;
|
|
174
212
|
function startCapturing() {
|
|
175
213
|
if (isCapturing) return;
|
|
176
|
-
if (console.error.__bugReporterPatched)
|
|
177
|
-
return;
|
|
214
|
+
if (console.error.__bugReporterPatched) return;
|
|
178
215
|
isCapturing = true;
|
|
179
216
|
capturedErrors = [];
|
|
180
217
|
originalConsoleError = console.error;
|
|
@@ -365,7 +402,7 @@ function clearCapturedNetworkErrors() {
|
|
|
365
402
|
}
|
|
366
403
|
|
|
367
404
|
// src/capture-overlay.tsx
|
|
368
|
-
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
405
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
369
406
|
function dataUrlToBlob(dataUrl) {
|
|
370
407
|
var _a;
|
|
371
408
|
const [header, base64] = dataUrl.split(",");
|
|
@@ -383,13 +420,13 @@ function CaptureOverlay({
|
|
|
383
420
|
onCapture,
|
|
384
421
|
onCancel
|
|
385
422
|
}) {
|
|
386
|
-
const [hoveredElement, setHoveredElement] =
|
|
387
|
-
const [hoveredRect, setHoveredRect] =
|
|
388
|
-
const [isCapturing3, setIsCapturing] =
|
|
389
|
-
const [isTouchMode, setIsTouchMode] =
|
|
390
|
-
const [selectedSection, setSelectedSection] =
|
|
391
|
-
const [selectedRect, setSelectedRect] =
|
|
392
|
-
const [selectedTarget, setSelectedTarget] =
|
|
423
|
+
const [hoveredElement, setHoveredElement] = useState2(null);
|
|
424
|
+
const [hoveredRect, setHoveredRect] = useState2(null);
|
|
425
|
+
const [isCapturing3, setIsCapturing] = useState2(false);
|
|
426
|
+
const [isTouchMode, setIsTouchMode] = useState2(false);
|
|
427
|
+
const [selectedSection, setSelectedSection] = useState2(null);
|
|
428
|
+
const [selectedRect, setSelectedRect] = useState2(null);
|
|
429
|
+
const [selectedTarget, setSelectedTarget] = useState2(null);
|
|
393
430
|
const overlayRef = useRef(null);
|
|
394
431
|
const hoveredElementRef = useRef(null);
|
|
395
432
|
const rafRef = useRef(null);
|
|
@@ -420,12 +457,21 @@ function CaptureOverlay({
|
|
|
420
457
|
skipFonts: true
|
|
421
458
|
});
|
|
422
459
|
const blob = dataUrlToBlob(dataUrl);
|
|
423
|
-
const metadata = collectMetadata(
|
|
460
|
+
const metadata = collectMetadata(
|
|
461
|
+
section,
|
|
462
|
+
siteId,
|
|
463
|
+
reporterName,
|
|
464
|
+
reporterEmail,
|
|
465
|
+
elementInfo
|
|
466
|
+
);
|
|
424
467
|
const consoleErrors = getCapturedErrors();
|
|
425
468
|
const networkErrors = getCapturedNetworkErrors();
|
|
426
469
|
onCapture({ screenshot: blob, metadata, consoleErrors, networkErrors });
|
|
427
470
|
} catch (err) {
|
|
428
|
-
console.warn(
|
|
471
|
+
console.warn(
|
|
472
|
+
"Bug reporter: first capture attempt failed, retrying with simpler settings",
|
|
473
|
+
err
|
|
474
|
+
);
|
|
429
475
|
try {
|
|
430
476
|
const dataUrl = await toPng(section, {
|
|
431
477
|
quality: 0.6,
|
|
@@ -434,13 +480,25 @@ function CaptureOverlay({
|
|
|
434
480
|
cacheBust: true
|
|
435
481
|
});
|
|
436
482
|
const retryBlob = dataUrlToBlob(dataUrl);
|
|
437
|
-
const metadata = collectMetadata(
|
|
483
|
+
const metadata = collectMetadata(
|
|
484
|
+
section,
|
|
485
|
+
siteId,
|
|
486
|
+
reporterName,
|
|
487
|
+
reporterEmail,
|
|
488
|
+
elementInfo
|
|
489
|
+
);
|
|
438
490
|
const consoleErrors = getCapturedErrors();
|
|
439
491
|
const networkErrors = getCapturedNetworkErrors();
|
|
440
492
|
onCapture({ screenshot: retryBlob, metadata, consoleErrors, networkErrors });
|
|
441
493
|
} catch (e) {
|
|
442
494
|
console.error("Bug reporter: screenshot capture failed after retry");
|
|
443
|
-
const metadata = collectMetadata(
|
|
495
|
+
const metadata = collectMetadata(
|
|
496
|
+
section,
|
|
497
|
+
siteId,
|
|
498
|
+
reporterName,
|
|
499
|
+
reporterEmail,
|
|
500
|
+
elementInfo
|
|
501
|
+
);
|
|
444
502
|
const consoleErrors = getCapturedErrors();
|
|
445
503
|
const networkErrors = getCapturedNetworkErrors();
|
|
446
504
|
onCapture({
|
|
@@ -571,31 +629,41 @@ function CaptureOverlay({
|
|
|
571
629
|
document.removeEventListener("click", handleClick, true);
|
|
572
630
|
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
573
631
|
};
|
|
574
|
-
}, [
|
|
632
|
+
}, [
|
|
633
|
+
isActive,
|
|
634
|
+
isTouchMode,
|
|
635
|
+
handleMouseMove,
|
|
636
|
+
handleClick,
|
|
637
|
+
handleTouchEnd,
|
|
638
|
+
handlePointerDown,
|
|
639
|
+
handleKeyDown,
|
|
640
|
+
handleScroll
|
|
641
|
+
]);
|
|
575
642
|
const highlightRect = isTouchMode ? selectedRect : hoveredRect;
|
|
576
643
|
const showHighlight = isTouchMode ? !!selectedSection : !!hoveredElement && !!hoveredRect;
|
|
577
644
|
if (!isActive) return null;
|
|
578
|
-
return /* @__PURE__ */
|
|
645
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
579
646
|
/* @__PURE__ */ jsx2(
|
|
580
647
|
"div",
|
|
581
648
|
{
|
|
582
649
|
"data-bug-reporter": true,
|
|
583
650
|
role: "alert",
|
|
584
651
|
"aria-live": "assertive",
|
|
585
|
-
className: "fixed top-0
|
|
586
|
-
children: isTouchMode ? /* @__PURE__ */
|
|
652
|
+
className: "fixed top-0 right-0 left-0 z-[10000] flex items-center justify-center gap-3 bg-indigo-600 px-4 py-2 text-center text-sm font-medium text-white",
|
|
653
|
+
children: isTouchMode ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
587
654
|
/* @__PURE__ */ jsx2("span", { children: "Tap the section with the bug" }),
|
|
588
655
|
/* @__PURE__ */ jsx2(
|
|
589
656
|
"button",
|
|
590
657
|
{
|
|
591
658
|
onClick: onCancel,
|
|
592
|
-
className: "
|
|
659
|
+
className: "min-h-[44px] rounded-md bg-white/20 px-3 py-1 text-sm font-medium",
|
|
593
660
|
children: "Cancel"
|
|
594
661
|
}
|
|
595
662
|
)
|
|
596
|
-
] }) : /* @__PURE__ */
|
|
597
|
-
"Click on the section with the bug. Press
|
|
598
|
-
|
|
663
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
664
|
+
"Click on the section with the bug. Press",
|
|
665
|
+
" ",
|
|
666
|
+
/* @__PURE__ */ jsx2("kbd", { className: "mx-1 rounded bg-indigo-800 px-1.5 py-0.5 text-xs", children: "Esc" }),
|
|
599
667
|
" to cancel."
|
|
600
668
|
] })
|
|
601
669
|
}
|
|
@@ -605,7 +673,7 @@ function CaptureOverlay({
|
|
|
605
673
|
{
|
|
606
674
|
ref: overlayRef,
|
|
607
675
|
"data-bug-reporter": true,
|
|
608
|
-
className: "
|
|
676
|
+
className: "pointer-events-none fixed z-[9998] rounded-sm border-2 border-indigo-500 transition-all duration-150 ease-out",
|
|
609
677
|
style: {
|
|
610
678
|
top: highlightRect.top - 2,
|
|
611
679
|
left: highlightRect.left - 2,
|
|
@@ -619,11 +687,11 @@ function CaptureOverlay({
|
|
|
619
687
|
"div",
|
|
620
688
|
{
|
|
621
689
|
"data-bug-reporter": true,
|
|
622
|
-
className: "fixed
|
|
690
|
+
className: "fixed right-0 bottom-0 left-0 z-[10000] border-t border-gray-200 bg-white shadow-lg",
|
|
623
691
|
style: { paddingBottom: "env(safe-area-inset-bottom, 0px)" },
|
|
624
|
-
children: /* @__PURE__ */
|
|
625
|
-
/* @__PURE__ */ jsx2("span", { className: "text-sm font-medium text-gray-900
|
|
626
|
-
/* @__PURE__ */
|
|
692
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-3 px-4 py-3", children: [
|
|
693
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate text-sm font-medium text-gray-900", children: "Capture this section?" }),
|
|
694
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 gap-2", children: [
|
|
627
695
|
/* @__PURE__ */ jsx2(
|
|
628
696
|
"button",
|
|
629
697
|
{
|
|
@@ -633,7 +701,7 @@ function CaptureOverlay({
|
|
|
633
701
|
setSelectedTarget(null);
|
|
634
702
|
touchCoordsRef.current = null;
|
|
635
703
|
},
|
|
636
|
-
className: "
|
|
704
|
+
className: "min-h-[44px] rounded-md border border-gray-300 px-4 text-sm font-medium text-gray-700",
|
|
637
705
|
children: "Cancel"
|
|
638
706
|
}
|
|
639
707
|
),
|
|
@@ -641,7 +709,7 @@ function CaptureOverlay({
|
|
|
641
709
|
"button",
|
|
642
710
|
{
|
|
643
711
|
onClick: handleConfirmCapture,
|
|
644
|
-
className: "
|
|
712
|
+
className: "min-h-[44px] rounded-md bg-indigo-600 px-4 text-sm font-medium text-white",
|
|
645
713
|
children: "Capture"
|
|
646
714
|
}
|
|
647
715
|
)
|
|
@@ -654,9 +722,9 @@ function CaptureOverlay({
|
|
|
654
722
|
}
|
|
655
723
|
|
|
656
724
|
// src/report-modal.tsx
|
|
657
|
-
import { useState as
|
|
725
|
+
import { useState as useState3, useRef as useRef2, useEffect as useEffect2, useCallback as useCallback2, useMemo } from "react";
|
|
658
726
|
import { X, Send, Loader2, CheckCircle2 } from "lucide-react";
|
|
659
|
-
import { Fragment as Fragment2, jsx as jsx3, jsxs as
|
|
727
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
660
728
|
function ReportModal({
|
|
661
729
|
isOpen,
|
|
662
730
|
captureResult,
|
|
@@ -665,13 +733,13 @@ function ReportModal({
|
|
|
665
733
|
user,
|
|
666
734
|
onClose
|
|
667
735
|
}) {
|
|
668
|
-
const [messages, setMessages] =
|
|
669
|
-
const [input, setInput] =
|
|
670
|
-
const [isLoading, setIsLoading] =
|
|
671
|
-
const [modalState, setModalState] =
|
|
672
|
-
const [reportId, setReportId] =
|
|
673
|
-
const [screenshotUrl, setScreenshotUrl] =
|
|
674
|
-
const [errorMessage, setErrorMessage] =
|
|
736
|
+
const [messages, setMessages] = useState3([]);
|
|
737
|
+
const [input, setInput] = useState3("");
|
|
738
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
739
|
+
const [modalState, setModalState] = useState3("chatting");
|
|
740
|
+
const [reportId, setReportId] = useState3(null);
|
|
741
|
+
const [screenshotUrl, setScreenshotUrl] = useState3(null);
|
|
742
|
+
const [errorMessage, setErrorMessage] = useState3(null);
|
|
675
743
|
const chatEndRef = useRef2(null);
|
|
676
744
|
const inputRef = useRef2(null);
|
|
677
745
|
const hasInitRef = useRef2(false);
|
|
@@ -715,7 +783,9 @@ function ReportModal({
|
|
|
715
783
|
})
|
|
716
784
|
});
|
|
717
785
|
if (response.status === 401) {
|
|
718
|
-
console.error(
|
|
786
|
+
console.error(
|
|
787
|
+
"Bug reporter: invalid or missing API key. Check your BugReporter apiKey prop."
|
|
788
|
+
);
|
|
719
789
|
setMessages([
|
|
720
790
|
{
|
|
721
791
|
role: "assistant",
|
|
@@ -812,9 +882,7 @@ function ReportModal({
|
|
|
812
882
|
setModalState("submitted");
|
|
813
883
|
} catch (err) {
|
|
814
884
|
console.error("Bug reporter: failed to submit report", err);
|
|
815
|
-
setErrorMessage(
|
|
816
|
-
err instanceof Error ? err.message : "Failed to submit report"
|
|
817
|
-
);
|
|
885
|
+
setErrorMessage(err instanceof Error ? err.message : "Failed to submit report");
|
|
818
886
|
setModalState("error");
|
|
819
887
|
}
|
|
820
888
|
},
|
|
@@ -827,10 +895,7 @@ function ReportModal({
|
|
|
827
895
|
if (!input.trim() || isLoading || !captureResult) return;
|
|
828
896
|
const userMessage = input.trim();
|
|
829
897
|
setInput("");
|
|
830
|
-
const newMessages = [
|
|
831
|
-
...messages,
|
|
832
|
-
{ role: "user", content: userMessage }
|
|
833
|
-
];
|
|
898
|
+
const newMessages = [...messages, { role: "user", content: userMessage }];
|
|
834
899
|
setMessages(newMessages);
|
|
835
900
|
setIsLoading(true);
|
|
836
901
|
try {
|
|
@@ -846,7 +911,9 @@ function ReportModal({
|
|
|
846
911
|
})
|
|
847
912
|
});
|
|
848
913
|
if (response.status === 401) {
|
|
849
|
-
console.error(
|
|
914
|
+
console.error(
|
|
915
|
+
"Bug reporter: invalid or missing API key. Check your BugReporter apiKey prop."
|
|
916
|
+
);
|
|
850
917
|
setMessages([
|
|
851
918
|
...newMessages,
|
|
852
919
|
{
|
|
@@ -858,10 +925,7 @@ function ReportModal({
|
|
|
858
925
|
}
|
|
859
926
|
if (!response.ok) throw new Error("Failed to get AI response");
|
|
860
927
|
const data = await response.json();
|
|
861
|
-
setMessages([
|
|
862
|
-
...newMessages,
|
|
863
|
-
{ role: "assistant", content: data.message }
|
|
864
|
-
]);
|
|
928
|
+
setMessages([...newMessages, { role: "assistant", content: data.message }]);
|
|
865
929
|
if (data.readyToSubmit && data.structuredReport) {
|
|
866
930
|
await submitReport(
|
|
867
931
|
[...newMessages, { role: "assistant", content: data.message }],
|
|
@@ -908,113 +972,125 @@ function ReportModal({
|
|
|
908
972
|
onClick: (e) => {
|
|
909
973
|
if (e.target === e.currentTarget) handleClose();
|
|
910
974
|
},
|
|
911
|
-
children: /* @__PURE__ */
|
|
975
|
+
children: /* @__PURE__ */ jsxs3(
|
|
912
976
|
"div",
|
|
913
977
|
{
|
|
914
978
|
className: cn(
|
|
915
|
-
"
|
|
916
|
-
"w-full max-w-lg
|
|
917
|
-
"max-[768px]:mx-0 max-[768px]:
|
|
979
|
+
"flex flex-col overflow-hidden rounded-xl border border-gray-200 bg-white shadow-2xl dark:border-gray-800 dark:bg-gray-950",
|
|
980
|
+
"mx-4 w-full max-w-lg",
|
|
981
|
+
"max-[768px]:mx-0 max-[768px]:h-full max-[768px]:max-w-none max-[768px]:rounded-none",
|
|
918
982
|
"min-[769px]:max-h-[85vh]"
|
|
919
983
|
),
|
|
920
984
|
children: [
|
|
921
|
-
/* @__PURE__ */
|
|
922
|
-
/* @__PURE__ */
|
|
923
|
-
/* @__PURE__ */ jsx3("h2", { className: "font-semibold text-
|
|
985
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between border-b border-gray-200 bg-gray-50/30 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/30", children: [
|
|
986
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
987
|
+
/* @__PURE__ */ jsx3("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Bug Report" }),
|
|
924
988
|
/* @__PURE__ */ jsx3("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: siteId })
|
|
925
989
|
] }),
|
|
926
990
|
/* @__PURE__ */ jsx3(
|
|
927
991
|
"button",
|
|
928
992
|
{
|
|
929
993
|
onClick: handleClose,
|
|
930
|
-
className: "p-1.5
|
|
994
|
+
className: "rounded-md p-1.5 transition-colors hover:bg-gray-100 dark:hover:bg-gray-800",
|
|
931
995
|
"aria-label": "Close",
|
|
932
996
|
children: /* @__PURE__ */ jsx3(X, { className: "h-4 w-4 text-gray-600 dark:text-gray-400" })
|
|
933
997
|
}
|
|
934
998
|
)
|
|
935
999
|
] }),
|
|
936
|
-
screenshotUrl && /* @__PURE__ */ jsx3("div", { className: "
|
|
1000
|
+
screenshotUrl && /* @__PURE__ */ jsx3("div", { className: "border-b border-gray-200 bg-gray-50/10 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/10", children: /* @__PURE__ */ jsx3(
|
|
937
1001
|
"img",
|
|
938
1002
|
{
|
|
939
1003
|
src: screenshotUrl,
|
|
940
1004
|
alt: "Captured section",
|
|
941
|
-
className: "
|
|
1005
|
+
className: "max-h-40 w-full rounded-md border border-gray-200 object-contain dark:border-gray-700"
|
|
942
1006
|
}
|
|
943
1007
|
) }),
|
|
944
|
-
/* @__PURE__ */ jsx3("div", { className: "flex-1 overflow-y-auto px-4 py-3
|
|
945
|
-
/* @__PURE__ */ jsx3(CheckCircle2, { className: "h-12 w-12 text-green-500
|
|
946
|
-
/* @__PURE__ */ jsx3("h3", { className: "font-semibold text-
|
|
947
|
-
/* @__PURE__ */
|
|
948
|
-
"Reference:
|
|
949
|
-
|
|
1008
|
+
/* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 space-y-3 overflow-y-auto px-4 py-3", children: modalState === "submitted" ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
1009
|
+
/* @__PURE__ */ jsx3(CheckCircle2, { className: "mb-3 h-12 w-12 text-green-500" }),
|
|
1010
|
+
/* @__PURE__ */ jsx3("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Report Submitted" }),
|
|
1011
|
+
/* @__PURE__ */ jsxs3("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: [
|
|
1012
|
+
"Reference:",
|
|
1013
|
+
" ",
|
|
1014
|
+
/* @__PURE__ */ jsx3("code", { className: "rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800", children: reportId == null ? void 0 : reportId.slice(0, 8) })
|
|
950
1015
|
] }),
|
|
951
|
-
/* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-500 dark:text-gray-400
|
|
1016
|
+
/* @__PURE__ */ jsx3("p", { className: "mt-2 text-sm text-gray-500 dark:text-gray-400", children: "Thanks for the report \u2014 we'll look into it." }),
|
|
952
1017
|
/* @__PURE__ */ jsx3(
|
|
953
1018
|
"button",
|
|
954
1019
|
{
|
|
955
1020
|
onClick: handleClose,
|
|
956
|
-
className: "mt-4 px-4 py-2
|
|
1021
|
+
className: "mt-4 rounded-md bg-indigo-600 px-4 py-2 text-sm text-white transition-colors hover:bg-indigo-700",
|
|
957
1022
|
children: "Done"
|
|
958
1023
|
}
|
|
959
1024
|
)
|
|
960
|
-
] }) : modalState === "error" ? /* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */ jsx3(X, { className: "h-12 w-12 text-red-500
|
|
962
|
-
/* @__PURE__ */ jsx3("h3", { className: "font-semibold text-
|
|
963
|
-
/* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-500 dark:text-gray-400
|
|
1025
|
+
] }) : modalState === "error" ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
1026
|
+
/* @__PURE__ */ jsx3(X, { className: "mb-3 h-12 w-12 text-red-500" }),
|
|
1027
|
+
/* @__PURE__ */ jsx3("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Submission Failed" }),
|
|
1028
|
+
/* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: errorMessage || "Something went wrong. Please try again." }),
|
|
964
1029
|
/* @__PURE__ */ jsx3(
|
|
965
1030
|
"button",
|
|
966
1031
|
{
|
|
967
1032
|
onClick: () => setModalState("chatting"),
|
|
968
|
-
className: "mt-4 px-4 py-2
|
|
1033
|
+
className: "mt-4 rounded-md bg-indigo-600 px-4 py-2 text-sm text-white transition-colors hover:bg-indigo-700",
|
|
969
1034
|
children: "Try Again"
|
|
970
1035
|
}
|
|
971
1036
|
)
|
|
972
|
-
] }) : modalState === "submitting" ? /* @__PURE__ */
|
|
973
|
-
/* @__PURE__ */ jsx3(Loader2, { className: "h-8 w-8 animate-spin text-indigo-500
|
|
1037
|
+
] }) : modalState === "submitting" ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-8", children: [
|
|
1038
|
+
/* @__PURE__ */ jsx3(Loader2, { className: "mb-3 h-8 w-8 animate-spin text-indigo-500" }),
|
|
974
1039
|
/* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Submitting your report..." })
|
|
975
|
-
] }) : /* @__PURE__ */
|
|
1040
|
+
] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
976
1041
|
(captureResult == null ? void 0 : captureResult.screenshot.size) === 0 && /* @__PURE__ */ jsx3("p", { className: "text-xs text-amber-600", children: "Screenshot could not be captured. Please describe the visual issue in detail." }),
|
|
977
1042
|
messages.map((msg, i) => /* @__PURE__ */ jsx3(
|
|
978
1043
|
"div",
|
|
979
1044
|
{
|
|
980
1045
|
className: cn(
|
|
981
1046
|
"text-sm leading-relaxed",
|
|
982
|
-
msg.role === "assistant" ? "
|
|
1047
|
+
msg.role === "assistant" ? "rounded-lg bg-gray-100/50 p-3 text-gray-900 dark:bg-gray-800/50 dark:text-gray-100" : "ml-8 rounded-lg bg-indigo-600 p-3 text-white"
|
|
983
1048
|
),
|
|
984
1049
|
children: msg.content
|
|
985
1050
|
},
|
|
986
1051
|
i
|
|
987
1052
|
)),
|
|
988
|
-
isLoading && /* @__PURE__ */
|
|
1053
|
+
isLoading && /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 rounded-lg bg-gray-100/50 p-3 dark:bg-gray-800/50", children: [
|
|
989
1054
|
/* @__PURE__ */ jsx3(Loader2, { className: "h-3.5 w-3.5 animate-spin text-gray-500" }),
|
|
990
1055
|
/* @__PURE__ */ jsx3("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Thinking..." })
|
|
991
1056
|
] }),
|
|
992
1057
|
/* @__PURE__ */ jsx3("div", { ref: chatEndRef })
|
|
993
1058
|
] }) }),
|
|
994
|
-
modalState === "chatting" && /* @__PURE__ */
|
|
995
|
-
/* @__PURE__ */
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
/* @__PURE__ */
|
|
1010
|
-
|
|
1059
|
+
modalState === "chatting" && /* @__PURE__ */ jsx3("div", { className: "border-t border-gray-200 px-4 py-3 dark:border-gray-800", children: /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-2", children: [
|
|
1060
|
+
/* @__PURE__ */ jsx3(
|
|
1061
|
+
"textarea",
|
|
1062
|
+
{
|
|
1063
|
+
ref: inputRef,
|
|
1064
|
+
value: input,
|
|
1065
|
+
onChange: (e) => setInput(e.target.value),
|
|
1066
|
+
onKeyDown: handleKeyDown,
|
|
1067
|
+
placeholder: "Describe what's wrong...",
|
|
1068
|
+
rows: 2,
|
|
1069
|
+
className: "w-full resize-none rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 focus:border-transparent focus:ring-2 focus:ring-indigo-400 focus:outline-none dark:border-gray-700 dark:bg-gray-950 dark:text-gray-100",
|
|
1070
|
+
disabled: isLoading
|
|
1071
|
+
}
|
|
1072
|
+
),
|
|
1073
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-2", children: [
|
|
1074
|
+
captureResult && (captureResult.consoleErrors.length > 0 || captureResult.networkErrors.length > 0) && /* @__PURE__ */ jsxs3("p", { className: "flex-1 text-xs text-amber-600", children: [
|
|
1075
|
+
[
|
|
1076
|
+
captureResult.consoleErrors.length > 0 ? `${captureResult.consoleErrors.length} console error${captureResult.consoleErrors.length !== 1 ? "s" : ""}` : null,
|
|
1077
|
+
captureResult.networkErrors.length > 0 ? `${captureResult.networkErrors.length} failed request${captureResult.networkErrors.length !== 1 ? "s" : ""}` : null
|
|
1078
|
+
].filter(Boolean).join(" + "),
|
|
1079
|
+
" ",
|
|
1080
|
+
"captured \u2014 these will be included in the report."
|
|
1081
|
+
] }),
|
|
1082
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2", children: [
|
|
1083
|
+
/* @__PURE__ */ jsxs3(
|
|
1011
1084
|
"button",
|
|
1012
1085
|
{
|
|
1013
1086
|
onClick: sendMessage,
|
|
1014
1087
|
disabled: !input.trim() || isLoading,
|
|
1015
|
-
className: "
|
|
1088
|
+
className: "flex items-center gap-1 rounded-md bg-indigo-600 px-3 py-2 text-nowrap text-white transition-colors hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50",
|
|
1016
1089
|
title: "Send message",
|
|
1017
|
-
children:
|
|
1090
|
+
children: [
|
|
1091
|
+
/* @__PURE__ */ jsx3(Send, { className: "h-4 w-4" }),
|
|
1092
|
+
/* @__PURE__ */ jsx3("span", { className: "text-sm font-medium", children: "Send message" })
|
|
1093
|
+
]
|
|
1018
1094
|
}
|
|
1019
1095
|
),
|
|
1020
1096
|
messages.length >= 2 && /* @__PURE__ */ jsx3(
|
|
@@ -1022,22 +1098,14 @@ function ReportModal({
|
|
|
1022
1098
|
{
|
|
1023
1099
|
onClick: handleManualSubmit,
|
|
1024
1100
|
disabled: isLoading,
|
|
1025
|
-
className: "px-
|
|
1101
|
+
className: "rounded-md bg-green-600 px-3 py-2 text-xs font-medium text-nowrap text-white transition-colors hover:bg-green-700 disabled:opacity-50",
|
|
1026
1102
|
title: "Submit report now",
|
|
1027
|
-
children: "Submit"
|
|
1103
|
+
children: /* @__PURE__ */ jsx3("span", { className: "text-sm font-medium", children: "Submit report" })
|
|
1028
1104
|
}
|
|
1029
1105
|
)
|
|
1030
1106
|
] })
|
|
1031
|
-
] }),
|
|
1032
|
-
captureResult && (captureResult.consoleErrors.length > 0 || captureResult.networkErrors.length > 0) && /* @__PURE__ */ jsxs2("p", { className: "text-xs text-amber-600 mt-1.5", children: [
|
|
1033
|
-
[
|
|
1034
|
-
captureResult.consoleErrors.length > 0 ? `${captureResult.consoleErrors.length} console error${captureResult.consoleErrors.length !== 1 ? "s" : ""}` : null,
|
|
1035
|
-
captureResult.networkErrors.length > 0 ? `${captureResult.networkErrors.length} failed request${captureResult.networkErrors.length !== 1 ? "s" : ""}` : null
|
|
1036
|
-
].filter(Boolean).join(" + "),
|
|
1037
|
-
" ",
|
|
1038
|
-
"captured \u2014 these will be included in the report."
|
|
1039
1107
|
] })
|
|
1040
|
-
] })
|
|
1108
|
+
] }) })
|
|
1041
1109
|
]
|
|
1042
1110
|
}
|
|
1043
1111
|
)
|
|
@@ -1046,16 +1114,18 @@ function ReportModal({
|
|
|
1046
1114
|
}
|
|
1047
1115
|
|
|
1048
1116
|
// src/bug-reporter.tsx
|
|
1049
|
-
import { Fragment as Fragment3, jsx as jsx4, jsxs as
|
|
1117
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1050
1118
|
function JarveBugReporter({
|
|
1051
1119
|
apiUrl,
|
|
1052
1120
|
apiKey,
|
|
1053
1121
|
user,
|
|
1122
|
+
buttonPosition,
|
|
1054
1123
|
children
|
|
1055
1124
|
}) {
|
|
1056
|
-
const
|
|
1057
|
-
const [
|
|
1058
|
-
const [
|
|
1125
|
+
const safeApiKey = apiKey || "";
|
|
1126
|
+
const [captureMode, setCaptureMode] = useState4(false);
|
|
1127
|
+
const [captureResult, setCaptureResult] = useState4(null);
|
|
1128
|
+
const [showModal, setShowModal] = useState4(false);
|
|
1059
1129
|
useEffect3(() => {
|
|
1060
1130
|
startCapturing();
|
|
1061
1131
|
startNetworkCapture();
|
|
@@ -1081,12 +1151,19 @@ function JarveBugReporter({
|
|
|
1081
1151
|
clearCapturedErrors();
|
|
1082
1152
|
clearCapturedNetworkErrors();
|
|
1083
1153
|
}, []);
|
|
1084
|
-
const siteId =
|
|
1154
|
+
const siteId = safeApiKey.startsWith("brk_") ? safeApiKey.slice(4, 12) : "external";
|
|
1085
1155
|
const reporterName = (user == null ? void 0 : user.name) || "Anonymous";
|
|
1086
1156
|
const reporterEmail = (user == null ? void 0 : user.email) || "unknown@external";
|
|
1087
|
-
return /* @__PURE__ */
|
|
1157
|
+
return /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1088
1158
|
children,
|
|
1089
|
-
/* @__PURE__ */ jsx4(
|
|
1159
|
+
/* @__PURE__ */ jsx4(
|
|
1160
|
+
FloatingButton,
|
|
1161
|
+
{
|
|
1162
|
+
isActive: captureMode,
|
|
1163
|
+
onClick: toggleCaptureMode,
|
|
1164
|
+
position: buttonPosition
|
|
1165
|
+
}
|
|
1166
|
+
),
|
|
1090
1167
|
/* @__PURE__ */ jsx4(
|
|
1091
1168
|
CaptureOverlay,
|
|
1092
1169
|
{
|