@bbearai/react-native 0.4.0 → 0.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/dist/index.js +133 -33
- package/dist/index.mjs +138 -38
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -11393,7 +11393,7 @@ function shouldShowDeprecationWarning() {
|
|
|
11393
11393
|
}
|
|
11394
11394
|
if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
|
|
11395
11395
|
|
|
11396
|
-
//
|
|
11396
|
+
// node_modules/@bbearai/core/dist/index.mjs
|
|
11397
11397
|
var MAX_CONSOLE_LOGS = 50;
|
|
11398
11398
|
var MAX_NETWORK_REQUESTS = 20;
|
|
11399
11399
|
var MAX_NAVIGATION_HISTORY = 20;
|
|
@@ -11634,6 +11634,11 @@ function captureError(error, errorInfo) {
|
|
|
11634
11634
|
componentStack: errorInfo?.componentStack
|
|
11635
11635
|
};
|
|
11636
11636
|
}
|
|
11637
|
+
var formatPgError = (e) => {
|
|
11638
|
+
if (!e || typeof e !== "object") return { raw: e };
|
|
11639
|
+
const { message, code, details, hint } = e;
|
|
11640
|
+
return { message, code, details, hint };
|
|
11641
|
+
};
|
|
11637
11642
|
var DEFAULT_SUPABASE_URL = "https://kyxgzjnqgvapvlnvqawz.supabase.co";
|
|
11638
11643
|
var getEnvVar = (key) => {
|
|
11639
11644
|
try {
|
|
@@ -11803,7 +11808,7 @@ var BugBearClient = class {
|
|
|
11803
11808
|
)
|
|
11804
11809
|
`).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).limit(100);
|
|
11805
11810
|
if (error) {
|
|
11806
|
-
console.error("BugBear: Failed to fetch assignments", error);
|
|
11811
|
+
console.error("BugBear: Failed to fetch assignments", formatPgError(error));
|
|
11807
11812
|
return [];
|
|
11808
11813
|
}
|
|
11809
11814
|
const mapped = (data || []).map((item) => ({
|
|
@@ -12031,7 +12036,7 @@ var BugBearClient = class {
|
|
|
12031
12036
|
}
|
|
12032
12037
|
const { error } = await this.supabase.from("test_assignments").update(updateData).eq("id", assignmentId);
|
|
12033
12038
|
if (error) {
|
|
12034
|
-
console.error("BugBear: Failed to skip assignment", error);
|
|
12039
|
+
console.error("BugBear: Failed to skip assignment", formatPgError(error));
|
|
12035
12040
|
return { success: false, error: error.message };
|
|
12036
12041
|
}
|
|
12037
12042
|
return { success: true };
|
|
@@ -12210,7 +12215,7 @@ var BugBearClient = class {
|
|
|
12210
12215
|
p_tester_id: testerInfo.id
|
|
12211
12216
|
});
|
|
12212
12217
|
if (error) {
|
|
12213
|
-
console.error("BugBear: Failed to fetch tester stats", error);
|
|
12218
|
+
console.error("BugBear: Failed to fetch tester stats", formatPgError(error));
|
|
12214
12219
|
return null;
|
|
12215
12220
|
}
|
|
12216
12221
|
return data;
|
|
@@ -12361,7 +12366,7 @@ var BugBearClient = class {
|
|
|
12361
12366
|
if (updates.platforms !== void 0) updateData.platforms = updates.platforms;
|
|
12362
12367
|
const { error } = await this.supabase.from("testers").update(updateData).eq("id", testerInfo.id);
|
|
12363
12368
|
if (error) {
|
|
12364
|
-
console.error("BugBear: updateTesterProfile error", error);
|
|
12369
|
+
console.error("BugBear: updateTesterProfile error", formatPgError(error));
|
|
12365
12370
|
return { success: false, error: error.message };
|
|
12366
12371
|
}
|
|
12367
12372
|
return { success: true };
|
|
@@ -12383,14 +12388,14 @@ var BugBearClient = class {
|
|
|
12383
12388
|
*/
|
|
12384
12389
|
async isQAEnabled() {
|
|
12385
12390
|
try {
|
|
12386
|
-
const { data, error } = await this.supabase.
|
|
12391
|
+
const { data, error } = await this.supabase.rpc("check_qa_enabled", {
|
|
12392
|
+
p_project_id: this.config.projectId
|
|
12393
|
+
});
|
|
12387
12394
|
if (error) {
|
|
12388
|
-
|
|
12389
|
-
console.warn("BugBear: Could not check QA status", error.message || error.code || "Unknown error");
|
|
12390
|
-
}
|
|
12395
|
+
console.warn("BugBear: Could not check QA status", error.message || error.code || "Unknown error");
|
|
12391
12396
|
return true;
|
|
12392
12397
|
}
|
|
12393
|
-
return data
|
|
12398
|
+
return data ?? true;
|
|
12394
12399
|
} catch (err) {
|
|
12395
12400
|
return true;
|
|
12396
12401
|
}
|
|
@@ -12420,7 +12425,7 @@ var BugBearClient = class {
|
|
|
12420
12425
|
upsert: false
|
|
12421
12426
|
});
|
|
12422
12427
|
if (error) {
|
|
12423
|
-
console.error("BugBear: Failed to upload screenshot", error);
|
|
12428
|
+
console.error("BugBear: Failed to upload screenshot", formatPgError(error));
|
|
12424
12429
|
return null;
|
|
12425
12430
|
}
|
|
12426
12431
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
@@ -12451,7 +12456,7 @@ var BugBearClient = class {
|
|
|
12451
12456
|
upsert: false
|
|
12452
12457
|
});
|
|
12453
12458
|
if (error) {
|
|
12454
|
-
console.error("BugBear: Failed to upload image from URI", error);
|
|
12459
|
+
console.error("BugBear: Failed to upload image from URI", formatPgError(error));
|
|
12455
12460
|
return null;
|
|
12456
12461
|
}
|
|
12457
12462
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
@@ -12526,7 +12531,7 @@ var BugBearClient = class {
|
|
|
12526
12531
|
}
|
|
12527
12532
|
const { data, error } = await query;
|
|
12528
12533
|
if (error) {
|
|
12529
|
-
console.error("BugBear: Failed to fetch fix requests", error);
|
|
12534
|
+
console.error("BugBear: Failed to fetch fix requests", formatPgError(error));
|
|
12530
12535
|
return [];
|
|
12531
12536
|
}
|
|
12532
12537
|
return (data || []).map((fr) => ({
|
|
@@ -12557,7 +12562,7 @@ var BugBearClient = class {
|
|
|
12557
12562
|
p_tester_id: testerInfo.id
|
|
12558
12563
|
});
|
|
12559
12564
|
if (error) {
|
|
12560
|
-
console.error("BugBear: Failed to fetch threads via RPC", error);
|
|
12565
|
+
console.error("BugBear: Failed to fetch threads via RPC", formatPgError(error));
|
|
12561
12566
|
return [];
|
|
12562
12567
|
}
|
|
12563
12568
|
if (!data || data.length === 0) return [];
|
|
@@ -12601,7 +12606,7 @@ var BugBearClient = class {
|
|
|
12601
12606
|
attachments
|
|
12602
12607
|
`).eq("thread_id", threadId).order("created_at", { ascending: true }).limit(200);
|
|
12603
12608
|
if (error) {
|
|
12604
|
-
console.error("BugBear: Failed to fetch messages", error);
|
|
12609
|
+
console.error("BugBear: Failed to fetch messages", formatPgError(error));
|
|
12605
12610
|
return [];
|
|
12606
12611
|
}
|
|
12607
12612
|
return (data || []).map((msg) => ({
|
|
@@ -12645,7 +12650,7 @@ var BugBearClient = class {
|
|
|
12645
12650
|
}
|
|
12646
12651
|
const { error } = await this.supabase.from("discussion_messages").insert(insertData);
|
|
12647
12652
|
if (error) {
|
|
12648
|
-
console.error("BugBear: Failed to send message", error);
|
|
12653
|
+
console.error("BugBear: Failed to send message", formatPgError(error));
|
|
12649
12654
|
return false;
|
|
12650
12655
|
}
|
|
12651
12656
|
await this.markThreadAsRead(threadId);
|
|
@@ -12761,7 +12766,7 @@ var BugBearClient = class {
|
|
|
12761
12766
|
p_platform: options.platform || null
|
|
12762
12767
|
});
|
|
12763
12768
|
if (error) {
|
|
12764
|
-
console.error("BugBear: Failed to start session", error);
|
|
12769
|
+
console.error("BugBear: Failed to start session", formatPgError(error));
|
|
12765
12770
|
return { success: false, error: error.message };
|
|
12766
12771
|
}
|
|
12767
12772
|
const session = await this.getSession(data);
|
|
@@ -12786,7 +12791,7 @@ var BugBearClient = class {
|
|
|
12786
12791
|
p_routes_covered: options.routesCovered || null
|
|
12787
12792
|
});
|
|
12788
12793
|
if (error) {
|
|
12789
|
-
console.error("BugBear: Failed to end session", error);
|
|
12794
|
+
console.error("BugBear: Failed to end session", formatPgError(error));
|
|
12790
12795
|
return { success: false, error: error.message };
|
|
12791
12796
|
}
|
|
12792
12797
|
const session = this.transformSession(data);
|
|
@@ -12834,7 +12839,7 @@ var BugBearClient = class {
|
|
|
12834
12839
|
if (!testerInfo) return [];
|
|
12835
12840
|
const { data, error } = await this.supabase.from("qa_sessions").select("*").eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).order("started_at", { ascending: false }).limit(limit);
|
|
12836
12841
|
if (error) {
|
|
12837
|
-
console.error("BugBear: Failed to fetch session history", error);
|
|
12842
|
+
console.error("BugBear: Failed to fetch session history", formatPgError(error));
|
|
12838
12843
|
return [];
|
|
12839
12844
|
}
|
|
12840
12845
|
return (data || []).map((s) => this.transformSession(s));
|
|
@@ -12862,7 +12867,7 @@ var BugBearClient = class {
|
|
|
12862
12867
|
p_app_context: options.appContext || null
|
|
12863
12868
|
});
|
|
12864
12869
|
if (error) {
|
|
12865
|
-
console.error("BugBear: Failed to add finding", error);
|
|
12870
|
+
console.error("BugBear: Failed to add finding", formatPgError(error));
|
|
12866
12871
|
return { success: false, error: error.message };
|
|
12867
12872
|
}
|
|
12868
12873
|
const finding = this.transformFinding(data);
|
|
@@ -12880,7 +12885,7 @@ var BugBearClient = class {
|
|
|
12880
12885
|
try {
|
|
12881
12886
|
const { data, error } = await this.supabase.from("qa_findings").select("*").eq("session_id", sessionId).order("created_at", { ascending: true }).limit(100);
|
|
12882
12887
|
if (error) {
|
|
12883
|
-
console.error("BugBear: Failed to fetch findings", error);
|
|
12888
|
+
console.error("BugBear: Failed to fetch findings", formatPgError(error));
|
|
12884
12889
|
return [];
|
|
12885
12890
|
}
|
|
12886
12891
|
return (data || []).map((f) => this.transformFinding(f));
|
|
@@ -12898,7 +12903,7 @@ var BugBearClient = class {
|
|
|
12898
12903
|
p_finding_id: findingId
|
|
12899
12904
|
});
|
|
12900
12905
|
if (error) {
|
|
12901
|
-
console.error("BugBear: Failed to convert finding", error);
|
|
12906
|
+
console.error("BugBear: Failed to convert finding", formatPgError(error));
|
|
12902
12907
|
return { success: false, error: error.message };
|
|
12903
12908
|
}
|
|
12904
12909
|
return { success: true, bugId: data };
|
|
@@ -12919,7 +12924,7 @@ var BugBearClient = class {
|
|
|
12919
12924
|
dismissed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
12920
12925
|
}).eq("id", findingId);
|
|
12921
12926
|
if (error) {
|
|
12922
|
-
console.error("BugBear: Failed to dismiss finding", error);
|
|
12927
|
+
console.error("BugBear: Failed to dismiss finding", formatPgError(error));
|
|
12923
12928
|
return { success: false, error: error.message };
|
|
12924
12929
|
}
|
|
12925
12930
|
return { success: true };
|
|
@@ -13782,7 +13787,10 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13782
13787
|
import_react_native4.Keyboard.dismiss();
|
|
13783
13788
|
setIsSubmitting(true);
|
|
13784
13789
|
try {
|
|
13785
|
-
await client.failAssignment(displayedAssignment.id);
|
|
13790
|
+
const result = await client.failAssignment(displayedAssignment.id);
|
|
13791
|
+
if (!result.success) {
|
|
13792
|
+
console.error("BugBear: Failed to mark assignment as failed", result.error);
|
|
13793
|
+
}
|
|
13786
13794
|
await refreshAssignments();
|
|
13787
13795
|
nav.replace({
|
|
13788
13796
|
name: "REPORT",
|
|
@@ -14013,10 +14021,19 @@ var import_react_native5 = require("react-native");
|
|
|
14013
14021
|
function TestListScreen({ nav }) {
|
|
14014
14022
|
const { assignments, currentAssignment, refreshAssignments } = useBugBear();
|
|
14015
14023
|
const [filter, setFilter] = (0, import_react5.useState)("all");
|
|
14024
|
+
const [roleFilter, setRoleFilter] = (0, import_react5.useState)(null);
|
|
14016
14025
|
const [collapsedFolders, setCollapsedFolders] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
|
|
14017
14026
|
(0, import_react5.useEffect)(() => {
|
|
14018
14027
|
refreshAssignments();
|
|
14019
14028
|
}, []);
|
|
14029
|
+
const availableRoles = (0, import_react5.useMemo)(() => {
|
|
14030
|
+
const roleMap = /* @__PURE__ */ new Map();
|
|
14031
|
+
for (const a of assignments) {
|
|
14032
|
+
if (a.testCase.role) roleMap.set(a.testCase.role.id, a.testCase.role);
|
|
14033
|
+
}
|
|
14034
|
+
return Array.from(roleMap.values());
|
|
14035
|
+
}, [assignments]);
|
|
14036
|
+
const selectedRole = availableRoles.find((r) => r.id === roleFilter);
|
|
14020
14037
|
const groupedAssignments = (0, import_react5.useMemo)(() => {
|
|
14021
14038
|
const groups = /* @__PURE__ */ new Map();
|
|
14022
14039
|
for (const assignment of assignments) {
|
|
@@ -14060,16 +14077,39 @@ function TestListScreen({ nav }) {
|
|
|
14060
14077
|
});
|
|
14061
14078
|
}, []);
|
|
14062
14079
|
const filterAssignment = (a) => {
|
|
14080
|
+
if (roleFilter && a.testCase.role?.id !== roleFilter) return false;
|
|
14063
14081
|
if (filter === "pending") return a.status === "pending" || a.status === "in_progress";
|
|
14064
14082
|
if (filter === "completed") return a.status === "passed" || a.status === "failed";
|
|
14065
14083
|
return true;
|
|
14066
14084
|
};
|
|
14067
|
-
return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, null, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.filterBar }, ["all", "pending", "completed"].map((f) => /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { key: f, style: [styles3.filterBtn, filter === f && styles3.filterBtnActive], onPress: () => setFilter(f) }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.filterBtnText, filter === f && styles3.filterBtnTextActive] }, f === "all" ? `All (${assignments.length})` : f === "pending" ? `To Do (${assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length})` : `Done (${assignments.filter((a) => a.status === "passed" || a.status === "failed").length})`)))),
|
|
14085
|
+
return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, null, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.filterBar }, ["all", "pending", "completed"].map((f) => /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { key: f, style: [styles3.filterBtn, filter === f && styles3.filterBtnActive], onPress: () => setFilter(f) }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.filterBtnText, filter === f && styles3.filterBtnTextActive] }, f === "all" ? `All (${assignments.length})` : f === "pending" ? `To Do (${assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length})` : `Done (${assignments.filter((a) => a.status === "passed" || a.status === "failed").length})`)))), availableRoles.length >= 2 && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.roleSection }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles3.roleBar }, /* @__PURE__ */ import_react5.default.createElement(
|
|
14086
|
+
import_react_native5.TouchableOpacity,
|
|
14087
|
+
{
|
|
14088
|
+
style: [styles3.roleBtn, !roleFilter && styles3.roleBtnActive],
|
|
14089
|
+
onPress: () => setRoleFilter(null)
|
|
14090
|
+
},
|
|
14091
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.roleBtnText, !roleFilter && styles3.roleBtnTextActive] }, "All Roles")
|
|
14092
|
+
), availableRoles.map((role) => {
|
|
14093
|
+
const isActive = roleFilter === role.id;
|
|
14094
|
+
return /* @__PURE__ */ import_react5.default.createElement(
|
|
14095
|
+
import_react_native5.TouchableOpacity,
|
|
14096
|
+
{
|
|
14097
|
+
key: role.id,
|
|
14098
|
+
style: [
|
|
14099
|
+
styles3.roleBtn,
|
|
14100
|
+
isActive && { backgroundColor: role.color + "20", borderColor: role.color + "60", borderWidth: 1 }
|
|
14101
|
+
],
|
|
14102
|
+
onPress: () => setRoleFilter(isActive ? null : role.id)
|
|
14103
|
+
},
|
|
14104
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.roleDot, { backgroundColor: role.color }] }),
|
|
14105
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.roleBtnText, isActive && { color: role.color, fontWeight: "600" }] }, role.name)
|
|
14106
|
+
);
|
|
14107
|
+
})), selectedRole?.loginHint && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.loginHint, { backgroundColor: selectedRole.color + "10", borderColor: selectedRole.color + "30" }] }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.loginHintText }, "Log in as: ", selectedRole.loginHint))), groupedAssignments.map((folder) => {
|
|
14068
14108
|
const folderId = folder.group?.id || "ungrouped";
|
|
14069
14109
|
const isCollapsed = collapsedFolders.has(folderId);
|
|
14070
14110
|
const filtered = folder.assignments.filter(filterAssignment);
|
|
14071
14111
|
if (filtered.length === 0 && filter !== "all") return null;
|
|
14072
|
-
return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { key: folderId, style: styles3.folder }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles3.folderHeader, onPress: () => toggleFolder(folderId) }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderToggle }, isCollapsed ? "\u25B6" : "\u25BC"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderName }, folder.group?.name || "Ungrouped"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.folderProgress }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.folderProgressFill, { width: `${Math.round((folder.stats.passed + folder.stats.failed) / folder.stats.total * 100)}%` }] })), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderCount }, folder.stats.passed + folder.stats.failed, "/", folder.stats.total)), !isCollapsed && filtered.map((assignment) => {
|
|
14112
|
+
return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { key: folderId, style: styles3.folder }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles3.folderHeader, onPress: () => toggleFolder(folderId) }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderToggle }, isCollapsed ? "\u25B6" : "\u25BC"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderName, numberOfLines: 1 }, folder.group?.name || "Ungrouped"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.folderProgress }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.folderProgressFill, { width: `${folder.stats.total > 0 ? Math.round((folder.stats.passed + folder.stats.failed) / folder.stats.total * 100) : 0}%` }] })), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderCount }, folder.stats.passed + folder.stats.failed, "/", folder.stats.total)), !isCollapsed && filtered.map((assignment) => {
|
|
14073
14113
|
const badge = getStatusBadge(assignment.status);
|
|
14074
14114
|
const isCurrent = currentAssignment?.id === assignment.id;
|
|
14075
14115
|
return /* @__PURE__ */ import_react5.default.createElement(
|
|
@@ -14080,17 +14120,28 @@ function TestListScreen({ nav }) {
|
|
|
14080
14120
|
onPress: () => nav.push({ name: "TEST_DETAIL", testId: assignment.id })
|
|
14081
14121
|
},
|
|
14082
14122
|
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testBadge }, badge.icon),
|
|
14083
|
-
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testInfo }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.retestTag }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testMeta }, assignment.testCase.
|
|
14123
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testInfo }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.retestTag }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testMeta }, assignment.testCase.testKey, " \xB7 ", assignment.testCase.priority), assignment.testCase.role && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.roleBadgeRow }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testMeta }, " \xB7 "), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.roleBadgeDot, { backgroundColor: assignment.testCase.role.color }] }), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.testMeta, { color: assignment.testCase.role.color, fontWeight: "500" }] }, assignment.testCase.role.name))))
|
|
14084
14124
|
);
|
|
14085
14125
|
}));
|
|
14086
|
-
}), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.refreshText }, "\u21BB Refresh")));
|
|
14126
|
+
}), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.refreshText }, "\u21BB", " Refresh")));
|
|
14087
14127
|
}
|
|
14088
14128
|
var styles3 = import_react_native5.StyleSheet.create({
|
|
14089
|
-
filterBar: { flexDirection: "row", gap: 8, marginBottom:
|
|
14129
|
+
filterBar: { flexDirection: "row", gap: 8, marginBottom: 8 },
|
|
14090
14130
|
filterBtn: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 8, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border },
|
|
14091
14131
|
filterBtnActive: { backgroundColor: colors.blue, borderColor: colors.blue },
|
|
14092
14132
|
filterBtnText: { fontSize: 12, color: colors.textSecondary },
|
|
14093
14133
|
filterBtnTextActive: { color: "#fff", fontWeight: "600" },
|
|
14134
|
+
roleSection: { marginBottom: 12 },
|
|
14135
|
+
roleBar: { flexDirection: "row", marginBottom: 6 },
|
|
14136
|
+
roleBtn: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 6, marginRight: 6, borderWidth: 1, borderColor: "transparent" },
|
|
14137
|
+
roleBtnActive: { backgroundColor: colors.card, borderColor: colors.border },
|
|
14138
|
+
roleBtnText: { fontSize: 11, color: colors.textMuted },
|
|
14139
|
+
roleBtnTextActive: { color: colors.textPrimary, fontWeight: "600" },
|
|
14140
|
+
roleDot: { width: 6, height: 6, borderRadius: 3 },
|
|
14141
|
+
loginHint: { borderRadius: 6, padding: 8, borderWidth: 1 },
|
|
14142
|
+
loginHintText: { fontSize: 11, color: colors.textSecondary },
|
|
14143
|
+
roleBadgeRow: { flexDirection: "row", alignItems: "center", gap: 3 },
|
|
14144
|
+
roleBadgeDot: { width: 5, height: 5, borderRadius: 3 },
|
|
14094
14145
|
folder: { marginBottom: 12 },
|
|
14095
14146
|
folderHeader: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 8, paddingHorizontal: 4 },
|
|
14096
14147
|
folderToggle: { fontSize: 10, color: colors.textMuted, width: 14 },
|
|
@@ -14103,7 +14154,7 @@ var styles3 = import_react_native5.StyleSheet.create({
|
|
|
14103
14154
|
testBadge: { fontSize: 16, marginRight: 10, width: 20 },
|
|
14104
14155
|
testInfo: { flex: 1 },
|
|
14105
14156
|
testTitle: { fontSize: 14, color: colors.textPrimary, marginBottom: 2 },
|
|
14106
|
-
testMetaRow: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
14157
|
+
testMetaRow: { flexDirection: "row", alignItems: "center", gap: 6, flexWrap: "wrap" },
|
|
14107
14158
|
retestTag: { backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 4, paddingHorizontal: 5, paddingVertical: 1 },
|
|
14108
14159
|
retestTagText: { fontSize: 10, fontWeight: "600", color: "#fbbf24" },
|
|
14109
14160
|
testMeta: { fontSize: 11, color: colors.textDim },
|
|
@@ -14446,6 +14497,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14446
14497
|
const [submitting, setSubmitting] = (0, import_react10.useState)(false);
|
|
14447
14498
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
14448
14499
|
const images = useImageAttachments(uploadImage, 5, "screenshots");
|
|
14500
|
+
const isRetestFailure = prefill?.type === "test_fail";
|
|
14449
14501
|
const isBugType = reportType === "bug" || reportType === "test_fail";
|
|
14450
14502
|
const handleSubmit = async () => {
|
|
14451
14503
|
if (!client || !description.trim()) return;
|
|
@@ -14485,7 +14537,50 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14485
14537
|
setSubmitting(false);
|
|
14486
14538
|
}
|
|
14487
14539
|
};
|
|
14488
|
-
return /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, null, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style:
|
|
14540
|
+
return /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, null, isRetestFailure ? /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.retestBanner }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.retestIcon }, "\u{1F504}"), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, null, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.retestTitle }, "Bug Still Present"), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.retestSubtitle }, "The fix did not resolve this issue"))), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.section }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: shared.label }, "Severity"), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.severityRow }, [
|
|
14541
|
+
{ sev: "critical", color: "#ef4444" },
|
|
14542
|
+
{ sev: "high", color: "#f97316" },
|
|
14543
|
+
{ sev: "medium", color: "#eab308" },
|
|
14544
|
+
{ sev: "low", color: "#6b7280" }
|
|
14545
|
+
].map(({ sev, color }) => /* @__PURE__ */ import_react10.default.createElement(
|
|
14546
|
+
import_react_native9.TouchableOpacity,
|
|
14547
|
+
{
|
|
14548
|
+
key: sev,
|
|
14549
|
+
style: [styles7.sevButton, severity === sev && { backgroundColor: `${color}30`, borderColor: color }],
|
|
14550
|
+
onPress: () => setSeverity(sev)
|
|
14551
|
+
},
|
|
14552
|
+
/* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: [styles7.sevText, severity === sev && { color }] }, sev)
|
|
14553
|
+
)))), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.section }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: shared.label }, "What went wrong?"), /* @__PURE__ */ import_react10.default.createElement(
|
|
14554
|
+
import_react_native9.TextInput,
|
|
14555
|
+
{
|
|
14556
|
+
style: styles7.descInput,
|
|
14557
|
+
value: description,
|
|
14558
|
+
onChangeText: setDescription,
|
|
14559
|
+
placeholder: "Describe what you observed. What still doesn't work?",
|
|
14560
|
+
placeholderTextColor: colors.textMuted,
|
|
14561
|
+
multiline: true,
|
|
14562
|
+
numberOfLines: 4,
|
|
14563
|
+
textAlignVertical: "top"
|
|
14564
|
+
}
|
|
14565
|
+
)), /* @__PURE__ */ import_react10.default.createElement(
|
|
14566
|
+
ImagePickerButtons,
|
|
14567
|
+
{
|
|
14568
|
+
images: images.images,
|
|
14569
|
+
maxImages: 5,
|
|
14570
|
+
onPickGallery: images.pickFromGallery,
|
|
14571
|
+
onPickCamera: images.pickFromCamera,
|
|
14572
|
+
onRemove: images.removeImage,
|
|
14573
|
+
label: "Attachments (optional)"
|
|
14574
|
+
}
|
|
14575
|
+
), error && /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.errorBanner }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.errorText }, error)), /* @__PURE__ */ import_react10.default.createElement(
|
|
14576
|
+
import_react_native9.TouchableOpacity,
|
|
14577
|
+
{
|
|
14578
|
+
style: [shared.primaryButton, styles7.retestSubmitButton, (!description.trim() || submitting || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
|
|
14579
|
+
onPress: handleSubmit,
|
|
14580
|
+
disabled: !description.trim() || submitting || images.isUploading
|
|
14581
|
+
},
|
|
14582
|
+
/* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Failed Retest")
|
|
14583
|
+
)) : /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: shared.label }, "What are you reporting?"), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.typeRow }, [
|
|
14489
14584
|
{ type: "bug", label: "Bug", icon: "\u{1F41B}" },
|
|
14490
14585
|
{ type: "feedback", label: "Feedback", icon: "\u{1F4A1}" },
|
|
14491
14586
|
{ type: "suggestion", label: "Idea", icon: "\u2728" }
|
|
@@ -14550,7 +14645,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14550
14645
|
disabled: !description.trim() || submitting || images.isUploading
|
|
14551
14646
|
},
|
|
14552
14647
|
/* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Report")
|
|
14553
|
-
));
|
|
14648
|
+
)));
|
|
14554
14649
|
}
|
|
14555
14650
|
var styles7 = import_react_native9.StyleSheet.create({
|
|
14556
14651
|
typeRow: { flexDirection: "row", gap: 10, marginBottom: 20 },
|
|
@@ -14567,7 +14662,12 @@ var styles7 = import_react_native9.StyleSheet.create({
|
|
|
14567
14662
|
screenInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, fontSize: 13, color: colors.textPrimary },
|
|
14568
14663
|
screenHint: { fontSize: 11, color: colors.textMuted, marginTop: 4 },
|
|
14569
14664
|
errorBanner: { backgroundColor: "#7f1d1d", borderWidth: 1, borderColor: "#991b1b", borderRadius: 8, padding: 12, marginTop: 16 },
|
|
14570
|
-
errorText: { fontSize: 13, color: "#fca5a5", lineHeight: 18 }
|
|
14665
|
+
errorText: { fontSize: 13, color: "#fca5a5", lineHeight: 18 },
|
|
14666
|
+
retestBanner: { flexDirection: "row", alignItems: "center", gap: 10, backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 10, paddingVertical: 12, paddingHorizontal: 14, marginBottom: 20 },
|
|
14667
|
+
retestIcon: { fontSize: 16 },
|
|
14668
|
+
retestTitle: { fontSize: 15, fontWeight: "600", color: "#fbbf24", lineHeight: 20 },
|
|
14669
|
+
retestSubtitle: { fontSize: 12, color: "#d97706", lineHeight: 16 },
|
|
14670
|
+
retestSubmitButton: { backgroundColor: "#b45309" }
|
|
14571
14671
|
});
|
|
14572
14672
|
|
|
14573
14673
|
// src/widget/screens/ReportSuccessScreen.tsx
|
package/dist/index.mjs
CHANGED
|
@@ -11360,7 +11360,7 @@ function shouldShowDeprecationWarning() {
|
|
|
11360
11360
|
}
|
|
11361
11361
|
if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
|
|
11362
11362
|
|
|
11363
|
-
//
|
|
11363
|
+
// node_modules/@bbearai/core/dist/index.mjs
|
|
11364
11364
|
var MAX_CONSOLE_LOGS = 50;
|
|
11365
11365
|
var MAX_NETWORK_REQUESTS = 20;
|
|
11366
11366
|
var MAX_NAVIGATION_HISTORY = 20;
|
|
@@ -11601,6 +11601,11 @@ function captureError(error, errorInfo) {
|
|
|
11601
11601
|
componentStack: errorInfo?.componentStack
|
|
11602
11602
|
};
|
|
11603
11603
|
}
|
|
11604
|
+
var formatPgError = (e) => {
|
|
11605
|
+
if (!e || typeof e !== "object") return { raw: e };
|
|
11606
|
+
const { message, code, details, hint } = e;
|
|
11607
|
+
return { message, code, details, hint };
|
|
11608
|
+
};
|
|
11604
11609
|
var DEFAULT_SUPABASE_URL = "https://kyxgzjnqgvapvlnvqawz.supabase.co";
|
|
11605
11610
|
var getEnvVar = (key) => {
|
|
11606
11611
|
try {
|
|
@@ -11770,7 +11775,7 @@ var BugBearClient = class {
|
|
|
11770
11775
|
)
|
|
11771
11776
|
`).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).limit(100);
|
|
11772
11777
|
if (error) {
|
|
11773
|
-
console.error("BugBear: Failed to fetch assignments", error);
|
|
11778
|
+
console.error("BugBear: Failed to fetch assignments", formatPgError(error));
|
|
11774
11779
|
return [];
|
|
11775
11780
|
}
|
|
11776
11781
|
const mapped = (data || []).map((item) => ({
|
|
@@ -11998,7 +12003,7 @@ var BugBearClient = class {
|
|
|
11998
12003
|
}
|
|
11999
12004
|
const { error } = await this.supabase.from("test_assignments").update(updateData).eq("id", assignmentId);
|
|
12000
12005
|
if (error) {
|
|
12001
|
-
console.error("BugBear: Failed to skip assignment", error);
|
|
12006
|
+
console.error("BugBear: Failed to skip assignment", formatPgError(error));
|
|
12002
12007
|
return { success: false, error: error.message };
|
|
12003
12008
|
}
|
|
12004
12009
|
return { success: true };
|
|
@@ -12177,7 +12182,7 @@ var BugBearClient = class {
|
|
|
12177
12182
|
p_tester_id: testerInfo.id
|
|
12178
12183
|
});
|
|
12179
12184
|
if (error) {
|
|
12180
|
-
console.error("BugBear: Failed to fetch tester stats", error);
|
|
12185
|
+
console.error("BugBear: Failed to fetch tester stats", formatPgError(error));
|
|
12181
12186
|
return null;
|
|
12182
12187
|
}
|
|
12183
12188
|
return data;
|
|
@@ -12328,7 +12333,7 @@ var BugBearClient = class {
|
|
|
12328
12333
|
if (updates.platforms !== void 0) updateData.platforms = updates.platforms;
|
|
12329
12334
|
const { error } = await this.supabase.from("testers").update(updateData).eq("id", testerInfo.id);
|
|
12330
12335
|
if (error) {
|
|
12331
|
-
console.error("BugBear: updateTesterProfile error", error);
|
|
12336
|
+
console.error("BugBear: updateTesterProfile error", formatPgError(error));
|
|
12332
12337
|
return { success: false, error: error.message };
|
|
12333
12338
|
}
|
|
12334
12339
|
return { success: true };
|
|
@@ -12350,14 +12355,14 @@ var BugBearClient = class {
|
|
|
12350
12355
|
*/
|
|
12351
12356
|
async isQAEnabled() {
|
|
12352
12357
|
try {
|
|
12353
|
-
const { data, error } = await this.supabase.
|
|
12358
|
+
const { data, error } = await this.supabase.rpc("check_qa_enabled", {
|
|
12359
|
+
p_project_id: this.config.projectId
|
|
12360
|
+
});
|
|
12354
12361
|
if (error) {
|
|
12355
|
-
|
|
12356
|
-
console.warn("BugBear: Could not check QA status", error.message || error.code || "Unknown error");
|
|
12357
|
-
}
|
|
12362
|
+
console.warn("BugBear: Could not check QA status", error.message || error.code || "Unknown error");
|
|
12358
12363
|
return true;
|
|
12359
12364
|
}
|
|
12360
|
-
return data
|
|
12365
|
+
return data ?? true;
|
|
12361
12366
|
} catch (err) {
|
|
12362
12367
|
return true;
|
|
12363
12368
|
}
|
|
@@ -12387,7 +12392,7 @@ var BugBearClient = class {
|
|
|
12387
12392
|
upsert: false
|
|
12388
12393
|
});
|
|
12389
12394
|
if (error) {
|
|
12390
|
-
console.error("BugBear: Failed to upload screenshot", error);
|
|
12395
|
+
console.error("BugBear: Failed to upload screenshot", formatPgError(error));
|
|
12391
12396
|
return null;
|
|
12392
12397
|
}
|
|
12393
12398
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
@@ -12418,7 +12423,7 @@ var BugBearClient = class {
|
|
|
12418
12423
|
upsert: false
|
|
12419
12424
|
});
|
|
12420
12425
|
if (error) {
|
|
12421
|
-
console.error("BugBear: Failed to upload image from URI", error);
|
|
12426
|
+
console.error("BugBear: Failed to upload image from URI", formatPgError(error));
|
|
12422
12427
|
return null;
|
|
12423
12428
|
}
|
|
12424
12429
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
@@ -12493,7 +12498,7 @@ var BugBearClient = class {
|
|
|
12493
12498
|
}
|
|
12494
12499
|
const { data, error } = await query;
|
|
12495
12500
|
if (error) {
|
|
12496
|
-
console.error("BugBear: Failed to fetch fix requests", error);
|
|
12501
|
+
console.error("BugBear: Failed to fetch fix requests", formatPgError(error));
|
|
12497
12502
|
return [];
|
|
12498
12503
|
}
|
|
12499
12504
|
return (data || []).map((fr) => ({
|
|
@@ -12524,7 +12529,7 @@ var BugBearClient = class {
|
|
|
12524
12529
|
p_tester_id: testerInfo.id
|
|
12525
12530
|
});
|
|
12526
12531
|
if (error) {
|
|
12527
|
-
console.error("BugBear: Failed to fetch threads via RPC", error);
|
|
12532
|
+
console.error("BugBear: Failed to fetch threads via RPC", formatPgError(error));
|
|
12528
12533
|
return [];
|
|
12529
12534
|
}
|
|
12530
12535
|
if (!data || data.length === 0) return [];
|
|
@@ -12568,7 +12573,7 @@ var BugBearClient = class {
|
|
|
12568
12573
|
attachments
|
|
12569
12574
|
`).eq("thread_id", threadId).order("created_at", { ascending: true }).limit(200);
|
|
12570
12575
|
if (error) {
|
|
12571
|
-
console.error("BugBear: Failed to fetch messages", error);
|
|
12576
|
+
console.error("BugBear: Failed to fetch messages", formatPgError(error));
|
|
12572
12577
|
return [];
|
|
12573
12578
|
}
|
|
12574
12579
|
return (data || []).map((msg) => ({
|
|
@@ -12612,7 +12617,7 @@ var BugBearClient = class {
|
|
|
12612
12617
|
}
|
|
12613
12618
|
const { error } = await this.supabase.from("discussion_messages").insert(insertData);
|
|
12614
12619
|
if (error) {
|
|
12615
|
-
console.error("BugBear: Failed to send message", error);
|
|
12620
|
+
console.error("BugBear: Failed to send message", formatPgError(error));
|
|
12616
12621
|
return false;
|
|
12617
12622
|
}
|
|
12618
12623
|
await this.markThreadAsRead(threadId);
|
|
@@ -12728,7 +12733,7 @@ var BugBearClient = class {
|
|
|
12728
12733
|
p_platform: options.platform || null
|
|
12729
12734
|
});
|
|
12730
12735
|
if (error) {
|
|
12731
|
-
console.error("BugBear: Failed to start session", error);
|
|
12736
|
+
console.error("BugBear: Failed to start session", formatPgError(error));
|
|
12732
12737
|
return { success: false, error: error.message };
|
|
12733
12738
|
}
|
|
12734
12739
|
const session = await this.getSession(data);
|
|
@@ -12753,7 +12758,7 @@ var BugBearClient = class {
|
|
|
12753
12758
|
p_routes_covered: options.routesCovered || null
|
|
12754
12759
|
});
|
|
12755
12760
|
if (error) {
|
|
12756
|
-
console.error("BugBear: Failed to end session", error);
|
|
12761
|
+
console.error("BugBear: Failed to end session", formatPgError(error));
|
|
12757
12762
|
return { success: false, error: error.message };
|
|
12758
12763
|
}
|
|
12759
12764
|
const session = this.transformSession(data);
|
|
@@ -12801,7 +12806,7 @@ var BugBearClient = class {
|
|
|
12801
12806
|
if (!testerInfo) return [];
|
|
12802
12807
|
const { data, error } = await this.supabase.from("qa_sessions").select("*").eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).order("started_at", { ascending: false }).limit(limit);
|
|
12803
12808
|
if (error) {
|
|
12804
|
-
console.error("BugBear: Failed to fetch session history", error);
|
|
12809
|
+
console.error("BugBear: Failed to fetch session history", formatPgError(error));
|
|
12805
12810
|
return [];
|
|
12806
12811
|
}
|
|
12807
12812
|
return (data || []).map((s) => this.transformSession(s));
|
|
@@ -12829,7 +12834,7 @@ var BugBearClient = class {
|
|
|
12829
12834
|
p_app_context: options.appContext || null
|
|
12830
12835
|
});
|
|
12831
12836
|
if (error) {
|
|
12832
|
-
console.error("BugBear: Failed to add finding", error);
|
|
12837
|
+
console.error("BugBear: Failed to add finding", formatPgError(error));
|
|
12833
12838
|
return { success: false, error: error.message };
|
|
12834
12839
|
}
|
|
12835
12840
|
const finding = this.transformFinding(data);
|
|
@@ -12847,7 +12852,7 @@ var BugBearClient = class {
|
|
|
12847
12852
|
try {
|
|
12848
12853
|
const { data, error } = await this.supabase.from("qa_findings").select("*").eq("session_id", sessionId).order("created_at", { ascending: true }).limit(100);
|
|
12849
12854
|
if (error) {
|
|
12850
|
-
console.error("BugBear: Failed to fetch findings", error);
|
|
12855
|
+
console.error("BugBear: Failed to fetch findings", formatPgError(error));
|
|
12851
12856
|
return [];
|
|
12852
12857
|
}
|
|
12853
12858
|
return (data || []).map((f) => this.transformFinding(f));
|
|
@@ -12865,7 +12870,7 @@ var BugBearClient = class {
|
|
|
12865
12870
|
p_finding_id: findingId
|
|
12866
12871
|
});
|
|
12867
12872
|
if (error) {
|
|
12868
|
-
console.error("BugBear: Failed to convert finding", error);
|
|
12873
|
+
console.error("BugBear: Failed to convert finding", formatPgError(error));
|
|
12869
12874
|
return { success: false, error: error.message };
|
|
12870
12875
|
}
|
|
12871
12876
|
return { success: true, bugId: data };
|
|
@@ -12886,7 +12891,7 @@ var BugBearClient = class {
|
|
|
12886
12891
|
dismissed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
12887
12892
|
}).eq("id", findingId);
|
|
12888
12893
|
if (error) {
|
|
12889
|
-
console.error("BugBear: Failed to dismiss finding", error);
|
|
12894
|
+
console.error("BugBear: Failed to dismiss finding", formatPgError(error));
|
|
12890
12895
|
return { success: false, error: error.message };
|
|
12891
12896
|
}
|
|
12892
12897
|
return { success: true };
|
|
@@ -13215,7 +13220,7 @@ import {
|
|
|
13215
13220
|
Image as Image3,
|
|
13216
13221
|
TouchableOpacity as TouchableOpacity12,
|
|
13217
13222
|
Modal as Modal2,
|
|
13218
|
-
ScrollView as
|
|
13223
|
+
ScrollView as ScrollView3,
|
|
13219
13224
|
StyleSheet as StyleSheet14,
|
|
13220
13225
|
Dimensions as Dimensions2,
|
|
13221
13226
|
KeyboardAvoidingView,
|
|
@@ -13764,7 +13769,10 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13764
13769
|
Keyboard.dismiss();
|
|
13765
13770
|
setIsSubmitting(true);
|
|
13766
13771
|
try {
|
|
13767
|
-
await client.failAssignment(displayedAssignment.id);
|
|
13772
|
+
const result = await client.failAssignment(displayedAssignment.id);
|
|
13773
|
+
if (!result.success) {
|
|
13774
|
+
console.error("BugBear: Failed to mark assignment as failed", result.error);
|
|
13775
|
+
}
|
|
13768
13776
|
await refreshAssignments();
|
|
13769
13777
|
nav.replace({
|
|
13770
13778
|
name: "REPORT",
|
|
@@ -13991,14 +13999,23 @@ var styles2 = StyleSheet3.create({
|
|
|
13991
13999
|
|
|
13992
14000
|
// src/widget/screens/TestListScreen.tsx
|
|
13993
14001
|
import React4, { useState as useState3, useMemo as useMemo2, useCallback as useCallback3, useEffect as useEffect4 } from "react";
|
|
13994
|
-
import { View as View3, Text as Text3, TouchableOpacity as TouchableOpacity3, StyleSheet as StyleSheet4 } from "react-native";
|
|
14002
|
+
import { View as View3, Text as Text3, TouchableOpacity as TouchableOpacity3, StyleSheet as StyleSheet4, ScrollView } from "react-native";
|
|
13995
14003
|
function TestListScreen({ nav }) {
|
|
13996
14004
|
const { assignments, currentAssignment, refreshAssignments } = useBugBear();
|
|
13997
14005
|
const [filter, setFilter] = useState3("all");
|
|
14006
|
+
const [roleFilter, setRoleFilter] = useState3(null);
|
|
13998
14007
|
const [collapsedFolders, setCollapsedFolders] = useState3(/* @__PURE__ */ new Set());
|
|
13999
14008
|
useEffect4(() => {
|
|
14000
14009
|
refreshAssignments();
|
|
14001
14010
|
}, []);
|
|
14011
|
+
const availableRoles = useMemo2(() => {
|
|
14012
|
+
const roleMap = /* @__PURE__ */ new Map();
|
|
14013
|
+
for (const a of assignments) {
|
|
14014
|
+
if (a.testCase.role) roleMap.set(a.testCase.role.id, a.testCase.role);
|
|
14015
|
+
}
|
|
14016
|
+
return Array.from(roleMap.values());
|
|
14017
|
+
}, [assignments]);
|
|
14018
|
+
const selectedRole = availableRoles.find((r) => r.id === roleFilter);
|
|
14002
14019
|
const groupedAssignments = useMemo2(() => {
|
|
14003
14020
|
const groups = /* @__PURE__ */ new Map();
|
|
14004
14021
|
for (const assignment of assignments) {
|
|
@@ -14042,16 +14059,39 @@ function TestListScreen({ nav }) {
|
|
|
14042
14059
|
});
|
|
14043
14060
|
}, []);
|
|
14044
14061
|
const filterAssignment = (a) => {
|
|
14062
|
+
if (roleFilter && a.testCase.role?.id !== roleFilter) return false;
|
|
14045
14063
|
if (filter === "pending") return a.status === "pending" || a.status === "in_progress";
|
|
14046
14064
|
if (filter === "completed") return a.status === "passed" || a.status === "failed";
|
|
14047
14065
|
return true;
|
|
14048
14066
|
};
|
|
14049
|
-
return /* @__PURE__ */ React4.createElement(View3, null, /* @__PURE__ */ React4.createElement(View3, { style: styles3.filterBar }, ["all", "pending", "completed"].map((f) => /* @__PURE__ */ React4.createElement(TouchableOpacity3, { key: f, style: [styles3.filterBtn, filter === f && styles3.filterBtnActive], onPress: () => setFilter(f) }, /* @__PURE__ */ React4.createElement(Text3, { style: [styles3.filterBtnText, filter === f && styles3.filterBtnTextActive] }, f === "all" ? `All (${assignments.length})` : f === "pending" ? `To Do (${assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length})` : `Done (${assignments.filter((a) => a.status === "passed" || a.status === "failed").length})`)))),
|
|
14067
|
+
return /* @__PURE__ */ React4.createElement(View3, null, /* @__PURE__ */ React4.createElement(View3, { style: styles3.filterBar }, ["all", "pending", "completed"].map((f) => /* @__PURE__ */ React4.createElement(TouchableOpacity3, { key: f, style: [styles3.filterBtn, filter === f && styles3.filterBtnActive], onPress: () => setFilter(f) }, /* @__PURE__ */ React4.createElement(Text3, { style: [styles3.filterBtnText, filter === f && styles3.filterBtnTextActive] }, f === "all" ? `All (${assignments.length})` : f === "pending" ? `To Do (${assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length})` : `Done (${assignments.filter((a) => a.status === "passed" || a.status === "failed").length})`)))), availableRoles.length >= 2 && /* @__PURE__ */ React4.createElement(View3, { style: styles3.roleSection }, /* @__PURE__ */ React4.createElement(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles3.roleBar }, /* @__PURE__ */ React4.createElement(
|
|
14068
|
+
TouchableOpacity3,
|
|
14069
|
+
{
|
|
14070
|
+
style: [styles3.roleBtn, !roleFilter && styles3.roleBtnActive],
|
|
14071
|
+
onPress: () => setRoleFilter(null)
|
|
14072
|
+
},
|
|
14073
|
+
/* @__PURE__ */ React4.createElement(Text3, { style: [styles3.roleBtnText, !roleFilter && styles3.roleBtnTextActive] }, "All Roles")
|
|
14074
|
+
), availableRoles.map((role) => {
|
|
14075
|
+
const isActive = roleFilter === role.id;
|
|
14076
|
+
return /* @__PURE__ */ React4.createElement(
|
|
14077
|
+
TouchableOpacity3,
|
|
14078
|
+
{
|
|
14079
|
+
key: role.id,
|
|
14080
|
+
style: [
|
|
14081
|
+
styles3.roleBtn,
|
|
14082
|
+
isActive && { backgroundColor: role.color + "20", borderColor: role.color + "60", borderWidth: 1 }
|
|
14083
|
+
],
|
|
14084
|
+
onPress: () => setRoleFilter(isActive ? null : role.id)
|
|
14085
|
+
},
|
|
14086
|
+
/* @__PURE__ */ React4.createElement(View3, { style: [styles3.roleDot, { backgroundColor: role.color }] }),
|
|
14087
|
+
/* @__PURE__ */ React4.createElement(Text3, { style: [styles3.roleBtnText, isActive && { color: role.color, fontWeight: "600" }] }, role.name)
|
|
14088
|
+
);
|
|
14089
|
+
})), selectedRole?.loginHint && /* @__PURE__ */ React4.createElement(View3, { style: [styles3.loginHint, { backgroundColor: selectedRole.color + "10", borderColor: selectedRole.color + "30" }] }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.loginHintText }, "Log in as: ", selectedRole.loginHint))), groupedAssignments.map((folder) => {
|
|
14050
14090
|
const folderId = folder.group?.id || "ungrouped";
|
|
14051
14091
|
const isCollapsed = collapsedFolders.has(folderId);
|
|
14052
14092
|
const filtered = folder.assignments.filter(filterAssignment);
|
|
14053
14093
|
if (filtered.length === 0 && filter !== "all") return null;
|
|
14054
|
-
return /* @__PURE__ */ React4.createElement(View3, { key: folderId, style: styles3.folder }, /* @__PURE__ */ React4.createElement(TouchableOpacity3, { style: styles3.folderHeader, onPress: () => toggleFolder(folderId) }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.folderToggle }, isCollapsed ? "\u25B6" : "\u25BC"), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.folderName }, folder.group?.name || "Ungrouped"), /* @__PURE__ */ React4.createElement(View3, { style: styles3.folderProgress }, /* @__PURE__ */ React4.createElement(View3, { style: [styles3.folderProgressFill, { width: `${Math.round((folder.stats.passed + folder.stats.failed) / folder.stats.total * 100)}%` }] })), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.folderCount }, folder.stats.passed + folder.stats.failed, "/", folder.stats.total)), !isCollapsed && filtered.map((assignment) => {
|
|
14094
|
+
return /* @__PURE__ */ React4.createElement(View3, { key: folderId, style: styles3.folder }, /* @__PURE__ */ React4.createElement(TouchableOpacity3, { style: styles3.folderHeader, onPress: () => toggleFolder(folderId) }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.folderToggle }, isCollapsed ? "\u25B6" : "\u25BC"), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.folderName, numberOfLines: 1 }, folder.group?.name || "Ungrouped"), /* @__PURE__ */ React4.createElement(View3, { style: styles3.folderProgress }, /* @__PURE__ */ React4.createElement(View3, { style: [styles3.folderProgressFill, { width: `${folder.stats.total > 0 ? Math.round((folder.stats.passed + folder.stats.failed) / folder.stats.total * 100) : 0}%` }] })), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.folderCount }, folder.stats.passed + folder.stats.failed, "/", folder.stats.total)), !isCollapsed && filtered.map((assignment) => {
|
|
14055
14095
|
const badge = getStatusBadge(assignment.status);
|
|
14056
14096
|
const isCurrent = currentAssignment?.id === assignment.id;
|
|
14057
14097
|
return /* @__PURE__ */ React4.createElement(
|
|
@@ -14062,17 +14102,28 @@ function TestListScreen({ nav }) {
|
|
|
14062
14102
|
onPress: () => nav.push({ name: "TEST_DETAIL", testId: assignment.id })
|
|
14063
14103
|
},
|
|
14064
14104
|
/* @__PURE__ */ React4.createElement(Text3, { style: styles3.testBadge }, badge.icon),
|
|
14065
|
-
/* @__PURE__ */ React4.createElement(View3, { style: styles3.testInfo }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ React4.createElement(View3, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ React4.createElement(View3, { style: styles3.retestTag }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testMeta }, assignment.testCase.
|
|
14105
|
+
/* @__PURE__ */ React4.createElement(View3, { style: styles3.testInfo }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ React4.createElement(View3, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ React4.createElement(View3, { style: styles3.retestTag }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testMeta }, assignment.testCase.testKey, " \xB7 ", assignment.testCase.priority), assignment.testCase.role && /* @__PURE__ */ React4.createElement(View3, { style: styles3.roleBadgeRow }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testMeta }, " \xB7 "), /* @__PURE__ */ React4.createElement(View3, { style: [styles3.roleBadgeDot, { backgroundColor: assignment.testCase.role.color }] }), /* @__PURE__ */ React4.createElement(Text3, { style: [styles3.testMeta, { color: assignment.testCase.role.color, fontWeight: "500" }] }, assignment.testCase.role.name))))
|
|
14066
14106
|
);
|
|
14067
14107
|
}));
|
|
14068
|
-
}), /* @__PURE__ */ React4.createElement(TouchableOpacity3, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.refreshText }, "\u21BB Refresh")));
|
|
14108
|
+
}), /* @__PURE__ */ React4.createElement(TouchableOpacity3, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.refreshText }, "\u21BB", " Refresh")));
|
|
14069
14109
|
}
|
|
14070
14110
|
var styles3 = StyleSheet4.create({
|
|
14071
|
-
filterBar: { flexDirection: "row", gap: 8, marginBottom:
|
|
14111
|
+
filterBar: { flexDirection: "row", gap: 8, marginBottom: 8 },
|
|
14072
14112
|
filterBtn: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 8, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border },
|
|
14073
14113
|
filterBtnActive: { backgroundColor: colors.blue, borderColor: colors.blue },
|
|
14074
14114
|
filterBtnText: { fontSize: 12, color: colors.textSecondary },
|
|
14075
14115
|
filterBtnTextActive: { color: "#fff", fontWeight: "600" },
|
|
14116
|
+
roleSection: { marginBottom: 12 },
|
|
14117
|
+
roleBar: { flexDirection: "row", marginBottom: 6 },
|
|
14118
|
+
roleBtn: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 6, marginRight: 6, borderWidth: 1, borderColor: "transparent" },
|
|
14119
|
+
roleBtnActive: { backgroundColor: colors.card, borderColor: colors.border },
|
|
14120
|
+
roleBtnText: { fontSize: 11, color: colors.textMuted },
|
|
14121
|
+
roleBtnTextActive: { color: colors.textPrimary, fontWeight: "600" },
|
|
14122
|
+
roleDot: { width: 6, height: 6, borderRadius: 3 },
|
|
14123
|
+
loginHint: { borderRadius: 6, padding: 8, borderWidth: 1 },
|
|
14124
|
+
loginHintText: { fontSize: 11, color: colors.textSecondary },
|
|
14125
|
+
roleBadgeRow: { flexDirection: "row", alignItems: "center", gap: 3 },
|
|
14126
|
+
roleBadgeDot: { width: 5, height: 5, borderRadius: 3 },
|
|
14076
14127
|
folder: { marginBottom: 12 },
|
|
14077
14128
|
folderHeader: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 8, paddingHorizontal: 4 },
|
|
14078
14129
|
folderToggle: { fontSize: 10, color: colors.textMuted, width: 14 },
|
|
@@ -14085,7 +14136,7 @@ var styles3 = StyleSheet4.create({
|
|
|
14085
14136
|
testBadge: { fontSize: 16, marginRight: 10, width: 20 },
|
|
14086
14137
|
testInfo: { flex: 1 },
|
|
14087
14138
|
testTitle: { fontSize: 14, color: colors.textPrimary, marginBottom: 2 },
|
|
14088
|
-
testMetaRow: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
14139
|
+
testMetaRow: { flexDirection: "row", alignItems: "center", gap: 6, flexWrap: "wrap" },
|
|
14089
14140
|
retestTag: { backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 4, paddingHorizontal: 5, paddingVertical: 1 },
|
|
14090
14141
|
retestTagText: { fontSize: 10, fontWeight: "600", color: "#fbbf24" },
|
|
14091
14142
|
testMeta: { fontSize: 11, color: colors.textDim },
|
|
@@ -14180,10 +14231,10 @@ import { View as View5, Text as Text5, TouchableOpacity as TouchableOpacity5, St
|
|
|
14180
14231
|
|
|
14181
14232
|
// src/widget/ImagePreviewStrip.tsx
|
|
14182
14233
|
import React5 from "react";
|
|
14183
|
-
import { View as View4, Text as Text4, TouchableOpacity as TouchableOpacity4, ScrollView, Image, ActivityIndicator, StyleSheet as StyleSheet5 } from "react-native";
|
|
14234
|
+
import { View as View4, Text as Text4, TouchableOpacity as TouchableOpacity4, ScrollView as ScrollView2, Image, ActivityIndicator, StyleSheet as StyleSheet5 } from "react-native";
|
|
14184
14235
|
function ImagePreviewStrip({ images, onRemove }) {
|
|
14185
14236
|
if (images.length === 0) return null;
|
|
14186
|
-
return /* @__PURE__ */ React5.createElement(
|
|
14237
|
+
return /* @__PURE__ */ React5.createElement(ScrollView2, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles4.strip }, images.map((img) => /* @__PURE__ */ React5.createElement(View4, { key: img.id, style: styles4.thumbContainer }, /* @__PURE__ */ React5.createElement(Image, { source: { uri: img.localUri }, style: styles4.thumb }), img.status === "uploading" && /* @__PURE__ */ React5.createElement(View4, { style: styles4.thumbOverlay }, /* @__PURE__ */ React5.createElement(ActivityIndicator, { size: "small", color: "#fff" })), img.status === "error" && /* @__PURE__ */ React5.createElement(View4, { style: [styles4.thumbOverlay, styles4.thumbOverlayError] }, /* @__PURE__ */ React5.createElement(Text4, { style: styles4.thumbErrorText }, "!")), /* @__PURE__ */ React5.createElement(TouchableOpacity4, { style: styles4.thumbRemove, onPress: () => onRemove(img.id) }, /* @__PURE__ */ React5.createElement(Text4, { style: styles4.thumbRemoveText }, "\u2715")))));
|
|
14187
14238
|
}
|
|
14188
14239
|
var styles4 = StyleSheet5.create({
|
|
14189
14240
|
strip: {
|
|
@@ -14428,6 +14479,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14428
14479
|
const [submitting, setSubmitting] = useState6(false);
|
|
14429
14480
|
const [error, setError] = useState6(null);
|
|
14430
14481
|
const images = useImageAttachments(uploadImage, 5, "screenshots");
|
|
14482
|
+
const isRetestFailure = prefill?.type === "test_fail";
|
|
14431
14483
|
const isBugType = reportType === "bug" || reportType === "test_fail";
|
|
14432
14484
|
const handleSubmit = async () => {
|
|
14433
14485
|
if (!client || !description.trim()) return;
|
|
@@ -14467,7 +14519,50 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14467
14519
|
setSubmitting(false);
|
|
14468
14520
|
}
|
|
14469
14521
|
};
|
|
14470
|
-
return /* @__PURE__ */ React8.createElement(View7, null, /* @__PURE__ */ React8.createElement(Text7, { style:
|
|
14522
|
+
return /* @__PURE__ */ React8.createElement(View7, null, isRetestFailure ? /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(View7, { style: styles7.retestBanner }, /* @__PURE__ */ React8.createElement(Text7, { style: styles7.retestIcon }, "\u{1F504}"), /* @__PURE__ */ React8.createElement(View7, null, /* @__PURE__ */ React8.createElement(Text7, { style: styles7.retestTitle }, "Bug Still Present"), /* @__PURE__ */ React8.createElement(Text7, { style: styles7.retestSubtitle }, "The fix did not resolve this issue"))), /* @__PURE__ */ React8.createElement(View7, { style: styles7.section }, /* @__PURE__ */ React8.createElement(Text7, { style: shared.label }, "Severity"), /* @__PURE__ */ React8.createElement(View7, { style: styles7.severityRow }, [
|
|
14523
|
+
{ sev: "critical", color: "#ef4444" },
|
|
14524
|
+
{ sev: "high", color: "#f97316" },
|
|
14525
|
+
{ sev: "medium", color: "#eab308" },
|
|
14526
|
+
{ sev: "low", color: "#6b7280" }
|
|
14527
|
+
].map(({ sev, color }) => /* @__PURE__ */ React8.createElement(
|
|
14528
|
+
TouchableOpacity7,
|
|
14529
|
+
{
|
|
14530
|
+
key: sev,
|
|
14531
|
+
style: [styles7.sevButton, severity === sev && { backgroundColor: `${color}30`, borderColor: color }],
|
|
14532
|
+
onPress: () => setSeverity(sev)
|
|
14533
|
+
},
|
|
14534
|
+
/* @__PURE__ */ React8.createElement(Text7, { style: [styles7.sevText, severity === sev && { color }] }, sev)
|
|
14535
|
+
)))), /* @__PURE__ */ React8.createElement(View7, { style: styles7.section }, /* @__PURE__ */ React8.createElement(Text7, { style: shared.label }, "What went wrong?"), /* @__PURE__ */ React8.createElement(
|
|
14536
|
+
TextInput3,
|
|
14537
|
+
{
|
|
14538
|
+
style: styles7.descInput,
|
|
14539
|
+
value: description,
|
|
14540
|
+
onChangeText: setDescription,
|
|
14541
|
+
placeholder: "Describe what you observed. What still doesn't work?",
|
|
14542
|
+
placeholderTextColor: colors.textMuted,
|
|
14543
|
+
multiline: true,
|
|
14544
|
+
numberOfLines: 4,
|
|
14545
|
+
textAlignVertical: "top"
|
|
14546
|
+
}
|
|
14547
|
+
)), /* @__PURE__ */ React8.createElement(
|
|
14548
|
+
ImagePickerButtons,
|
|
14549
|
+
{
|
|
14550
|
+
images: images.images,
|
|
14551
|
+
maxImages: 5,
|
|
14552
|
+
onPickGallery: images.pickFromGallery,
|
|
14553
|
+
onPickCamera: images.pickFromCamera,
|
|
14554
|
+
onRemove: images.removeImage,
|
|
14555
|
+
label: "Attachments (optional)"
|
|
14556
|
+
}
|
|
14557
|
+
), error && /* @__PURE__ */ React8.createElement(View7, { style: styles7.errorBanner }, /* @__PURE__ */ React8.createElement(Text7, { style: styles7.errorText }, error)), /* @__PURE__ */ React8.createElement(
|
|
14558
|
+
TouchableOpacity7,
|
|
14559
|
+
{
|
|
14560
|
+
style: [shared.primaryButton, styles7.retestSubmitButton, (!description.trim() || submitting || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
|
|
14561
|
+
onPress: handleSubmit,
|
|
14562
|
+
disabled: !description.trim() || submitting || images.isUploading
|
|
14563
|
+
},
|
|
14564
|
+
/* @__PURE__ */ React8.createElement(Text7, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Failed Retest")
|
|
14565
|
+
)) : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text7, { style: shared.label }, "What are you reporting?"), /* @__PURE__ */ React8.createElement(View7, { style: styles7.typeRow }, [
|
|
14471
14566
|
{ type: "bug", label: "Bug", icon: "\u{1F41B}" },
|
|
14472
14567
|
{ type: "feedback", label: "Feedback", icon: "\u{1F4A1}" },
|
|
14473
14568
|
{ type: "suggestion", label: "Idea", icon: "\u2728" }
|
|
@@ -14532,7 +14627,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14532
14627
|
disabled: !description.trim() || submitting || images.isUploading
|
|
14533
14628
|
},
|
|
14534
14629
|
/* @__PURE__ */ React8.createElement(Text7, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Report")
|
|
14535
|
-
));
|
|
14630
|
+
)));
|
|
14536
14631
|
}
|
|
14537
14632
|
var styles7 = StyleSheet8.create({
|
|
14538
14633
|
typeRow: { flexDirection: "row", gap: 10, marginBottom: 20 },
|
|
@@ -14549,7 +14644,12 @@ var styles7 = StyleSheet8.create({
|
|
|
14549
14644
|
screenInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, fontSize: 13, color: colors.textPrimary },
|
|
14550
14645
|
screenHint: { fontSize: 11, color: colors.textMuted, marginTop: 4 },
|
|
14551
14646
|
errorBanner: { backgroundColor: "#7f1d1d", borderWidth: 1, borderColor: "#991b1b", borderRadius: 8, padding: 12, marginTop: 16 },
|
|
14552
|
-
errorText: { fontSize: 13, color: "#fca5a5", lineHeight: 18 }
|
|
14647
|
+
errorText: { fontSize: 13, color: "#fca5a5", lineHeight: 18 },
|
|
14648
|
+
retestBanner: { flexDirection: "row", alignItems: "center", gap: 10, backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 10, paddingVertical: 12, paddingHorizontal: 14, marginBottom: 20 },
|
|
14649
|
+
retestIcon: { fontSize: 16 },
|
|
14650
|
+
retestTitle: { fontSize: 15, fontWeight: "600", color: "#fbbf24", lineHeight: 20 },
|
|
14651
|
+
retestSubtitle: { fontSize: 12, color: "#d97706", lineHeight: 16 },
|
|
14652
|
+
retestSubmitButton: { backgroundColor: "#b45309" }
|
|
14553
14653
|
});
|
|
14554
14654
|
|
|
14555
14655
|
// src/widget/screens/ReportSuccessScreen.tsx
|
|
@@ -15100,7 +15200,7 @@ function BugBearButton({
|
|
|
15100
15200
|
style: styles13.modalOverlay
|
|
15101
15201
|
},
|
|
15102
15202
|
/* @__PURE__ */ React14.createElement(View13, { style: styles13.modalContainer }, /* @__PURE__ */ React14.createElement(View13, { style: styles13.header }, /* @__PURE__ */ React14.createElement(View13, { style: styles13.headerLeft }, canGoBack ? /* @__PURE__ */ React14.createElement(View13, { style: styles13.headerNavRow }, /* @__PURE__ */ React14.createElement(TouchableOpacity12, { onPress: () => nav.pop(), style: styles13.backButton }, /* @__PURE__ */ React14.createElement(Text13, { style: styles13.backText }, "\u2190 Back")), /* @__PURE__ */ React14.createElement(TouchableOpacity12, { onPress: () => nav.reset(), style: styles13.homeButton }, /* @__PURE__ */ React14.createElement(Text13, { style: styles13.homeText }, "\u{1F3E0}"))) : /* @__PURE__ */ React14.createElement(View13, { style: styles13.headerTitleRow }, /* @__PURE__ */ React14.createElement(Text13, { style: styles13.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ React14.createElement(TouchableOpacity12, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ React14.createElement(Text13, { style: styles13.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ React14.createElement(Text13, { style: styles13.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ React14.createElement(TouchableOpacity12, { onPress: handleClose, style: styles13.closeButton }, /* @__PURE__ */ React14.createElement(Text13, { style: styles13.closeText }, "\u2715"))), /* @__PURE__ */ React14.createElement(
|
|
15103
|
-
|
|
15203
|
+
ScrollView3,
|
|
15104
15204
|
{
|
|
15105
15205
|
style: styles13.content,
|
|
15106
15206
|
contentContainerStyle: styles13.contentContainer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbearai/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "BugBear React Native components for mobile apps",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@bbearai/core": "^0.
|
|
52
|
+
"@bbearai/core": "^0.4.0",
|
|
53
53
|
"@eslint/js": "^9.39.2",
|
|
54
54
|
"@types/react": "^18.2.0",
|
|
55
55
|
"eslint": "^9.39.2",
|