@bbearai/react 0.1.6 → 0.1.8
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.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +772 -93
- package/dist/index.mjs +772 -93
- package/package.json +11 -3
package/dist/index.mjs
CHANGED
|
@@ -20,6 +20,14 @@ var BugBearContext = createContext({
|
|
|
20
20
|
},
|
|
21
21
|
updateTesterProfile: async () => ({ success: false }),
|
|
22
22
|
refreshTesterInfo: async () => {
|
|
23
|
+
},
|
|
24
|
+
// QA Sessions
|
|
25
|
+
activeSession: null,
|
|
26
|
+
sessionFindings: [],
|
|
27
|
+
startSession: async () => ({ success: false }),
|
|
28
|
+
endSession: async () => ({ success: false }),
|
|
29
|
+
addFinding: async () => ({ success: false }),
|
|
30
|
+
refreshSession: async () => {
|
|
23
31
|
}
|
|
24
32
|
});
|
|
25
33
|
function useBugBear() {
|
|
@@ -33,11 +41,52 @@ function BugBearProvider({ config, children, enabled = true }) {
|
|
|
33
41
|
const [assignments, setAssignments] = useState([]);
|
|
34
42
|
const [isLoading, setIsLoading] = useState(true);
|
|
35
43
|
const hasInitialized = useRef(false);
|
|
44
|
+
const [activeSession, setActiveSession] = useState(null);
|
|
45
|
+
const [sessionFindings, setSessionFindings] = useState([]);
|
|
36
46
|
const refreshAssignments = useCallback(async () => {
|
|
37
47
|
if (!client) return;
|
|
38
48
|
const newAssignments = await client.getAssignedTests();
|
|
39
49
|
setAssignments(newAssignments);
|
|
40
50
|
}, [client]);
|
|
51
|
+
const refreshSession = useCallback(async () => {
|
|
52
|
+
if (!client) return;
|
|
53
|
+
const session = await client.getActiveSession();
|
|
54
|
+
setActiveSession(session);
|
|
55
|
+
if (session) {
|
|
56
|
+
const findings = await client.getSessionFindings(session.id);
|
|
57
|
+
setSessionFindings(findings);
|
|
58
|
+
} else {
|
|
59
|
+
setSessionFindings([]);
|
|
60
|
+
}
|
|
61
|
+
}, [client]);
|
|
62
|
+
const startSession = useCallback(async (options = {}) => {
|
|
63
|
+
if (!client) return { success: false, error: "Client not initialized" };
|
|
64
|
+
const result = await client.startSession(options);
|
|
65
|
+
if (result.success && result.session) {
|
|
66
|
+
setActiveSession(result.session);
|
|
67
|
+
setSessionFindings([]);
|
|
68
|
+
}
|
|
69
|
+
return { success: result.success, error: result.error };
|
|
70
|
+
}, [client]);
|
|
71
|
+
const endSession = useCallback(async (notes) => {
|
|
72
|
+
if (!client || !activeSession) return { success: false, error: "No active session" };
|
|
73
|
+
const routesCovered = client.getNavigationHistory();
|
|
74
|
+
const result = await client.endSession(activeSession.id, { notes, routesCovered });
|
|
75
|
+
if (result.success) {
|
|
76
|
+
setActiveSession(null);
|
|
77
|
+
setSessionFindings([]);
|
|
78
|
+
}
|
|
79
|
+
return { success: result.success, error: result.error };
|
|
80
|
+
}, [client, activeSession]);
|
|
81
|
+
const addFinding = useCallback(async (options) => {
|
|
82
|
+
if (!client || !activeSession) return { success: false, error: "No active session" };
|
|
83
|
+
const result = await client.addFinding(activeSession.id, options);
|
|
84
|
+
if (result.success && result.finding) {
|
|
85
|
+
setSessionFindings((prev) => [...prev, result.finding]);
|
|
86
|
+
setActiveSession((prev) => prev ? { ...prev, findingsCount: prev.findingsCount + 1 } : null);
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}, [client, activeSession]);
|
|
41
90
|
const initializeBugBear = useCallback(async (bugBearClient) => {
|
|
42
91
|
setIsLoading(true);
|
|
43
92
|
try {
|
|
@@ -50,8 +99,16 @@ function BugBearProvider({ config, children, enabled = true }) {
|
|
|
50
99
|
setTesterInfo(info);
|
|
51
100
|
setIsTester(!!info);
|
|
52
101
|
if (info && qaEnabled) {
|
|
53
|
-
const newAssignments = await
|
|
102
|
+
const [newAssignments, session] = await Promise.all([
|
|
103
|
+
bugBearClient.getAssignedTests(),
|
|
104
|
+
bugBearClient.getActiveSession()
|
|
105
|
+
]);
|
|
54
106
|
setAssignments(newAssignments);
|
|
107
|
+
setActiveSession(session);
|
|
108
|
+
if (session) {
|
|
109
|
+
const findings = await bugBearClient.getSessionFindings(session.id);
|
|
110
|
+
setSessionFindings(findings);
|
|
111
|
+
}
|
|
55
112
|
}
|
|
56
113
|
} catch (err) {
|
|
57
114
|
console.error("BugBear: Init error", err);
|
|
@@ -106,7 +163,14 @@ function BugBearProvider({ config, children, enabled = true }) {
|
|
|
106
163
|
onNavigate: config.onNavigate,
|
|
107
164
|
refreshTesterStatus,
|
|
108
165
|
updateTesterProfile,
|
|
109
|
-
refreshTesterInfo
|
|
166
|
+
refreshTesterInfo,
|
|
167
|
+
// QA Sessions
|
|
168
|
+
activeSession,
|
|
169
|
+
sessionFindings,
|
|
170
|
+
startSession,
|
|
171
|
+
endSession,
|
|
172
|
+
addFinding,
|
|
173
|
+
refreshSession
|
|
110
174
|
},
|
|
111
175
|
children
|
|
112
176
|
}
|
|
@@ -185,7 +249,7 @@ function BugBearPanel({
|
|
|
185
249
|
defaultCollapsed = false,
|
|
186
250
|
draggable = true
|
|
187
251
|
}) {
|
|
188
|
-
const { client, shouldShowWidget, testerInfo, assignments, currentAssignment, refreshAssignments, isLoading, onNavigate, updateTesterProfile, refreshTesterInfo } = useBugBear();
|
|
252
|
+
const { client, shouldShowWidget, testerInfo, assignments, currentAssignment, refreshAssignments, isLoading, onNavigate, updateTesterProfile, refreshTesterInfo, activeSession, sessionFindings, startSession, endSession, addFinding } = useBugBear();
|
|
189
253
|
const [collapsed, setCollapsed] = useState2(defaultCollapsed);
|
|
190
254
|
const [activeTab, setActiveTab] = useState2("tests");
|
|
191
255
|
const [showSteps, setShowSteps] = useState2(false);
|
|
@@ -202,6 +266,16 @@ function BugBearPanel({
|
|
|
202
266
|
const [submitting, setSubmitting] = useState2(false);
|
|
203
267
|
const [submitted, setSubmitted] = useState2(false);
|
|
204
268
|
const [justPassed, setJustPassed] = useState2(false);
|
|
269
|
+
const [showFeedbackPrompt, setShowFeedbackPrompt] = useState2(false);
|
|
270
|
+
const [pendingFeedbackStatus, setPendingFeedbackStatus] = useState2(null);
|
|
271
|
+
const [feedbackRating, setFeedbackRating] = useState2(5);
|
|
272
|
+
const [feedbackNote, setFeedbackNote] = useState2("");
|
|
273
|
+
const [feedbackFlags, setFeedbackFlags] = useState2({
|
|
274
|
+
isOutdated: false,
|
|
275
|
+
needsMoreDetail: false,
|
|
276
|
+
stepsUnclear: false,
|
|
277
|
+
expectedResultUnclear: false
|
|
278
|
+
});
|
|
205
279
|
const [criteriaResults, setCriteriaResults] = useState2({});
|
|
206
280
|
const [profileEditing, setProfileEditing] = useState2(false);
|
|
207
281
|
const [profileName, setProfileName] = useState2("");
|
|
@@ -210,6 +284,23 @@ function BugBearPanel({
|
|
|
210
284
|
const [profilePlatforms, setProfilePlatforms] = useState2([]);
|
|
211
285
|
const [savingProfile, setSavingProfile] = useState2(false);
|
|
212
286
|
const [profileSaved, setProfileSaved] = useState2(false);
|
|
287
|
+
const [showProfileOverlay, setShowProfileOverlay] = useState2(false);
|
|
288
|
+
const [startingSession, setStartingSession] = useState2(false);
|
|
289
|
+
const [sessionFocusArea, setSessionFocusArea] = useState2("");
|
|
290
|
+
const [sessionPlatform, setSessionPlatform] = useState2("web");
|
|
291
|
+
const [suggestedRoutes, setSuggestedRoutes] = useState2([]);
|
|
292
|
+
const [focusAreas, setFocusAreas] = useState2([]);
|
|
293
|
+
const [showAddFinding, setShowAddFinding] = useState2(false);
|
|
294
|
+
const [findingType, setFindingType] = useState2("bug");
|
|
295
|
+
const [findingTitle, setFindingTitle] = useState2("");
|
|
296
|
+
const [findingDescription, setFindingDescription] = useState2("");
|
|
297
|
+
const [findingSeverity, setFindingSeverity] = useState2("medium");
|
|
298
|
+
const [addingFinding, setAddingFinding] = useState2(false);
|
|
299
|
+
const [endingSession, setEndingSession] = useState2(false);
|
|
300
|
+
const [sessionNotes, setSessionNotes] = useState2("");
|
|
301
|
+
const [showEndConfirm, setShowEndConfirm] = useState2(false);
|
|
302
|
+
const [sessionElapsedTime, setSessionElapsedTime] = useState2(0);
|
|
303
|
+
const [assignmentElapsedTime, setAssignmentElapsedTime] = useState2(0);
|
|
213
304
|
useEffect2(() => {
|
|
214
305
|
if (typeof window === "undefined") return;
|
|
215
306
|
try {
|
|
@@ -244,6 +335,84 @@ function BugBearPanel({
|
|
|
244
335
|
setCriteriaResults({});
|
|
245
336
|
setShowSteps(false);
|
|
246
337
|
}, [displayedAssignment?.id]);
|
|
338
|
+
useEffect2(() => {
|
|
339
|
+
if (!activeSession) {
|
|
340
|
+
setSessionElapsedTime(0);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const startTime = new Date(activeSession.startedAt).getTime();
|
|
344
|
+
const now = Date.now();
|
|
345
|
+
setSessionElapsedTime(Math.floor((now - startTime) / 1e3));
|
|
346
|
+
const interval = setInterval(() => {
|
|
347
|
+
const elapsed = Math.floor((Date.now() - startTime) / 1e3);
|
|
348
|
+
setSessionElapsedTime(elapsed);
|
|
349
|
+
}, 1e3);
|
|
350
|
+
return () => clearInterval(interval);
|
|
351
|
+
}, [activeSession]);
|
|
352
|
+
useEffect2(() => {
|
|
353
|
+
const activeAssignment = displayedAssignment?.status === "in_progress" ? displayedAssignment : null;
|
|
354
|
+
if (!activeAssignment?.startedAt) {
|
|
355
|
+
setAssignmentElapsedTime(0);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const startTime = new Date(activeAssignment.startedAt).getTime();
|
|
359
|
+
const now = Date.now();
|
|
360
|
+
setAssignmentElapsedTime(Math.floor((now - startTime) / 1e3));
|
|
361
|
+
const interval = setInterval(() => {
|
|
362
|
+
const elapsed = Math.floor((Date.now() - startTime) / 1e3);
|
|
363
|
+
setAssignmentElapsedTime(elapsed);
|
|
364
|
+
}, 1e3);
|
|
365
|
+
return () => clearInterval(interval);
|
|
366
|
+
}, [displayedAssignment?.id, displayedAssignment?.status, displayedAssignment?.startedAt]);
|
|
367
|
+
useEffect2(() => {
|
|
368
|
+
if (!client || activeSession) {
|
|
369
|
+
setSuggestedRoutes([]);
|
|
370
|
+
setFocusAreas([]);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const loadSuggestions = async () => {
|
|
374
|
+
try {
|
|
375
|
+
const supabase = client.supabase;
|
|
376
|
+
if (!supabase) return;
|
|
377
|
+
const projectId = client.config.projectId;
|
|
378
|
+
const [routeStatsRes, focusAreasRes] = await Promise.all([
|
|
379
|
+
supabase.from("route_test_stats").select("route, priority_score, open_bugs, exploratory_issues, last_tested_at, test_case_count").eq("project_id", projectId).order("priority_score", { ascending: false }).limit(10),
|
|
380
|
+
supabase.rpc("get_active_focus_areas", { p_project_id: projectId })
|
|
381
|
+
]);
|
|
382
|
+
if (routeStatsRes.data && routeStatsRes.data.length > 0) {
|
|
383
|
+
const suggestions = routeStatsRes.data.filter((r) => r.route && r.priority_score > 0).slice(0, 5).map((r) => {
|
|
384
|
+
let reason = "";
|
|
385
|
+
if (r.open_bugs > 0) {
|
|
386
|
+
reason = `${r.open_bugs} open bug${r.open_bugs > 1 ? "s" : ""}`;
|
|
387
|
+
} else if (!r.last_tested_at) {
|
|
388
|
+
reason = "Never tested";
|
|
389
|
+
} else if (r.test_case_count === 0) {
|
|
390
|
+
reason = "No test coverage";
|
|
391
|
+
} else {
|
|
392
|
+
reason = `Priority: ${r.priority_score}`;
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
route: r.route,
|
|
396
|
+
reason,
|
|
397
|
+
priorityScore: r.priority_score
|
|
398
|
+
};
|
|
399
|
+
});
|
|
400
|
+
setSuggestedRoutes(suggestions);
|
|
401
|
+
}
|
|
402
|
+
if (focusAreasRes.data && focusAreasRes.data.length > 0) {
|
|
403
|
+
setFocusAreas(focusAreasRes.data.slice(0, 3).map((fa) => ({
|
|
404
|
+
id: fa.id,
|
|
405
|
+
name: fa.name,
|
|
406
|
+
description: fa.description,
|
|
407
|
+
priority: fa.priority
|
|
408
|
+
})));
|
|
409
|
+
}
|
|
410
|
+
} catch (err) {
|
|
411
|
+
console.error("BugBear: Failed to load suggestions", err);
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
loadSuggestions();
|
|
415
|
+
}, [client, activeSession]);
|
|
247
416
|
const handleMouseDown = useCallback2((e) => {
|
|
248
417
|
if (!draggable || !panelPosition) return;
|
|
249
418
|
const target = e.target;
|
|
@@ -294,27 +463,86 @@ function BugBearPanel({
|
|
|
294
463
|
return null;
|
|
295
464
|
}
|
|
296
465
|
const handlePass = async () => {
|
|
297
|
-
if (!
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
466
|
+
if (!displayedAssignment) return;
|
|
467
|
+
setPendingFeedbackStatus("passed");
|
|
468
|
+
setShowFeedbackPrompt(true);
|
|
469
|
+
setFeedbackRating(5);
|
|
470
|
+
setFeedbackNote("");
|
|
471
|
+
setFeedbackFlags({
|
|
472
|
+
isOutdated: false,
|
|
473
|
+
needsMoreDetail: false,
|
|
474
|
+
stepsUnclear: false,
|
|
475
|
+
expectedResultUnclear: false
|
|
305
476
|
});
|
|
306
|
-
await refreshAssignments();
|
|
307
|
-
setSubmitting(false);
|
|
308
|
-
setJustPassed(true);
|
|
309
|
-
setTimeout(() => {
|
|
310
|
-
setJustPassed(false);
|
|
311
|
-
setSelectedTestId(null);
|
|
312
|
-
setTestView("detail");
|
|
313
|
-
}, 1200);
|
|
314
477
|
};
|
|
315
478
|
const handleFail = async () => {
|
|
316
|
-
|
|
317
|
-
|
|
479
|
+
if (!displayedAssignment) return;
|
|
480
|
+
setPendingFeedbackStatus("failed");
|
|
481
|
+
setShowFeedbackPrompt(true);
|
|
482
|
+
setFeedbackRating(3);
|
|
483
|
+
setFeedbackNote("");
|
|
484
|
+
setFeedbackFlags({
|
|
485
|
+
isOutdated: false,
|
|
486
|
+
needsMoreDetail: false,
|
|
487
|
+
stepsUnclear: false,
|
|
488
|
+
expectedResultUnclear: false
|
|
489
|
+
});
|
|
490
|
+
};
|
|
491
|
+
const handleSubmitFeedback = async (skipFeedback = false) => {
|
|
492
|
+
if (!client || !displayedAssignment) return;
|
|
493
|
+
setSubmitting(true);
|
|
494
|
+
const feedback = skipFeedback ? void 0 : {
|
|
495
|
+
rating: feedbackRating,
|
|
496
|
+
feedbackNote: feedbackNote.trim() || void 0,
|
|
497
|
+
isOutdated: feedbackFlags.isOutdated,
|
|
498
|
+
needsMoreDetail: feedbackFlags.needsMoreDetail,
|
|
499
|
+
stepsUnclear: feedbackFlags.stepsUnclear,
|
|
500
|
+
expectedResultUnclear: feedbackFlags.expectedResultUnclear
|
|
501
|
+
};
|
|
502
|
+
if (pendingFeedbackStatus === "passed") {
|
|
503
|
+
await client.submitReport({
|
|
504
|
+
type: "test_pass",
|
|
505
|
+
description: `Test passed: ${displayedAssignment.testCase.title}`,
|
|
506
|
+
assignmentId: displayedAssignment.id,
|
|
507
|
+
testCaseId: displayedAssignment.testCase.id,
|
|
508
|
+
appContext: getAppContext?.() || { currentRoute: window.location.pathname }
|
|
509
|
+
});
|
|
510
|
+
if (feedback) {
|
|
511
|
+
await client.submitTestFeedback({
|
|
512
|
+
testCaseId: displayedAssignment.testCase.id,
|
|
513
|
+
assignmentId: displayedAssignment.id,
|
|
514
|
+
feedback,
|
|
515
|
+
timeToCompleteSeconds: assignmentElapsedTime || void 0
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
await refreshAssignments();
|
|
519
|
+
setSubmitting(false);
|
|
520
|
+
setShowFeedbackPrompt(false);
|
|
521
|
+
setPendingFeedbackStatus(null);
|
|
522
|
+
setJustPassed(true);
|
|
523
|
+
setTimeout(() => {
|
|
524
|
+
setJustPassed(false);
|
|
525
|
+
setSelectedTestId(null);
|
|
526
|
+
setTestView("detail");
|
|
527
|
+
}, 1200);
|
|
528
|
+
} else if (pendingFeedbackStatus === "failed") {
|
|
529
|
+
if (feedback) {
|
|
530
|
+
await client.submitTestFeedback({
|
|
531
|
+
testCaseId: displayedAssignment.testCase.id,
|
|
532
|
+
assignmentId: displayedAssignment.id,
|
|
533
|
+
feedback,
|
|
534
|
+
timeToCompleteSeconds: assignmentElapsedTime || void 0
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
setSubmitting(false);
|
|
538
|
+
setShowFeedbackPrompt(false);
|
|
539
|
+
setPendingFeedbackStatus(null);
|
|
540
|
+
setActiveTab("report");
|
|
541
|
+
setReportType("test_fail");
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
const handleSkipFeedback = () => {
|
|
545
|
+
handleSubmitFeedback(true);
|
|
318
546
|
};
|
|
319
547
|
const handleSubmitReport = async () => {
|
|
320
548
|
if (!client || !description.trim()) return;
|
|
@@ -346,6 +574,15 @@ function BugBearPanel({
|
|
|
346
574
|
};
|
|
347
575
|
const pendingCount = assignments.filter((a) => a.status === "pending").length;
|
|
348
576
|
const inProgressCount = assignments.filter((a) => a.status === "in_progress").length;
|
|
577
|
+
const handleOpenProfile = () => {
|
|
578
|
+
if (testerInfo) {
|
|
579
|
+
setProfileName(testerInfo.name);
|
|
580
|
+
setProfileAdditionalEmails(testerInfo.additionalEmails || []);
|
|
581
|
+
setProfilePlatforms(testerInfo.platforms || []);
|
|
582
|
+
}
|
|
583
|
+
setProfileEditing(false);
|
|
584
|
+
setShowProfileOverlay(true);
|
|
585
|
+
};
|
|
349
586
|
const handleStartEditProfile = () => {
|
|
350
587
|
if (testerInfo) {
|
|
351
588
|
setProfileName(testerInfo.name);
|
|
@@ -358,6 +595,11 @@ function BugBearPanel({
|
|
|
358
595
|
setProfileEditing(false);
|
|
359
596
|
setNewEmailInput("");
|
|
360
597
|
};
|
|
598
|
+
const handleCloseProfile = () => {
|
|
599
|
+
setShowProfileOverlay(false);
|
|
600
|
+
setProfileEditing(false);
|
|
601
|
+
setNewEmailInput("");
|
|
602
|
+
};
|
|
361
603
|
const handleAddEmail = () => {
|
|
362
604
|
const email = newEmailInput.trim().toLowerCase();
|
|
363
605
|
if (email && email.includes("@") && !profileAdditionalEmails.includes(email)) {
|
|
@@ -386,10 +628,61 @@ function BugBearPanel({
|
|
|
386
628
|
if (result.success) {
|
|
387
629
|
setProfileEditing(false);
|
|
388
630
|
setProfileSaved(true);
|
|
389
|
-
setTimeout(() =>
|
|
631
|
+
setTimeout(() => {
|
|
632
|
+
setProfileSaved(false);
|
|
633
|
+
setShowProfileOverlay(false);
|
|
634
|
+
}, 1500);
|
|
390
635
|
}
|
|
391
636
|
setSavingProfile(false);
|
|
392
637
|
};
|
|
638
|
+
const handleStartSession = async () => {
|
|
639
|
+
setStartingSession(true);
|
|
640
|
+
const result = await startSession({
|
|
641
|
+
focusArea: sessionFocusArea.trim() || void 0,
|
|
642
|
+
platform: sessionPlatform
|
|
643
|
+
});
|
|
644
|
+
if (result.success) {
|
|
645
|
+
setSessionFocusArea("");
|
|
646
|
+
}
|
|
647
|
+
setStartingSession(false);
|
|
648
|
+
};
|
|
649
|
+
const handleEndSession = async () => {
|
|
650
|
+
setEndingSession(true);
|
|
651
|
+
const result = await endSession(sessionNotes.trim() || void 0);
|
|
652
|
+
if (result.success) {
|
|
653
|
+
setSessionNotes("");
|
|
654
|
+
setShowEndConfirm(false);
|
|
655
|
+
}
|
|
656
|
+
setEndingSession(false);
|
|
657
|
+
};
|
|
658
|
+
const handleAddFinding = async () => {
|
|
659
|
+
if (!findingTitle.trim()) return;
|
|
660
|
+
setAddingFinding(true);
|
|
661
|
+
const result = await addFinding({
|
|
662
|
+
type: findingType,
|
|
663
|
+
title: findingTitle.trim(),
|
|
664
|
+
description: findingDescription.trim() || void 0,
|
|
665
|
+
severity: findingType === "bug" ? findingSeverity : void 0,
|
|
666
|
+
route: typeof window !== "undefined" ? window.location.pathname : void 0
|
|
667
|
+
});
|
|
668
|
+
if (result.success) {
|
|
669
|
+
setFindingTitle("");
|
|
670
|
+
setFindingDescription("");
|
|
671
|
+
setFindingType("bug");
|
|
672
|
+
setFindingSeverity("medium");
|
|
673
|
+
setShowAddFinding(false);
|
|
674
|
+
}
|
|
675
|
+
setAddingFinding(false);
|
|
676
|
+
};
|
|
677
|
+
const formatElapsedTime = (seconds) => {
|
|
678
|
+
const h = Math.floor(seconds / 3600);
|
|
679
|
+
const m = Math.floor(seconds % 3600 / 60);
|
|
680
|
+
const s = seconds % 60;
|
|
681
|
+
if (h > 0) {
|
|
682
|
+
return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
|
|
683
|
+
}
|
|
684
|
+
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
685
|
+
};
|
|
393
686
|
return /* @__PURE__ */ jsxs(
|
|
394
687
|
"div",
|
|
395
688
|
{
|
|
@@ -437,7 +730,17 @@ function BugBearPanel({
|
|
|
437
730
|
"BugBear",
|
|
438
731
|
draggable && /* @__PURE__ */ jsx2("span", { className: "text-purple-300 text-xs", title: "Drag to move, double-click to reset", children: "\u22EE\u22EE" })
|
|
439
732
|
] }),
|
|
440
|
-
/* @__PURE__ */
|
|
733
|
+
/* @__PURE__ */ jsxs(
|
|
734
|
+
"button",
|
|
735
|
+
{
|
|
736
|
+
onClick: handleOpenProfile,
|
|
737
|
+
className: "text-purple-200 text-xs flex items-center gap-1 hover:text-white transition-colors",
|
|
738
|
+
children: [
|
|
739
|
+
testerInfo?.name,
|
|
740
|
+
/* @__PURE__ */ jsx2("span", { className: "text-[10px]", children: "\u270E" })
|
|
741
|
+
]
|
|
742
|
+
}
|
|
743
|
+
)
|
|
441
744
|
] })
|
|
442
745
|
] }),
|
|
443
746
|
/* @__PURE__ */ jsx2(
|
|
@@ -451,35 +754,40 @@ function BugBearPanel({
|
|
|
451
754
|
]
|
|
452
755
|
}
|
|
453
756
|
),
|
|
454
|
-
/* @__PURE__ */ jsxs("div", { className: "flex border-b border-gray-200", children: [
|
|
757
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 p-2 bg-gray-50 border-b border-gray-200", children: [
|
|
455
758
|
/* @__PURE__ */ jsxs(
|
|
456
759
|
"button",
|
|
457
760
|
{
|
|
458
761
|
onClick: () => setActiveTab("tests"),
|
|
459
|
-
className: `flex-1 px-
|
|
762
|
+
className: `flex-1 py-2 px-3 rounded-lg text-sm font-semibold transition-all flex items-center justify-center gap-1.5 ${activeTab === "tests" ? "bg-purple-600 text-white shadow-sm" : "bg-white text-gray-600 hover:bg-gray-100 border border-gray-200"}`,
|
|
460
763
|
children: [
|
|
461
|
-
"
|
|
462
|
-
|
|
764
|
+
/* @__PURE__ */ jsx2("span", { children: "\u{1F4CB}" }),
|
|
765
|
+
/* @__PURE__ */ jsx2("span", { children: "Run Tests" }),
|
|
766
|
+
pendingCount > 0 && /* @__PURE__ */ jsx2("span", { className: `ml-1 px-1.5 py-0.5 rounded-full text-xs ${activeTab === "tests" ? "bg-purple-500 text-white" : "bg-purple-100 text-purple-600"}`, children: pendingCount })
|
|
463
767
|
]
|
|
464
768
|
}
|
|
465
769
|
),
|
|
466
|
-
/* @__PURE__ */
|
|
467
|
-
"button",
|
|
468
|
-
{
|
|
469
|
-
onClick: () => setActiveTab("profile"),
|
|
470
|
-
className: `flex-1 px-4 py-2 text-sm font-medium transition-colors ${activeTab === "profile" ? "text-purple-600 border-b-2 border-purple-600" : "text-gray-500 hover:text-gray-700"}`,
|
|
471
|
-
children: "Profile"
|
|
472
|
-
}
|
|
473
|
-
),
|
|
474
|
-
/* @__PURE__ */ jsx2(
|
|
770
|
+
/* @__PURE__ */ jsxs(
|
|
475
771
|
"button",
|
|
476
772
|
{
|
|
477
|
-
onClick: () => setActiveTab("
|
|
478
|
-
className: `flex-1 px-
|
|
479
|
-
children:
|
|
773
|
+
onClick: () => setActiveTab("session"),
|
|
774
|
+
className: `flex-1 py-2 px-3 rounded-lg text-sm font-semibold transition-all flex items-center justify-center gap-1.5 relative ${activeTab === "session" ? "bg-amber-500 text-white shadow-sm" : "bg-white text-gray-600 hover:bg-gray-100 border border-gray-200"}`,
|
|
775
|
+
children: [
|
|
776
|
+
/* @__PURE__ */ jsx2("span", { children: "\u{1F50D}" }),
|
|
777
|
+
/* @__PURE__ */ jsx2("span", { children: "Explore" }),
|
|
778
|
+
activeSession && /* @__PURE__ */ jsx2("span", { className: "absolute -top-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white animate-pulse" })
|
|
779
|
+
]
|
|
480
780
|
}
|
|
481
781
|
)
|
|
482
782
|
] }),
|
|
783
|
+
/* @__PURE__ */ jsx2("div", { className: "flex justify-center py-1.5 border-b border-gray-200 bg-white", children: /* @__PURE__ */ jsx2(
|
|
784
|
+
"button",
|
|
785
|
+
{
|
|
786
|
+
onClick: () => setActiveTab("report"),
|
|
787
|
+
className: `px-4 py-1 text-xs font-medium transition-colors rounded-full ${activeTab === "report" ? "bg-red-50 text-red-600 border border-red-200" : "text-gray-500 hover:text-gray-700 hover:bg-gray-50"}`,
|
|
788
|
+
children: "\u{1F41B} Report Bug / Feedback"
|
|
789
|
+
}
|
|
790
|
+
) }),
|
|
483
791
|
/* @__PURE__ */ jsxs("div", { className: "p-4 max-h-96 overflow-y-auto", children: [
|
|
484
792
|
activeTab === "tests" && /* @__PURE__ */ jsx2("div", { children: assignments.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
|
|
485
793
|
/* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u2705" }),
|
|
@@ -530,6 +838,83 @@ function BugBearPanel({
|
|
|
530
838
|
assignment.id
|
|
531
839
|
))
|
|
532
840
|
] })
|
|
841
|
+
) : showFeedbackPrompt && displayedAssignment ? (
|
|
842
|
+
/* Feedback prompt after completing a test */
|
|
843
|
+
/* @__PURE__ */ jsxs("div", { className: "p-3", children: [
|
|
844
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
|
|
845
|
+
/* @__PURE__ */ jsx2("span", { className: "text-3xl", children: pendingFeedbackStatus === "passed" ? "\u2713" : "\u2717" }),
|
|
846
|
+
/* @__PURE__ */ jsx2("p", { className: `font-semibold mt-1 ${pendingFeedbackStatus === "passed" ? "text-green-600" : "text-red-600"}`, children: pendingFeedbackStatus === "passed" ? "Test Passed!" : "Test Failed" })
|
|
847
|
+
] }),
|
|
848
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-purple-50 border border-purple-100 rounded-lg p-3 mb-4", children: [
|
|
849
|
+
/* @__PURE__ */ jsx2("p", { className: "text-purple-800 text-sm font-medium mb-1", children: "Help us improve this test" }),
|
|
850
|
+
/* @__PURE__ */ jsx2("p", { className: "text-purple-600 text-xs", children: "Your feedback shapes better tests for everyone." })
|
|
851
|
+
] }),
|
|
852
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
853
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-600 mb-2", children: "How was this test?" }),
|
|
854
|
+
/* @__PURE__ */ jsx2("div", { className: "flex items-center gap-1 justify-center", children: [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ jsx2(
|
|
855
|
+
"button",
|
|
856
|
+
{
|
|
857
|
+
type: "button",
|
|
858
|
+
onClick: () => setFeedbackRating(star),
|
|
859
|
+
className: `text-2xl transition-colors ${star <= feedbackRating ? "text-yellow-400" : "text-gray-300"} hover:text-yellow-400`,
|
|
860
|
+
children: "\u2605"
|
|
861
|
+
},
|
|
862
|
+
star
|
|
863
|
+
)) }),
|
|
864
|
+
/* @__PURE__ */ jsx2("p", { className: "text-center text-xs text-gray-500 mt-1", children: feedbackRating === 1 ? "Needs work" : feedbackRating === 2 ? "Could be better" : feedbackRating === 3 ? "Okay" : feedbackRating === 4 ? "Good" : "Great!" })
|
|
865
|
+
] }),
|
|
866
|
+
feedbackRating < 4 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
867
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-600 mb-2", children: "What could be improved?" }),
|
|
868
|
+
/* @__PURE__ */ jsx2("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
869
|
+
{ key: "stepsUnclear", label: "Steps unclear" },
|
|
870
|
+
{ key: "expectedResultUnclear", label: "Expected result unclear" },
|
|
871
|
+
{ key: "needsMoreDetail", label: "Needs more detail" },
|
|
872
|
+
{ key: "isOutdated", label: "Seems outdated" }
|
|
873
|
+
].map(({ key, label }) => /* @__PURE__ */ jsx2(
|
|
874
|
+
"button",
|
|
875
|
+
{
|
|
876
|
+
type: "button",
|
|
877
|
+
onClick: () => setFeedbackFlags((prev) => ({ ...prev, [key]: !prev[key] })),
|
|
878
|
+
className: `px-2 py-1.5 rounded text-xs font-medium border transition-colors ${feedbackFlags[key] ? "bg-purple-100 border-purple-300 text-purple-700" : "bg-white border-gray-200 text-gray-600 hover:border-purple-200"}`,
|
|
879
|
+
children: label
|
|
880
|
+
},
|
|
881
|
+
key
|
|
882
|
+
)) })
|
|
883
|
+
] }),
|
|
884
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
885
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-600 mb-1", children: "Suggestions? (optional)" }),
|
|
886
|
+
/* @__PURE__ */ jsx2(
|
|
887
|
+
"textarea",
|
|
888
|
+
{
|
|
889
|
+
value: feedbackNote,
|
|
890
|
+
onChange: (e) => setFeedbackNote(e.target.value),
|
|
891
|
+
placeholder: "How could this test be improved?",
|
|
892
|
+
className: "w-full px-3 py-2 text-sm border border-gray-200 rounded-lg resize-none focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent",
|
|
893
|
+
rows: 2
|
|
894
|
+
}
|
|
895
|
+
)
|
|
896
|
+
] }),
|
|
897
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
898
|
+
/* @__PURE__ */ jsx2(
|
|
899
|
+
"button",
|
|
900
|
+
{
|
|
901
|
+
onClick: handleSkipFeedback,
|
|
902
|
+
disabled: submitting,
|
|
903
|
+
className: "flex-1 px-3 py-2 text-sm font-medium text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors disabled:opacity-50",
|
|
904
|
+
children: "Skip"
|
|
905
|
+
}
|
|
906
|
+
),
|
|
907
|
+
/* @__PURE__ */ jsx2(
|
|
908
|
+
"button",
|
|
909
|
+
{
|
|
910
|
+
onClick: () => handleSubmitFeedback(false),
|
|
911
|
+
disabled: submitting,
|
|
912
|
+
className: "flex-1 px-3 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700 transition-colors disabled:opacity-50",
|
|
913
|
+
children: submitting ? "Submitting..." : "Submit Feedback"
|
|
914
|
+
}
|
|
915
|
+
)
|
|
916
|
+
] })
|
|
917
|
+
] })
|
|
533
918
|
) : justPassed ? (
|
|
534
919
|
/* Success state after passing */
|
|
535
920
|
/* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
|
|
@@ -571,6 +956,14 @@ function BugBearPanel({
|
|
|
571
956
|
] })
|
|
572
957
|
] }),
|
|
573
958
|
/* @__PURE__ */ jsx2("h4", { className: "font-medium text-gray-900 text-sm mb-1", children: displayedAssignment.testCase.title }),
|
|
959
|
+
displayedAssignment.status === "in_progress" && displayedAssignment.startedAt && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-2 text-xs text-green-600 bg-green-50 px-2 py-1 rounded", children: [
|
|
960
|
+
/* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
|
|
961
|
+
/* @__PURE__ */ jsx2("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
|
|
962
|
+
/* @__PURE__ */ jsx2("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500" })
|
|
963
|
+
] }),
|
|
964
|
+
/* @__PURE__ */ jsx2("span", { className: "font-medium", children: "Testing" }),
|
|
965
|
+
/* @__PURE__ */ jsx2("span", { className: "font-mono", children: formatElapsedTime(assignmentElapsedTime) })
|
|
966
|
+
] }),
|
|
574
967
|
displayedAssignment.testCase.description && /* @__PURE__ */ jsx2("p", { className: "text-gray-500 text-xs mb-2", children: displayedAssignment.testCase.description }),
|
|
575
968
|
displayedAssignment.testCase.targetRoute && onNavigate && /* @__PURE__ */ jsxs(
|
|
576
969
|
"button",
|
|
@@ -747,7 +1140,345 @@ function BugBearPanel({
|
|
|
747
1140
|
] })
|
|
748
1141
|
] })
|
|
749
1142
|
) : null }),
|
|
750
|
-
activeTab === "
|
|
1143
|
+
activeTab === "session" && /* @__PURE__ */ jsx2("div", { children: !activeSession ? (
|
|
1144
|
+
/* Start Session View */
|
|
1145
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1146
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
|
|
1147
|
+
/* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F50D}" }),
|
|
1148
|
+
/* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900 mt-2", children: "Exploratory QA Session" }),
|
|
1149
|
+
/* @__PURE__ */ jsx2("p", { className: "text-gray-500 text-xs mt-1", children: "Explore freely and capture findings as you go" })
|
|
1150
|
+
] }),
|
|
1151
|
+
focusAreas.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
1152
|
+
/* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: [
|
|
1153
|
+
"\u{1F4CC} Focus Areas",
|
|
1154
|
+
/* @__PURE__ */ jsx2("span", { className: "ml-1 text-[10px] text-gray-500 font-normal", children: "from your team" })
|
|
1155
|
+
] }),
|
|
1156
|
+
/* @__PURE__ */ jsx2("div", { className: "space-y-1.5", children: focusAreas.map((area) => /* @__PURE__ */ jsxs(
|
|
1157
|
+
"button",
|
|
1158
|
+
{
|
|
1159
|
+
onClick: () => setSessionFocusArea(area.name),
|
|
1160
|
+
className: `w-full text-left px-3 py-2 rounded-lg text-xs transition-colors border ${sessionFocusArea === area.name ? "bg-amber-50 border-amber-300 text-amber-700" : "bg-amber-50/50 border-amber-200 text-gray-700 hover:bg-amber-50"}`,
|
|
1161
|
+
children: [
|
|
1162
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1163
|
+
/* @__PURE__ */ jsx2("span", { className: "font-medium", children: area.name }),
|
|
1164
|
+
/* @__PURE__ */ jsx2("span", { className: `text-[10px] px-1.5 py-0.5 rounded ${area.priority >= 70 ? "bg-red-100 text-red-600" : area.priority >= 50 ? "bg-amber-100 text-amber-600" : "bg-gray-100 text-gray-500"}`, children: area.priority >= 70 ? "Urgent" : area.priority >= 50 ? "Important" : "Suggested" })
|
|
1165
|
+
] }),
|
|
1166
|
+
area.description && /* @__PURE__ */ jsx2("p", { className: "text-[10px] text-gray-500 mt-0.5 line-clamp-2", children: area.description })
|
|
1167
|
+
]
|
|
1168
|
+
},
|
|
1169
|
+
area.id
|
|
1170
|
+
)) })
|
|
1171
|
+
] }),
|
|
1172
|
+
suggestedRoutes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
1173
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: "\u{1F3AF} Suggested Routes to Explore" }),
|
|
1174
|
+
/* @__PURE__ */ jsx2("div", { className: "space-y-1.5 max-h-32 overflow-y-auto", children: suggestedRoutes.map((suggestion, idx) => /* @__PURE__ */ jsx2(
|
|
1175
|
+
"button",
|
|
1176
|
+
{
|
|
1177
|
+
onClick: () => setSessionFocusArea(suggestion.route),
|
|
1178
|
+
className: `w-full text-left px-3 py-2 rounded-lg text-xs transition-colors border ${sessionFocusArea === suggestion.route ? "bg-purple-50 border-purple-300 text-purple-700" : "bg-gray-50 border-gray-200 text-gray-700 hover:bg-gray-100"}`,
|
|
1179
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1180
|
+
/* @__PURE__ */ jsx2("span", { className: "font-medium truncate", children: suggestion.route }),
|
|
1181
|
+
/* @__PURE__ */ jsx2("span", { className: `text-[10px] px-1.5 py-0.5 rounded ${suggestion.priorityScore >= 40 ? "bg-red-100 text-red-600" : suggestion.priorityScore >= 25 ? "bg-amber-100 text-amber-600" : "bg-gray-100 text-gray-500"}`, children: suggestion.reason })
|
|
1182
|
+
] })
|
|
1183
|
+
},
|
|
1184
|
+
idx
|
|
1185
|
+
)) })
|
|
1186
|
+
] }),
|
|
1187
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
1188
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Focus Area (optional)" }),
|
|
1189
|
+
/* @__PURE__ */ jsx2(
|
|
1190
|
+
"input",
|
|
1191
|
+
{
|
|
1192
|
+
type: "text",
|
|
1193
|
+
value: sessionFocusArea,
|
|
1194
|
+
onChange: (e) => setSessionFocusArea(e.target.value),
|
|
1195
|
+
placeholder: "e.g., checkout flow, settings page",
|
|
1196
|
+
className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
|
|
1197
|
+
}
|
|
1198
|
+
)
|
|
1199
|
+
] }),
|
|
1200
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
1201
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Platform" }),
|
|
1202
|
+
/* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: [
|
|
1203
|
+
{ key: "web", label: "\u{1F310} Web" },
|
|
1204
|
+
{ key: "ios", label: "\u{1F4F1} iOS" },
|
|
1205
|
+
{ key: "android", label: "\u{1F916} Android" }
|
|
1206
|
+
].map(({ key, label }) => /* @__PURE__ */ jsx2(
|
|
1207
|
+
"button",
|
|
1208
|
+
{
|
|
1209
|
+
onClick: () => setSessionPlatform(key),
|
|
1210
|
+
className: `flex-1 py-2 px-3 rounded-lg text-xs font-medium transition-colors border-2 ${sessionPlatform === key ? "bg-purple-50 border-purple-500 text-purple-700" : "bg-gray-50 border-transparent text-gray-600 hover:bg-gray-100"}`,
|
|
1211
|
+
children: label
|
|
1212
|
+
},
|
|
1213
|
+
key
|
|
1214
|
+
)) })
|
|
1215
|
+
] }),
|
|
1216
|
+
/* @__PURE__ */ jsx2(
|
|
1217
|
+
"button",
|
|
1218
|
+
{
|
|
1219
|
+
onClick: handleStartSession,
|
|
1220
|
+
disabled: startingSession,
|
|
1221
|
+
className: "w-full py-3 px-4 bg-green-600 text-white rounded-lg font-semibold text-sm hover:bg-green-700 disabled:opacity-50 transition-colors flex items-center justify-center gap-2",
|
|
1222
|
+
children: startingSession ? "Starting..." : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1223
|
+
/* @__PURE__ */ jsx2("span", { children: "\u25B6" }),
|
|
1224
|
+
" Start Session"
|
|
1225
|
+
] })
|
|
1226
|
+
}
|
|
1227
|
+
)
|
|
1228
|
+
] })
|
|
1229
|
+
) : showEndConfirm ? (
|
|
1230
|
+
/* End Session Confirmation */
|
|
1231
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1232
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
|
|
1233
|
+
/* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u270B" }),
|
|
1234
|
+
/* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900 mt-2", children: "End Session?" }),
|
|
1235
|
+
/* @__PURE__ */ jsxs("p", { className: "text-gray-500 text-xs mt-1", children: [
|
|
1236
|
+
"Duration: ",
|
|
1237
|
+
formatElapsedTime(sessionElapsedTime),
|
|
1238
|
+
" \u2022 ",
|
|
1239
|
+
sessionFindings.length,
|
|
1240
|
+
" finding",
|
|
1241
|
+
sessionFindings.length !== 1 ? "s" : ""
|
|
1242
|
+
] })
|
|
1243
|
+
] }),
|
|
1244
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
1245
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Session Notes (optional)" }),
|
|
1246
|
+
/* @__PURE__ */ jsx2(
|
|
1247
|
+
"textarea",
|
|
1248
|
+
{
|
|
1249
|
+
value: sessionNotes,
|
|
1250
|
+
onChange: (e) => setSessionNotes(e.target.value),
|
|
1251
|
+
placeholder: "Any overall observations from this session...",
|
|
1252
|
+
rows: 3,
|
|
1253
|
+
className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none"
|
|
1254
|
+
}
|
|
1255
|
+
)
|
|
1256
|
+
] }),
|
|
1257
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1258
|
+
/* @__PURE__ */ jsx2(
|
|
1259
|
+
"button",
|
|
1260
|
+
{
|
|
1261
|
+
onClick: () => setShowEndConfirm(false),
|
|
1262
|
+
className: "flex-1 py-2 px-3 bg-gray-100 text-gray-700 rounded-lg font-medium text-sm hover:bg-gray-200 transition-colors",
|
|
1263
|
+
children: "Cancel"
|
|
1264
|
+
}
|
|
1265
|
+
),
|
|
1266
|
+
/* @__PURE__ */ jsx2(
|
|
1267
|
+
"button",
|
|
1268
|
+
{
|
|
1269
|
+
onClick: handleEndSession,
|
|
1270
|
+
disabled: endingSession,
|
|
1271
|
+
className: "flex-1 py-2 px-3 bg-red-600 text-white rounded-lg font-medium text-sm hover:bg-red-700 disabled:opacity-50 transition-colors",
|
|
1272
|
+
children: endingSession ? "Ending..." : "End Session"
|
|
1273
|
+
}
|
|
1274
|
+
)
|
|
1275
|
+
] })
|
|
1276
|
+
] })
|
|
1277
|
+
) : showAddFinding ? (
|
|
1278
|
+
/* Add Finding Form */
|
|
1279
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1280
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
1281
|
+
/* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900 text-sm", children: "Add Finding" }),
|
|
1282
|
+
/* @__PURE__ */ jsx2(
|
|
1283
|
+
"button",
|
|
1284
|
+
{
|
|
1285
|
+
onClick: () => setShowAddFinding(false),
|
|
1286
|
+
className: "text-gray-400 hover:text-gray-600",
|
|
1287
|
+
children: "\u2715"
|
|
1288
|
+
}
|
|
1289
|
+
)
|
|
1290
|
+
] }),
|
|
1291
|
+
/* @__PURE__ */ jsx2("div", { className: "flex gap-1 mb-3", children: [
|
|
1292
|
+
{ type: "bug", label: "\u{1F41B} Bug", color: "red" },
|
|
1293
|
+
{ type: "concern", label: "\u26A0\uFE0F Concern", color: "orange" },
|
|
1294
|
+
{ type: "suggestion", label: "\u{1F4A1} Idea", color: "blue" },
|
|
1295
|
+
{ type: "question", label: "\u2753 Question", color: "purple" }
|
|
1296
|
+
].map(({ type, label, color }) => /* @__PURE__ */ jsx2(
|
|
1297
|
+
"button",
|
|
1298
|
+
{
|
|
1299
|
+
onClick: () => setFindingType(type),
|
|
1300
|
+
className: `flex-1 py-1.5 px-2 rounded text-xs font-medium transition-colors ${findingType === type ? color === "red" ? "bg-red-100 text-red-700 ring-2 ring-red-400" : color === "orange" ? "bg-orange-100 text-orange-700 ring-2 ring-orange-400" : color === "blue" ? "bg-blue-100 text-blue-700 ring-2 ring-blue-400" : "bg-purple-100 text-purple-700 ring-2 ring-purple-400" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
1301
|
+
children: label
|
|
1302
|
+
},
|
|
1303
|
+
type
|
|
1304
|
+
)) }),
|
|
1305
|
+
findingType === "bug" && /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
1306
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Severity" }),
|
|
1307
|
+
/* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low", "observation"].map((sev) => /* @__PURE__ */ jsx2(
|
|
1308
|
+
"button",
|
|
1309
|
+
{
|
|
1310
|
+
onClick: () => setFindingSeverity(sev),
|
|
1311
|
+
className: `flex-1 py-1 px-1 rounded text-xs font-medium capitalize transition-colors ${findingSeverity === sev ? sev === "critical" ? "bg-red-600 text-white" : sev === "high" ? "bg-orange-500 text-white" : sev === "medium" ? "bg-yellow-500 text-black" : sev === "low" ? "bg-gray-500 text-white" : "bg-blue-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
1312
|
+
children: sev === "observation" ? "obs" : sev
|
|
1313
|
+
},
|
|
1314
|
+
sev
|
|
1315
|
+
)) })
|
|
1316
|
+
] }),
|
|
1317
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
1318
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Title *" }),
|
|
1319
|
+
/* @__PURE__ */ jsx2(
|
|
1320
|
+
"input",
|
|
1321
|
+
{
|
|
1322
|
+
type: "text",
|
|
1323
|
+
value: findingTitle,
|
|
1324
|
+
onChange: (e) => setFindingTitle(e.target.value),
|
|
1325
|
+
placeholder: "Brief description of what you found",
|
|
1326
|
+
className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
|
|
1327
|
+
}
|
|
1328
|
+
)
|
|
1329
|
+
] }),
|
|
1330
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
1331
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Details (optional)" }),
|
|
1332
|
+
/* @__PURE__ */ jsx2(
|
|
1333
|
+
"textarea",
|
|
1334
|
+
{
|
|
1335
|
+
value: findingDescription,
|
|
1336
|
+
onChange: (e) => setFindingDescription(e.target.value),
|
|
1337
|
+
placeholder: "Steps to reproduce, expected behavior, etc.",
|
|
1338
|
+
rows: 2,
|
|
1339
|
+
className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none"
|
|
1340
|
+
}
|
|
1341
|
+
)
|
|
1342
|
+
] }),
|
|
1343
|
+
/* @__PURE__ */ jsx2(
|
|
1344
|
+
"button",
|
|
1345
|
+
{
|
|
1346
|
+
onClick: handleAddFinding,
|
|
1347
|
+
disabled: addingFinding || !findingTitle.trim(),
|
|
1348
|
+
className: "w-full py-2 px-4 bg-purple-600 text-white rounded-lg font-medium text-sm hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
1349
|
+
children: addingFinding ? "Adding..." : "Add Finding"
|
|
1350
|
+
}
|
|
1351
|
+
)
|
|
1352
|
+
] })
|
|
1353
|
+
) : (
|
|
1354
|
+
/* Active Session View */
|
|
1355
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1356
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-green-50 rounded-lg p-3 mb-3 border border-green-200", children: [
|
|
1357
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1358
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1359
|
+
/* @__PURE__ */ jsx2("span", { className: "w-2 h-2 bg-green-500 rounded-full animate-pulse" }),
|
|
1360
|
+
/* @__PURE__ */ jsx2("span", { className: "font-medium text-green-800 text-sm", children: "Session Active" })
|
|
1361
|
+
] }),
|
|
1362
|
+
/* @__PURE__ */ jsx2("span", { className: "font-mono text-green-700 text-lg font-semibold", children: formatElapsedTime(sessionElapsedTime) })
|
|
1363
|
+
] }),
|
|
1364
|
+
activeSession.focusArea && /* @__PURE__ */ jsxs("p", { className: "text-green-700 text-xs mt-1", children: [
|
|
1365
|
+
"Focus: ",
|
|
1366
|
+
activeSession.focusArea
|
|
1367
|
+
] })
|
|
1368
|
+
] }),
|
|
1369
|
+
/* @__PURE__ */ jsxs(
|
|
1370
|
+
"button",
|
|
1371
|
+
{
|
|
1372
|
+
onClick: () => setShowAddFinding(true),
|
|
1373
|
+
className: "w-full py-3 px-4 bg-purple-600 text-white rounded-lg font-semibold text-sm hover:bg-purple-700 transition-colors flex items-center justify-center gap-2 mb-3",
|
|
1374
|
+
children: [
|
|
1375
|
+
/* @__PURE__ */ jsx2("span", { children: "+" }),
|
|
1376
|
+
" Add Finding"
|
|
1377
|
+
]
|
|
1378
|
+
}
|
|
1379
|
+
),
|
|
1380
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
1381
|
+
/* @__PURE__ */ jsx2("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-500", children: [
|
|
1382
|
+
"Findings (",
|
|
1383
|
+
sessionFindings.length,
|
|
1384
|
+
")"
|
|
1385
|
+
] }) }),
|
|
1386
|
+
sessionFindings.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-4 bg-gray-50 rounded-lg", children: [
|
|
1387
|
+
/* @__PURE__ */ jsx2("p", { className: "text-gray-400 text-xs", children: "No findings yet" }),
|
|
1388
|
+
/* @__PURE__ */ jsx2("p", { className: "text-gray-400 text-xs", children: "Explore and add findings as you go" })
|
|
1389
|
+
] }) : /* @__PURE__ */ jsx2("div", { className: "space-y-2 max-h-32 overflow-y-auto", children: sessionFindings.map((finding) => /* @__PURE__ */ jsx2(
|
|
1390
|
+
"div",
|
|
1391
|
+
{
|
|
1392
|
+
className: `p-2 rounded-lg border text-xs ${finding.type === "bug" ? "bg-red-50 border-red-200" : finding.type === "concern" ? "bg-orange-50 border-orange-200" : finding.type === "suggestion" ? "bg-blue-50 border-blue-200" : "bg-purple-50 border-purple-200"}`,
|
|
1393
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
1394
|
+
/* @__PURE__ */ jsx2("span", { children: finding.type === "bug" ? "\u{1F41B}" : finding.type === "concern" ? "\u26A0\uFE0F" : finding.type === "suggestion" ? "\u{1F4A1}" : "\u2753" }),
|
|
1395
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
1396
|
+
/* @__PURE__ */ jsx2("p", { className: "font-medium text-gray-900 truncate", children: finding.title }),
|
|
1397
|
+
finding.severity && finding.type === "bug" && /* @__PURE__ */ jsx2("span", { className: `inline-block mt-0.5 px-1 py-0.5 rounded text-[10px] font-medium ${finding.severity === "critical" ? "bg-red-200 text-red-800" : finding.severity === "high" ? "bg-orange-200 text-orange-800" : finding.severity === "medium" ? "bg-yellow-200 text-yellow-800" : "bg-gray-200 text-gray-700"}`, children: finding.severity })
|
|
1398
|
+
] })
|
|
1399
|
+
] })
|
|
1400
|
+
},
|
|
1401
|
+
finding.id
|
|
1402
|
+
)) })
|
|
1403
|
+
] }),
|
|
1404
|
+
/* @__PURE__ */ jsx2(
|
|
1405
|
+
"button",
|
|
1406
|
+
{
|
|
1407
|
+
onClick: () => setShowEndConfirm(true),
|
|
1408
|
+
className: "w-full py-2 px-4 bg-gray-100 text-gray-700 rounded-lg font-medium text-sm hover:bg-gray-200 transition-colors",
|
|
1409
|
+
children: "End Session"
|
|
1410
|
+
}
|
|
1411
|
+
)
|
|
1412
|
+
] })
|
|
1413
|
+
) }),
|
|
1414
|
+
activeTab === "report" && /* @__PURE__ */ jsx2("div", { children: submitted ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
|
|
1415
|
+
/* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F389}" }),
|
|
1416
|
+
/* @__PURE__ */ jsx2("p", { className: "text-gray-600 mt-2 font-medium", children: "Report submitted!" })
|
|
1417
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1418
|
+
/* @__PURE__ */ jsx2("div", { className: "flex gap-2 mb-4", children: [
|
|
1419
|
+
{ type: "bug", label: "\u{1F41B} Bug", color: "red" },
|
|
1420
|
+
{ type: "feedback", label: "\u{1F4A1} Feedback", color: "blue" },
|
|
1421
|
+
{ type: "suggestion", label: "\u2728 Idea", color: "purple" }
|
|
1422
|
+
].map(({ type, label, color }) => /* @__PURE__ */ jsx2(
|
|
1423
|
+
"button",
|
|
1424
|
+
{
|
|
1425
|
+
onClick: () => setReportType(type),
|
|
1426
|
+
className: `flex-1 py-1.5 px-2 rounded-lg text-xs font-medium transition-colors ${reportType === type ? color === "red" ? "bg-red-100 text-red-700 ring-2 ring-red-500" : color === "blue" ? "bg-blue-100 text-blue-700 ring-2 ring-blue-500" : "bg-purple-100 text-purple-700 ring-2 ring-purple-500" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
1427
|
+
children: label
|
|
1428
|
+
},
|
|
1429
|
+
type
|
|
1430
|
+
)) }),
|
|
1431
|
+
(reportType === "bug" || reportType === "test_fail") && /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
1432
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Severity" }),
|
|
1433
|
+
/* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low"].map((sev) => /* @__PURE__ */ jsx2(
|
|
1434
|
+
"button",
|
|
1435
|
+
{
|
|
1436
|
+
onClick: () => setSeverity(sev),
|
|
1437
|
+
className: `flex-1 py-1 px-2 rounded text-xs font-medium capitalize transition-colors ${severity === sev ? sev === "critical" ? "bg-red-600 text-white" : sev === "high" ? "bg-orange-500 text-white" : sev === "medium" ? "bg-yellow-500 text-black" : "bg-gray-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
1438
|
+
children: sev
|
|
1439
|
+
},
|
|
1440
|
+
sev
|
|
1441
|
+
)) })
|
|
1442
|
+
] }),
|
|
1443
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
1444
|
+
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "What happened?" }),
|
|
1445
|
+
/* @__PURE__ */ jsx2(
|
|
1446
|
+
"textarea",
|
|
1447
|
+
{
|
|
1448
|
+
value: description,
|
|
1449
|
+
onChange: (e) => setDescription(e.target.value),
|
|
1450
|
+
placeholder: "Describe the issue...",
|
|
1451
|
+
rows: 3,
|
|
1452
|
+
className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none"
|
|
1453
|
+
}
|
|
1454
|
+
)
|
|
1455
|
+
] }),
|
|
1456
|
+
/* @__PURE__ */ jsx2(
|
|
1457
|
+
"button",
|
|
1458
|
+
{
|
|
1459
|
+
onClick: handleSubmitReport,
|
|
1460
|
+
disabled: submitting || !description.trim(),
|
|
1461
|
+
className: "w-full py-2 px-4 bg-purple-600 text-white rounded-lg font-medium text-sm hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
1462
|
+
children: submitting ? "Submitting..." : "Submit Report"
|
|
1463
|
+
}
|
|
1464
|
+
)
|
|
1465
|
+
] }) })
|
|
1466
|
+
] }),
|
|
1467
|
+
showProfileOverlay && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 bg-white z-50 flex flex-col rounded-xl overflow-hidden", children: [
|
|
1468
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-purple-600 text-white px-4 py-3 flex items-center justify-between", children: [
|
|
1469
|
+
/* @__PURE__ */ jsx2(
|
|
1470
|
+
"button",
|
|
1471
|
+
{
|
|
1472
|
+
onClick: handleCloseProfile,
|
|
1473
|
+
className: "text-sm text-purple-200 hover:text-white transition-colors",
|
|
1474
|
+
children: "\u2190 Back"
|
|
1475
|
+
}
|
|
1476
|
+
),
|
|
1477
|
+
/* @__PURE__ */ jsx2("span", { className: "font-semibold text-sm", children: "Profile" }),
|
|
1478
|
+
/* @__PURE__ */ jsx2("div", { className: "w-12" }),
|
|
1479
|
+
" "
|
|
1480
|
+
] }),
|
|
1481
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-y-auto p-4", children: profileSaved ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
|
|
751
1482
|
/* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u2705" }),
|
|
752
1483
|
/* @__PURE__ */ jsx2("p", { className: "text-gray-600 mt-2 font-medium", children: "Profile saved!" })
|
|
753
1484
|
] }) : profileEditing ? (
|
|
@@ -890,59 +1621,7 @@ function BugBearPanel({
|
|
|
890
1621
|
}
|
|
891
1622
|
)
|
|
892
1623
|
] })
|
|
893
|
-
) })
|
|
894
|
-
activeTab === "report" && /* @__PURE__ */ jsx2("div", { children: submitted ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
|
|
895
|
-
/* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F389}" }),
|
|
896
|
-
/* @__PURE__ */ jsx2("p", { className: "text-gray-600 mt-2 font-medium", children: "Report submitted!" })
|
|
897
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
898
|
-
/* @__PURE__ */ jsx2("div", { className: "flex gap-2 mb-4", children: [
|
|
899
|
-
{ type: "bug", label: "\u{1F41B} Bug", color: "red" },
|
|
900
|
-
{ type: "feedback", label: "\u{1F4A1} Feedback", color: "blue" },
|
|
901
|
-
{ type: "suggestion", label: "\u2728 Idea", color: "purple" }
|
|
902
|
-
].map(({ type, label, color }) => /* @__PURE__ */ jsx2(
|
|
903
|
-
"button",
|
|
904
|
-
{
|
|
905
|
-
onClick: () => setReportType(type),
|
|
906
|
-
className: `flex-1 py-1.5 px-2 rounded-lg text-xs font-medium transition-colors ${reportType === type ? color === "red" ? "bg-red-100 text-red-700 ring-2 ring-red-500" : color === "blue" ? "bg-blue-100 text-blue-700 ring-2 ring-blue-500" : "bg-purple-100 text-purple-700 ring-2 ring-purple-500" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
907
|
-
children: label
|
|
908
|
-
},
|
|
909
|
-
type
|
|
910
|
-
)) }),
|
|
911
|
-
(reportType === "bug" || reportType === "test_fail") && /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
912
|
-
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Severity" }),
|
|
913
|
-
/* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low"].map((sev) => /* @__PURE__ */ jsx2(
|
|
914
|
-
"button",
|
|
915
|
-
{
|
|
916
|
-
onClick: () => setSeverity(sev),
|
|
917
|
-
className: `flex-1 py-1 px-2 rounded text-xs font-medium capitalize transition-colors ${severity === sev ? sev === "critical" ? "bg-red-600 text-white" : sev === "high" ? "bg-orange-500 text-white" : sev === "medium" ? "bg-yellow-500 text-black" : "bg-gray-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
918
|
-
children: sev
|
|
919
|
-
},
|
|
920
|
-
sev
|
|
921
|
-
)) })
|
|
922
|
-
] }),
|
|
923
|
-
/* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
|
|
924
|
-
/* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "What happened?" }),
|
|
925
|
-
/* @__PURE__ */ jsx2(
|
|
926
|
-
"textarea",
|
|
927
|
-
{
|
|
928
|
-
value: description,
|
|
929
|
-
onChange: (e) => setDescription(e.target.value),
|
|
930
|
-
placeholder: "Describe the issue...",
|
|
931
|
-
rows: 3,
|
|
932
|
-
className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none"
|
|
933
|
-
}
|
|
934
|
-
)
|
|
935
|
-
] }),
|
|
936
|
-
/* @__PURE__ */ jsx2(
|
|
937
|
-
"button",
|
|
938
|
-
{
|
|
939
|
-
onClick: handleSubmitReport,
|
|
940
|
-
disabled: submitting || !description.trim(),
|
|
941
|
-
className: "w-full py-2 px-4 bg-purple-600 text-white rounded-lg font-medium text-sm hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
942
|
-
children: submitting ? "Submitting..." : "Submit Report"
|
|
943
|
-
}
|
|
944
|
-
)
|
|
945
|
-
] }) })
|
|
1624
|
+
) })
|
|
946
1625
|
] }),
|
|
947
1626
|
/* @__PURE__ */ jsxs("div", { className: "px-4 py-2 bg-gray-50 border-t border-gray-200 flex items-center justify-between text-xs text-gray-400", children: [
|
|
948
1627
|
/* @__PURE__ */ jsxs("span", { children: [
|