quick-bug-reporter-react 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.cjs +158 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +158 -14
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -92,6 +92,10 @@ type BugReporterSubmitOptions = {
|
|
|
92
92
|
consoleLogs?: ConsoleLogEntry[];
|
|
93
93
|
jsErrors?: CapturedJsError[];
|
|
94
94
|
onProgress?: SubmitProgressCallback;
|
|
95
|
+
stepsToReproduce?: string;
|
|
96
|
+
expectedResult?: string;
|
|
97
|
+
actualResult?: string;
|
|
98
|
+
additionalContext?: string;
|
|
95
99
|
};
|
|
96
100
|
declare class BugReporter {
|
|
97
101
|
private integration;
|
|
@@ -153,7 +157,12 @@ type BugReporterContextValue = {
|
|
|
153
157
|
screenshotHighlightCount: number;
|
|
154
158
|
updateScreenshotAnnotation: (annotation: ScreenshotAnnotationState) => void;
|
|
155
159
|
clearDraft: () => void;
|
|
156
|
-
submitReport: (title: string,
|
|
160
|
+
submitReport: (title: string, structuredFields: {
|
|
161
|
+
stepsToReproduce: string;
|
|
162
|
+
expectedResult: string;
|
|
163
|
+
actualResult: string;
|
|
164
|
+
additionalContext: string;
|
|
165
|
+
}) => Promise<BugSubmitResult | null>;
|
|
157
166
|
resetMessages: () => void;
|
|
158
167
|
};
|
|
159
168
|
declare function BugReporterProvider({ children, integrations, defaultProvider, maxDurationMs, }: BugReporterProviderProps): react_jsx_runtime.JSX.Element;
|
package/dist/index.d.ts
CHANGED
|
@@ -92,6 +92,10 @@ type BugReporterSubmitOptions = {
|
|
|
92
92
|
consoleLogs?: ConsoleLogEntry[];
|
|
93
93
|
jsErrors?: CapturedJsError[];
|
|
94
94
|
onProgress?: SubmitProgressCallback;
|
|
95
|
+
stepsToReproduce?: string;
|
|
96
|
+
expectedResult?: string;
|
|
97
|
+
actualResult?: string;
|
|
98
|
+
additionalContext?: string;
|
|
95
99
|
};
|
|
96
100
|
declare class BugReporter {
|
|
97
101
|
private integration;
|
|
@@ -153,7 +157,12 @@ type BugReporterContextValue = {
|
|
|
153
157
|
screenshotHighlightCount: number;
|
|
154
158
|
updateScreenshotAnnotation: (annotation: ScreenshotAnnotationState) => void;
|
|
155
159
|
clearDraft: () => void;
|
|
156
|
-
submitReport: (title: string,
|
|
160
|
+
submitReport: (title: string, structuredFields: {
|
|
161
|
+
stepsToReproduce: string;
|
|
162
|
+
expectedResult: string;
|
|
163
|
+
actualResult: string;
|
|
164
|
+
additionalContext: string;
|
|
165
|
+
}) => Promise<BugSubmitResult | null>;
|
|
157
166
|
resetMessages: () => void;
|
|
158
167
|
};
|
|
159
168
|
declare function BugReporterProvider({ children, integrations, defaultProvider, maxDurationMs, }: BugReporterProviderProps): react_jsx_runtime.JSX.Element;
|
package/dist/index.js
CHANGED
|
@@ -892,6 +892,10 @@ var CloudIntegration = class {
|
|
|
892
892
|
fd.set("project_key", this.projectKey);
|
|
893
893
|
fd.set("title", payload.title);
|
|
894
894
|
fd.set("description", payload.description || "");
|
|
895
|
+
if (payload.stepsToReproduce) fd.set("steps_to_reproduce", payload.stepsToReproduce);
|
|
896
|
+
if (payload.expectedResult) fd.set("expected_result", payload.expectedResult);
|
|
897
|
+
if (payload.actualResult) fd.set("actual_result", payload.actualResult);
|
|
898
|
+
if (payload.additionalContext) fd.set("additional_context", payload.additionalContext);
|
|
895
899
|
fd.set("provider", "cloud");
|
|
896
900
|
fd.set("capture_mode", payload.captureMode);
|
|
897
901
|
fd.set("has_screenshot", String(Boolean(payload.screenshotBlob)));
|
|
@@ -1827,6 +1831,10 @@ var BugReporter = class {
|
|
|
1827
1831
|
const payload = {
|
|
1828
1832
|
title: normalizedTitle,
|
|
1829
1833
|
description: normalizedDescription,
|
|
1834
|
+
stepsToReproduce: options.stepsToReproduce,
|
|
1835
|
+
expectedResult: options.expectedResult,
|
|
1836
|
+
actualResult: options.actualResult,
|
|
1837
|
+
additionalContext: options.additionalContext,
|
|
1830
1838
|
videoBlob: artifacts.videoBlob,
|
|
1831
1839
|
screenshotBlob: options.screenshotBlob ?? artifacts.screenshotBlob,
|
|
1832
1840
|
networkLogs: this.session.finalizeNetworkLogsForSubmit(artifacts.captureMode),
|
|
@@ -2359,7 +2367,7 @@ function BugReporterProvider({
|
|
|
2359
2367
|
setScreenshotAnnotation(annotation);
|
|
2360
2368
|
}, []);
|
|
2361
2369
|
const submitReport = useCallback(
|
|
2362
|
-
async (title,
|
|
2370
|
+
async (title, structuredFields) => {
|
|
2363
2371
|
const reporter = getOrCreateReporter();
|
|
2364
2372
|
if (!reporter) {
|
|
2365
2373
|
setError("No bug tracker integration is configured.");
|
|
@@ -2379,6 +2387,25 @@ function BugReporterProvider({
|
|
|
2379
2387
|
setSubmissionProgress("Preparing submission\u2026");
|
|
2380
2388
|
setError(null);
|
|
2381
2389
|
setSuccess(null);
|
|
2390
|
+
const { stepsToReproduce, expectedResult, actualResult, additionalContext } = structuredFields;
|
|
2391
|
+
const sections = [];
|
|
2392
|
+
if (stepsToReproduce.trim()) {
|
|
2393
|
+
sections.push(`## Steps to Reproduce
|
|
2394
|
+
${stepsToReproduce.trim()}`);
|
|
2395
|
+
}
|
|
2396
|
+
if (expectedResult.trim()) {
|
|
2397
|
+
sections.push(`## Expected Result
|
|
2398
|
+
${expectedResult.trim()}`);
|
|
2399
|
+
}
|
|
2400
|
+
if (actualResult.trim()) {
|
|
2401
|
+
sections.push(`## Actual Result
|
|
2402
|
+
${actualResult.trim()}`);
|
|
2403
|
+
}
|
|
2404
|
+
if (additionalContext.trim()) {
|
|
2405
|
+
sections.push(`## Additional Context
|
|
2406
|
+
${additionalContext.trim()}`);
|
|
2407
|
+
}
|
|
2408
|
+
const description = sections.length > 0 ? sections.join("\n\n") : "No description provided";
|
|
2382
2409
|
const screenshotBlobForSubmit = draftMode === "screenshot" ? screenshotAnnotation.annotatedBlob ?? screenshotBlob : null;
|
|
2383
2410
|
const metadata = {
|
|
2384
2411
|
annotation: draftMode === "screenshot" && screenshotAnnotation.highlights.length > 0 ? {
|
|
@@ -2393,6 +2420,10 @@ function BugReporterProvider({
|
|
|
2393
2420
|
};
|
|
2394
2421
|
try {
|
|
2395
2422
|
const result = await reporter.submit(title, description, {
|
|
2423
|
+
stepsToReproduce,
|
|
2424
|
+
expectedResult,
|
|
2425
|
+
actualResult,
|
|
2426
|
+
additionalContext,
|
|
2396
2427
|
screenshotBlob: screenshotBlobForSubmit,
|
|
2397
2428
|
metadata,
|
|
2398
2429
|
consoleLogs,
|
|
@@ -3190,6 +3221,7 @@ function providerLabel(provider) {
|
|
|
3190
3221
|
if (provider === "cloud") return "QuickBugs Cloud";
|
|
3191
3222
|
return provider;
|
|
3192
3223
|
}
|
|
3224
|
+
var CHAR_LIMIT = 4e3;
|
|
3193
3225
|
function BugReporterModal() {
|
|
3194
3226
|
const {
|
|
3195
3227
|
autoStopNotice,
|
|
@@ -3219,9 +3251,39 @@ function BugReporterModal() {
|
|
|
3219
3251
|
videoPreviewUrl
|
|
3220
3252
|
} = useBugReporter();
|
|
3221
3253
|
const [title, setTitle] = useState("");
|
|
3222
|
-
const [
|
|
3254
|
+
const [stepsToReproduce, setStepsToReproduce] = useState("");
|
|
3255
|
+
const [expectedResult, setExpectedResult] = useState("");
|
|
3256
|
+
const [actualResult, setActualResult] = useState("");
|
|
3257
|
+
const [additionalContext, setAdditionalContext] = useState("");
|
|
3223
3258
|
const [step, setStep] = useState("review");
|
|
3259
|
+
const [activeTab, setActiveTab] = useState("steps");
|
|
3260
|
+
const totalChars = stepsToReproduce.length + expectedResult.length + actualResult.length + additionalContext.length;
|
|
3261
|
+
const isOverLimit = totalChars > CHAR_LIMIT;
|
|
3224
3262
|
const elapsedLabel = useMemo(() => formatElapsed2(elapsedMs), [elapsedMs]);
|
|
3263
|
+
const handleStepsKeyDown = (event) => {
|
|
3264
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
3265
|
+
event.preventDefault();
|
|
3266
|
+
const textarea = event.currentTarget;
|
|
3267
|
+
const cursorPos = textarea.selectionStart;
|
|
3268
|
+
const textBeforeCursor = stepsToReproduce.substring(0, cursorPos);
|
|
3269
|
+
const textAfterCursor = stepsToReproduce.substring(cursorPos);
|
|
3270
|
+
const lines = textBeforeCursor.split("\n");
|
|
3271
|
+
const currentLine = lines[lines.length - 1];
|
|
3272
|
+
const numberMatch = currentLine.match(/^(\d+)\.\s/);
|
|
3273
|
+
const nextNumber = numberMatch ? parseInt(numberMatch[1]) + 1 : lines.length > 0 && stepsToReproduce.trim() === "" ? 1 : lines.length + 1;
|
|
3274
|
+
const newText = textBeforeCursor + "\n" + nextNumber + ". " + textAfterCursor;
|
|
3275
|
+
setStepsToReproduce(newText);
|
|
3276
|
+
setTimeout(() => {
|
|
3277
|
+
const newCursorPos = cursorPos + ("\n" + nextNumber + ". ").length;
|
|
3278
|
+
textarea.setSelectionRange(newCursorPos, newCursorPos);
|
|
3279
|
+
}, 0);
|
|
3280
|
+
}
|
|
3281
|
+
};
|
|
3282
|
+
const handleStepsFocus = () => {
|
|
3283
|
+
if (stepsToReproduce.trim() === "") {
|
|
3284
|
+
setStepsToReproduce("1. ");
|
|
3285
|
+
}
|
|
3286
|
+
};
|
|
3225
3287
|
const handleDialogOpenChange = (open) => {
|
|
3226
3288
|
if (open) {
|
|
3227
3289
|
openModal();
|
|
@@ -3232,15 +3294,24 @@ function BugReporterModal() {
|
|
|
3232
3294
|
};
|
|
3233
3295
|
const handleSubmit = async (event) => {
|
|
3234
3296
|
event.preventDefault();
|
|
3235
|
-
const result = await submitReport(title,
|
|
3297
|
+
const result = await submitReport(title, {
|
|
3298
|
+
stepsToReproduce,
|
|
3299
|
+
expectedResult,
|
|
3300
|
+
actualResult,
|
|
3301
|
+
additionalContext
|
|
3302
|
+
});
|
|
3236
3303
|
if (result) {
|
|
3237
3304
|
setTitle("");
|
|
3238
|
-
|
|
3305
|
+
setStepsToReproduce("");
|
|
3306
|
+
setExpectedResult("");
|
|
3307
|
+
setActualResult("");
|
|
3308
|
+
setAdditionalContext("");
|
|
3239
3309
|
setStep("review");
|
|
3310
|
+
setActiveTab("steps");
|
|
3240
3311
|
}
|
|
3241
3312
|
};
|
|
3242
3313
|
const hasIntegrations = availableProviders.length > 0;
|
|
3243
|
-
const canSubmit = !isSubmitting && !isCapturingScreenshot && hasIntegrations && !!selectedProvider && hasDraft && title.trim().length > 0;
|
|
3314
|
+
const canSubmit = !isSubmitting && !isCapturingScreenshot && hasIntegrations && !!selectedProvider && hasDraft && title.trim().length > 0 && !isOverLimit;
|
|
3244
3315
|
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: handleDialogOpenChange, children: /* @__PURE__ */ jsx(
|
|
3245
3316
|
DialogContent,
|
|
3246
3317
|
{
|
|
@@ -3406,18 +3477,91 @@ function BugReporterModal() {
|
|
|
3406
3477
|
}
|
|
3407
3478
|
)
|
|
3408
3479
|
] }),
|
|
3409
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-
|
|
3410
|
-
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium",
|
|
3411
|
-
/* @__PURE__ */
|
|
3480
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 sm:col-span-2", children: [
|
|
3481
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Bug Details" }),
|
|
3482
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-1 border-b border-gray-200", children: [
|
|
3483
|
+
/* @__PURE__ */ jsx(
|
|
3484
|
+
"button",
|
|
3485
|
+
{
|
|
3486
|
+
type: "button",
|
|
3487
|
+
className: `px-3 py-2 text-sm font-medium transition-colors ${activeTab === "steps" ? "border-b-2 border-indigo-600 text-indigo-600" : "text-gray-500 hover:text-gray-700"}`,
|
|
3488
|
+
onClick: () => setActiveTab("steps"),
|
|
3489
|
+
children: "Steps"
|
|
3490
|
+
}
|
|
3491
|
+
),
|
|
3492
|
+
/* @__PURE__ */ jsx(
|
|
3493
|
+
"button",
|
|
3494
|
+
{
|
|
3495
|
+
type: "button",
|
|
3496
|
+
className: `px-3 py-2 text-sm font-medium transition-colors ${activeTab === "expected" ? "border-b-2 border-indigo-600 text-indigo-600" : "text-gray-500 hover:text-gray-700"}`,
|
|
3497
|
+
onClick: () => setActiveTab("expected"),
|
|
3498
|
+
children: "Expected"
|
|
3499
|
+
}
|
|
3500
|
+
),
|
|
3501
|
+
/* @__PURE__ */ jsx(
|
|
3502
|
+
"button",
|
|
3503
|
+
{
|
|
3504
|
+
type: "button",
|
|
3505
|
+
className: `px-3 py-2 text-sm font-medium transition-colors ${activeTab === "actual" ? "border-b-2 border-indigo-600 text-indigo-600" : "text-gray-500 hover:text-gray-700"}`,
|
|
3506
|
+
onClick: () => setActiveTab("actual"),
|
|
3507
|
+
children: "Actual"
|
|
3508
|
+
}
|
|
3509
|
+
),
|
|
3510
|
+
/* @__PURE__ */ jsx(
|
|
3511
|
+
"button",
|
|
3512
|
+
{
|
|
3513
|
+
type: "button",
|
|
3514
|
+
className: `px-3 py-2 text-sm font-medium transition-colors ${activeTab === "context" ? "border-b-2 border-indigo-600 text-indigo-600" : "text-gray-500 hover:text-gray-700"}`,
|
|
3515
|
+
onClick: () => setActiveTab("context"),
|
|
3516
|
+
children: "Context"
|
|
3517
|
+
}
|
|
3518
|
+
)
|
|
3519
|
+
] }),
|
|
3520
|
+
activeTab === "steps" && /* @__PURE__ */ jsx(
|
|
3412
3521
|
Textarea,
|
|
3413
3522
|
{
|
|
3414
|
-
id: "bug-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3523
|
+
id: "bug-steps",
|
|
3524
|
+
placeholder: "Press Enter to start numbering steps...",
|
|
3525
|
+
value: stepsToReproduce,
|
|
3526
|
+
onChange: (event) => setStepsToReproduce(event.target.value),
|
|
3527
|
+
onKeyDown: handleStepsKeyDown,
|
|
3528
|
+
onFocus: handleStepsFocus
|
|
3419
3529
|
}
|
|
3420
|
-
)
|
|
3530
|
+
),
|
|
3531
|
+
activeTab === "expected" && /* @__PURE__ */ jsx(
|
|
3532
|
+
Textarea,
|
|
3533
|
+
{
|
|
3534
|
+
id: "bug-expected",
|
|
3535
|
+
placeholder: "Describe what should happen...",
|
|
3536
|
+
value: expectedResult,
|
|
3537
|
+
onChange: (event) => setExpectedResult(event.target.value)
|
|
3538
|
+
}
|
|
3539
|
+
),
|
|
3540
|
+
activeTab === "actual" && /* @__PURE__ */ jsx(
|
|
3541
|
+
Textarea,
|
|
3542
|
+
{
|
|
3543
|
+
id: "bug-actual",
|
|
3544
|
+
placeholder: "Describe what actually happened...",
|
|
3545
|
+
value: actualResult,
|
|
3546
|
+
onChange: (event) => setActualResult(event.target.value)
|
|
3547
|
+
}
|
|
3548
|
+
),
|
|
3549
|
+
activeTab === "context" && /* @__PURE__ */ jsx(
|
|
3550
|
+
Textarea,
|
|
3551
|
+
{
|
|
3552
|
+
id: "bug-context",
|
|
3553
|
+
placeholder: "Any additional information, workarounds, or notes...",
|
|
3554
|
+
value: additionalContext,
|
|
3555
|
+
onChange: (event) => setAdditionalContext(event.target.value)
|
|
3556
|
+
}
|
|
3557
|
+
),
|
|
3558
|
+
/* @__PURE__ */ jsxs("p", { className: `text-xs ${isOverLimit ? "text-red-600 font-medium" : "text-gray-500"}`, children: [
|
|
3559
|
+
totalChars,
|
|
3560
|
+
"/",
|
|
3561
|
+
CHAR_LIMIT,
|
|
3562
|
+
" characters ",
|
|
3563
|
+
isOverLimit && "(over limit)"
|
|
3564
|
+
] })
|
|
3421
3565
|
] }),
|
|
3422
3566
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
3423
3567
|
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", htmlFor: "bug-provider", children: "Submit to" }),
|