react-native-debug-toolkit 3.3.8 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -26
- package/README.zh-CN.md +52 -38
- package/android/src/main/java/com/reactnativedebugtoolkit/DebugToolkitNativeLogsModule.java +146 -0
- package/android/src/main/java/com/reactnativedebugtoolkit/ReactNativeDebugToolkitPackage.java +5 -3
- package/ios/DebugToolkitNativeLogs.mm +92 -0
- package/lib/commonjs/constants/logLevels.js +19 -0
- package/lib/commonjs/constants/logLevels.js.map +1 -0
- package/lib/commonjs/core/initialize.js +32 -19
- package/lib/commonjs/core/initialize.js.map +1 -1
- package/lib/commonjs/features/console/ConsoleLogTab.js +4 -15
- package/lib/commonjs/features/console/ConsoleLogTab.js.map +1 -1
- package/lib/commonjs/features/console/index.js +15 -8
- package/lib/commonjs/features/console/index.js.map +1 -1
- package/lib/commonjs/features/nativeLogs/NativeLogTab.js +156 -0
- package/lib/commonjs/features/nativeLogs/NativeLogTab.js.map +1 -0
- package/lib/commonjs/features/nativeLogs/index.js +97 -0
- package/lib/commonjs/features/nativeLogs/index.js.map +1 -0
- package/lib/commonjs/features/nativeLogs/nativeLogsBridge.js +71 -0
- package/lib/commonjs/features/nativeLogs/nativeLogsBridge.js.map +1 -0
- package/lib/commonjs/features/network/NetworkLogTab.js +90 -95
- package/lib/commonjs/features/network/NetworkLogTab.js.map +1 -1
- package/lib/commonjs/features/network/index.js +7 -4
- package/lib/commonjs/features/network/index.js.map +1 -1
- package/lib/commonjs/features/sessionHistory/SessionHistoryTab.js +1046 -0
- package/lib/commonjs/features/sessionHistory/SessionHistoryTab.js.map +1 -0
- package/lib/commonjs/features/sessionHistory/index.js +104 -0
- package/lib/commonjs/features/sessionHistory/index.js.map +1 -0
- package/lib/commonjs/features/track/index.js +4 -3
- package/lib/commonjs/features/track/index.js.map +1 -1
- package/lib/commonjs/index.js +27 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/DebugView.js +2 -0
- package/lib/commonjs/ui/DebugView.js.map +1 -1
- package/lib/commonjs/ui/panel/DebugPanel.js +67 -34
- package/lib/commonjs/ui/panel/DebugPanel.js.map +1 -1
- package/lib/commonjs/ui/panel/FeatureIntroCard.js +151 -0
- package/lib/commonjs/ui/panel/FeatureIntroCard.js.map +1 -0
- package/lib/commonjs/ui/panel/FeatureRail.js +163 -0
- package/lib/commonjs/ui/panel/FeatureRail.js.map +1 -0
- package/lib/commonjs/ui/panel/FloatPanelView.js +119 -22
- package/lib/commonjs/ui/panel/FloatPanelView.js.map +1 -1
- package/lib/commonjs/ui/panel/buildFeatureSummary.js +207 -0
- package/lib/commonjs/ui/panel/buildFeatureSummary.js.map +1 -0
- package/lib/commonjs/ui/panel/filterFeatureSnapshot.js +43 -0
- package/lib/commonjs/ui/panel/filterFeatureSnapshot.js.map +1 -0
- package/lib/commonjs/ui/theme/colors.js +6 -0
- package/lib/commonjs/ui/theme/colors.js.map +1 -1
- package/lib/commonjs/utils/DaemonClient.js +30 -8
- package/lib/commonjs/utils/DaemonClient.js.map +1 -1
- package/lib/commonjs/utils/SessionManager.js +132 -0
- package/lib/commonjs/utils/SessionManager.js.map +1 -0
- package/lib/commonjs/utils/StorageAdapter.js +104 -0
- package/lib/commonjs/utils/StorageAdapter.js.map +1 -0
- package/lib/commonjs/utils/createChannelFeature.js +22 -5
- package/lib/commonjs/utils/createChannelFeature.js.map +1 -1
- package/lib/commonjs/utils/createPersistedObservableStore.js +14 -8
- package/lib/commonjs/utils/createPersistedObservableStore.js.map +1 -1
- package/lib/commonjs/utils/debugPreferences.js +28 -5
- package/lib/commonjs/utils/debugPreferences.js.map +1 -1
- package/lib/commonjs/utils/deviceReport.js +5 -1
- package/lib/commonjs/utils/deviceReport.js.map +1 -1
- package/lib/commonjs/utils/logRuntime.js +32 -0
- package/lib/commonjs/utils/logRuntime.js.map +1 -0
- package/lib/module/constants/logLevels.js +15 -0
- package/lib/module/constants/logLevels.js.map +1 -0
- package/lib/module/core/initialize.js +32 -19
- package/lib/module/core/initialize.js.map +1 -1
- package/lib/module/features/console/ConsoleLogTab.js +1 -12
- package/lib/module/features/console/ConsoleLogTab.js.map +1 -1
- package/lib/module/features/console/index.js +15 -8
- package/lib/module/features/console/index.js.map +1 -1
- package/lib/module/features/nativeLogs/NativeLogTab.js +151 -0
- package/lib/module/features/nativeLogs/NativeLogTab.js.map +1 -0
- package/lib/module/features/nativeLogs/index.js +91 -0
- package/lib/module/features/nativeLogs/index.js.map +1 -0
- package/lib/module/features/nativeLogs/nativeLogsBridge.js +63 -0
- package/lib/module/features/nativeLogs/nativeLogsBridge.js.map +1 -0
- package/lib/module/features/network/NetworkLogTab.js +90 -95
- package/lib/module/features/network/NetworkLogTab.js.map +1 -1
- package/lib/module/features/network/index.js +7 -4
- package/lib/module/features/network/index.js.map +1 -1
- package/lib/module/features/sessionHistory/SessionHistoryTab.js +1041 -0
- package/lib/module/features/sessionHistory/SessionHistoryTab.js.map +1 -0
- package/lib/module/features/sessionHistory/index.js +100 -0
- package/lib/module/features/sessionHistory/index.js.map +1 -0
- package/lib/module/features/track/index.js +4 -3
- package/lib/module/features/track/index.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/DebugView.js +2 -0
- package/lib/module/ui/DebugView.js.map +1 -1
- package/lib/module/ui/panel/DebugPanel.js +67 -34
- package/lib/module/ui/panel/DebugPanel.js.map +1 -1
- package/lib/module/ui/panel/FeatureIntroCard.js +146 -0
- package/lib/module/ui/panel/FeatureIntroCard.js.map +1 -0
- package/lib/module/ui/panel/FeatureRail.js +158 -0
- package/lib/module/ui/panel/FeatureRail.js.map +1 -0
- package/lib/module/ui/panel/FloatPanelView.js +119 -22
- package/lib/module/ui/panel/FloatPanelView.js.map +1 -1
- package/lib/module/ui/panel/buildFeatureSummary.js +203 -0
- package/lib/module/ui/panel/buildFeatureSummary.js.map +1 -0
- package/lib/module/ui/panel/filterFeatureSnapshot.js +39 -0
- package/lib/module/ui/panel/filterFeatureSnapshot.js.map +1 -0
- package/lib/module/ui/theme/colors.js +6 -0
- package/lib/module/ui/theme/colors.js.map +1 -1
- package/lib/module/utils/DaemonClient.js +30 -8
- package/lib/module/utils/DaemonClient.js.map +1 -1
- package/lib/module/utils/SessionManager.js +127 -0
- package/lib/module/utils/SessionManager.js.map +1 -0
- package/lib/module/utils/StorageAdapter.js +96 -0
- package/lib/module/utils/StorageAdapter.js.map +1 -0
- package/lib/module/utils/createChannelFeature.js +22 -5
- package/lib/module/utils/createChannelFeature.js.map +1 -1
- package/lib/module/utils/createPersistedObservableStore.js +14 -8
- package/lib/module/utils/createPersistedObservableStore.js.map +1 -1
- package/lib/module/utils/debugPreferences.js +27 -5
- package/lib/module/utils/debugPreferences.js.map +1 -1
- package/lib/module/utils/deviceReport.js +4 -1
- package/lib/module/utils/deviceReport.js.map +1 -1
- package/lib/module/utils/logRuntime.js +26 -0
- package/lib/module/utils/logRuntime.js.map +1 -0
- package/lib/typescript/src/constants/logLevels.d.ts +3 -0
- package/lib/typescript/src/constants/logLevels.d.ts.map +1 -0
- package/lib/typescript/src/core/initialize.d.ts +6 -0
- package/lib/typescript/src/core/initialize.d.ts.map +1 -1
- package/lib/typescript/src/features/console/ConsoleLogTab.d.ts.map +1 -1
- package/lib/typescript/src/features/console/index.d.ts +2 -1
- package/lib/typescript/src/features/console/index.d.ts.map +1 -1
- package/lib/typescript/src/features/nativeLogs/NativeLogTab.d.ts +4 -0
- package/lib/typescript/src/features/nativeLogs/NativeLogTab.d.ts.map +1 -0
- package/lib/typescript/src/features/nativeLogs/index.d.ts +12 -0
- package/lib/typescript/src/features/nativeLogs/index.d.ts.map +1 -0
- package/lib/typescript/src/features/nativeLogs/nativeLogsBridge.d.ts +11 -0
- package/lib/typescript/src/features/nativeLogs/nativeLogsBridge.d.ts.map +1 -0
- package/lib/typescript/src/features/network/NetworkLogTab.d.ts.map +1 -1
- package/lib/typescript/src/features/network/index.d.ts +2 -1
- package/lib/typescript/src/features/network/index.d.ts.map +1 -1
- package/lib/typescript/src/features/sessionHistory/SessionHistoryTab.d.ts +20 -0
- package/lib/typescript/src/features/sessionHistory/SessionHistoryTab.d.ts.map +1 -0
- package/lib/typescript/src/features/sessionHistory/index.d.ts +4 -0
- package/lib/typescript/src/features/sessionHistory/index.d.ts.map +1 -0
- package/lib/typescript/src/features/track/index.d.ts +2 -1
- package/lib/typescript/src/features/track/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +7 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types/feature.d.ts +1 -1
- package/lib/typescript/src/types/feature.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts +3 -1
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/types/logs.d.ts +15 -0
- package/lib/typescript/src/types/logs.d.ts.map +1 -1
- package/lib/typescript/src/ui/DebugView.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/DebugPanel.d.ts +3 -1
- package/lib/typescript/src/ui/panel/DebugPanel.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/FeatureIntroCard.d.ts +14 -0
- package/lib/typescript/src/ui/panel/FeatureIntroCard.d.ts.map +1 -0
- package/lib/typescript/src/ui/panel/FeatureRail.d.ts +16 -0
- package/lib/typescript/src/ui/panel/FeatureRail.d.ts.map +1 -0
- package/lib/typescript/src/ui/panel/FloatPanelView.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/buildFeatureSummary.d.ts +13 -0
- package/lib/typescript/src/ui/panel/buildFeatureSummary.d.ts.map +1 -0
- package/lib/typescript/src/ui/panel/filterFeatureSnapshot.d.ts +3 -0
- package/lib/typescript/src/ui/panel/filterFeatureSnapshot.d.ts.map +1 -0
- package/lib/typescript/src/ui/theme/colors.d.ts +5 -0
- package/lib/typescript/src/ui/theme/colors.d.ts.map +1 -1
- package/lib/typescript/src/utils/DaemonClient.d.ts +7 -1
- package/lib/typescript/src/utils/DaemonClient.d.ts.map +1 -1
- package/lib/typescript/src/utils/SessionManager.d.ts +30 -0
- package/lib/typescript/src/utils/SessionManager.d.ts.map +1 -0
- package/lib/typescript/src/utils/StorageAdapter.d.ts +38 -0
- package/lib/typescript/src/utils/StorageAdapter.d.ts.map +1 -0
- package/lib/typescript/src/utils/createChannelFeature.d.ts +2 -0
- package/lib/typescript/src/utils/createChannelFeature.d.ts.map +1 -1
- package/lib/typescript/src/utils/createPersistedObservableStore.d.ts +4 -1
- package/lib/typescript/src/utils/createPersistedObservableStore.d.ts.map +1 -1
- package/lib/typescript/src/utils/debugPreferences.d.ts +1 -3
- package/lib/typescript/src/utils/debugPreferences.d.ts.map +1 -1
- package/lib/typescript/src/utils/deviceReport.d.ts +1 -0
- package/lib/typescript/src/utils/deviceReport.d.ts.map +1 -1
- package/lib/typescript/src/utils/logRuntime.d.ts +13 -0
- package/lib/typescript/src/utils/logRuntime.d.ts.map +1 -0
- package/node/daemon/src/console/console.html +18 -0
- package/node/mcp/src/logs.js +1 -1
- package/package.json +9 -1
- package/src/constants/logLevels.ts +13 -0
- package/src/core/initialize.ts +54 -25
- package/src/features/console/ConsoleLogTab.tsx +1 -14
- package/src/features/console/index.ts +18 -8
- package/src/features/nativeLogs/NativeLogTab.tsx +66 -0
- package/src/features/nativeLogs/index.ts +94 -0
- package/src/features/nativeLogs/nativeLogsBridge.ts +51 -0
- package/src/features/network/NetworkLogTab.tsx +60 -71
- package/src/features/network/index.ts +12 -3
- package/src/features/sessionHistory/SessionHistoryTab.tsx +693 -0
- package/src/features/sessionHistory/index.ts +102 -0
- package/src/features/track/index.ts +10 -3
- package/src/index.ts +16 -0
- package/src/types/feature.ts +3 -1
- package/src/types/index.ts +13 -0
- package/src/types/logs.ts +17 -0
- package/src/ui/DebugView.tsx +2 -0
- package/src/ui/panel/DebugPanel.tsx +60 -30
- package/src/ui/panel/FeatureIntroCard.tsx +147 -0
- package/src/ui/panel/FeatureRail.tsx +165 -0
- package/src/ui/panel/FloatPanelView.tsx +123 -15
- package/src/ui/panel/buildFeatureSummary.ts +288 -0
- package/src/ui/panel/filterFeatureSnapshot.ts +51 -0
- package/src/ui/theme/colors.ts +7 -0
- package/src/utils/DaemonClient.ts +33 -5
- package/src/utils/SessionManager.ts +174 -0
- package/src/utils/StorageAdapter.ts +135 -0
- package/src/utils/createChannelFeature.ts +28 -6
- package/src/utils/createPersistedObservableStore.ts +18 -10
- package/src/utils/debugPreferences.ts +38 -7
- package/src/utils/deviceReport.ts +5 -1
- package/src/utils/logRuntime.ts +39 -0
- package/lib/commonjs/ui/panel/FeatureTabBar.js +0 -182
- package/lib/commonjs/ui/panel/FeatureTabBar.js.map +0 -1
- package/lib/module/ui/panel/FeatureTabBar.js +0 -177
- package/lib/module/ui/panel/FeatureTabBar.js.map +0 -1
- package/lib/typescript/src/ui/panel/FeatureTabBar.d.ts +0 -13
- package/lib/typescript/src/ui/panel/FeatureTabBar.d.ts.map +0 -1
- package/src/ui/panel/FeatureTabBar.tsx +0 -204
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, ScrollView, Pressable } from 'react-native';
|
|
3
|
+
import { Colors } from '../theme/colors';
|
|
4
|
+
|
|
5
|
+
// ─── Label Model ──────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
const SHORT_LABEL_MAP: Record<string, string> = {
|
|
8
|
+
network: 'network',
|
|
9
|
+
console: 'console',
|
|
10
|
+
native: 'native',
|
|
11
|
+
navigation: 'nav',
|
|
12
|
+
zustand: 'zustand',
|
|
13
|
+
track: 'track',
|
|
14
|
+
clipboard: 'clip',
|
|
15
|
+
environment: 'env',
|
|
16
|
+
devConnect: 'dev',
|
|
17
|
+
sessionHistory: 'session',
|
|
18
|
+
thirdPartyLibs: 'libs',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function shortLabelForFeature(label: string, id: string): string {
|
|
22
|
+
const mapped = SHORT_LABEL_MAP[id];
|
|
23
|
+
if (mapped) return mapped;
|
|
24
|
+
const trimmed = label.trim();
|
|
25
|
+
return trimmed.toLowerCase().slice(0, 7);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ─── Rail Component ───────────────────────────────────
|
|
29
|
+
|
|
30
|
+
export interface RailItem {
|
|
31
|
+
id: string;
|
|
32
|
+
label: string;
|
|
33
|
+
dotColor?: string | null;
|
|
34
|
+
count?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface FeatureRailProps {
|
|
38
|
+
items: RailItem[];
|
|
39
|
+
activeIndex: number;
|
|
40
|
+
onSelectTab: (index: number) => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function FeatureRail({ items, activeIndex, onSelectTab }: FeatureRailProps) {
|
|
44
|
+
return (
|
|
45
|
+
<View style={styles.rail}>
|
|
46
|
+
<ScrollView
|
|
47
|
+
showsVerticalScrollIndicator={false}
|
|
48
|
+
contentContainerStyle={styles.scrollContent}
|
|
49
|
+
>
|
|
50
|
+
{items.map((item, index) => {
|
|
51
|
+
const isActive = index === activeIndex;
|
|
52
|
+
const short = shortLabelForFeature(item.label, item.id);
|
|
53
|
+
const dotColor = item.dotColor ?? null;
|
|
54
|
+
const hasCount = item.count != null && item.count > 0;
|
|
55
|
+
return (
|
|
56
|
+
<Pressable
|
|
57
|
+
key={item.id}
|
|
58
|
+
onPress={() => onSelectTab(index)}
|
|
59
|
+
style={[styles.item, isActive && styles.activeItem]}
|
|
60
|
+
accessibilityRole="tab"
|
|
61
|
+
accessibilityLabel={item.label}
|
|
62
|
+
accessibilityState={{ selected: isActive }}
|
|
63
|
+
>
|
|
64
|
+
{isActive && <View style={styles.activeBar} />}
|
|
65
|
+
<Text
|
|
66
|
+
style={[styles.itemName, isActive && styles.activeItemName]}
|
|
67
|
+
numberOfLines={1}
|
|
68
|
+
>
|
|
69
|
+
{short}
|
|
70
|
+
</Text>
|
|
71
|
+
<View style={styles.itemMeta}>
|
|
72
|
+
{dotColor && (
|
|
73
|
+
<View style={[styles.dot, { backgroundColor: dotColor }]} />
|
|
74
|
+
)}
|
|
75
|
+
{hasCount && (
|
|
76
|
+
<View style={styles.countPill}>
|
|
77
|
+
<Text style={styles.countText}>{item.count}</Text>
|
|
78
|
+
</View>
|
|
79
|
+
)}
|
|
80
|
+
</View>
|
|
81
|
+
</Pressable>
|
|
82
|
+
);
|
|
83
|
+
})}
|
|
84
|
+
</ScrollView>
|
|
85
|
+
</View>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const RAIL_WIDTH = 80;
|
|
90
|
+
|
|
91
|
+
const styles = StyleSheet.create({
|
|
92
|
+
rail: {
|
|
93
|
+
width: RAIL_WIDTH,
|
|
94
|
+
backgroundColor: Colors.railBackground,
|
|
95
|
+
borderRightWidth: StyleSheet.hairlineWidth,
|
|
96
|
+
borderRightColor: Colors.panelDivider,
|
|
97
|
+
},
|
|
98
|
+
scrollContent: {
|
|
99
|
+
paddingVertical: 6,
|
|
100
|
+
paddingHorizontal: 6,
|
|
101
|
+
gap: 3,
|
|
102
|
+
},
|
|
103
|
+
item: {
|
|
104
|
+
minHeight: 56,
|
|
105
|
+
borderRadius: 8,
|
|
106
|
+
justifyContent: 'center',
|
|
107
|
+
alignItems: 'center',
|
|
108
|
+
paddingVertical: 8,
|
|
109
|
+
paddingHorizontal: 4,
|
|
110
|
+
position: 'relative',
|
|
111
|
+
overflow: 'hidden',
|
|
112
|
+
},
|
|
113
|
+
activeItem: {
|
|
114
|
+
backgroundColor: Colors.surface,
|
|
115
|
+
elevation: 2,
|
|
116
|
+
shadowColor: '#000',
|
|
117
|
+
shadowOffset: { width: 0, height: 2 },
|
|
118
|
+
shadowOpacity: 0.06,
|
|
119
|
+
shadowRadius: 4,
|
|
120
|
+
},
|
|
121
|
+
activeBar: {
|
|
122
|
+
position: 'absolute',
|
|
123
|
+
left: 0,
|
|
124
|
+
top: 10,
|
|
125
|
+
bottom: 10,
|
|
126
|
+
width: 3,
|
|
127
|
+
borderRadius: 1.5,
|
|
128
|
+
backgroundColor: Colors.primary,
|
|
129
|
+
},
|
|
130
|
+
itemName: {
|
|
131
|
+
fontSize: 11,
|
|
132
|
+
fontWeight: '700',
|
|
133
|
+
color: Colors.textSecondary,
|
|
134
|
+
letterSpacing: 0.2,
|
|
135
|
+
},
|
|
136
|
+
activeItemName: {
|
|
137
|
+
color: Colors.text,
|
|
138
|
+
fontWeight: '800',
|
|
139
|
+
},
|
|
140
|
+
itemMeta: {
|
|
141
|
+
marginTop: 4,
|
|
142
|
+
flexDirection: 'row',
|
|
143
|
+
alignItems: 'center',
|
|
144
|
+
gap: 3,
|
|
145
|
+
},
|
|
146
|
+
dot: {
|
|
147
|
+
width: 6,
|
|
148
|
+
height: 6,
|
|
149
|
+
borderRadius: 3,
|
|
150
|
+
},
|
|
151
|
+
countPill: {
|
|
152
|
+
minWidth: 18,
|
|
153
|
+
height: 14,
|
|
154
|
+
borderRadius: 7,
|
|
155
|
+
backgroundColor: Colors.background,
|
|
156
|
+
paddingHorizontal: 4,
|
|
157
|
+
alignItems: 'center',
|
|
158
|
+
justifyContent: 'center',
|
|
159
|
+
},
|
|
160
|
+
countText: {
|
|
161
|
+
fontSize: 10,
|
|
162
|
+
fontWeight: '800',
|
|
163
|
+
color: Colors.textSecondary,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
@@ -6,11 +6,15 @@ import {
|
|
|
6
6
|
Animated,
|
|
7
7
|
} from 'react-native';
|
|
8
8
|
import type { AnyDebugFeature } from '../../types';
|
|
9
|
+
import { Colors } from '../theme/colors';
|
|
9
10
|
import { getPreference, setPreference, KEYS } from '../../utils/debugPreferences';
|
|
10
11
|
import { FloatIcon } from '../floating/FloatIcon';
|
|
11
12
|
import { DebugPanel } from './DebugPanel';
|
|
12
|
-
import {
|
|
13
|
-
import type {
|
|
13
|
+
import { FeatureRail } from './FeatureRail';
|
|
14
|
+
import type { RailItem } from './FeatureRail';
|
|
15
|
+
import { FeatureIntroCard } from './FeatureIntroCard';
|
|
16
|
+
import { buildFeatureSummary } from './buildFeatureSummary';
|
|
17
|
+
import { filterFeatureSnapshot } from './filterFeatureSnapshot';
|
|
14
18
|
import { resolveStoredTabIndex } from './tabPersistence';
|
|
15
19
|
import { useTabAnimation } from './useTabAnimation';
|
|
16
20
|
|
|
@@ -40,6 +44,57 @@ class DebugErrorBoundary extends Component<
|
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
// ─── Snapshot helpers ──────────────────────────────────
|
|
48
|
+
|
|
49
|
+
function snapshotCount(feature: AnyDebugFeature): number | undefined {
|
|
50
|
+
try {
|
|
51
|
+
const snap = feature.getSnapshot();
|
|
52
|
+
if (Array.isArray(snap)) return snap.length;
|
|
53
|
+
if (snap && typeof snap === 'object') {
|
|
54
|
+
const obj = snap as Record<string, unknown>;
|
|
55
|
+
if (Array.isArray(obj.items)) return obj.items.length;
|
|
56
|
+
if (Array.isArray(obj.logs)) return obj.logs.length;
|
|
57
|
+
if (Array.isArray(obj.entries)) return obj.entries.length;
|
|
58
|
+
if (Array.isArray(obj.environments)) return obj.environments.length;
|
|
59
|
+
}
|
|
60
|
+
} catch { /* ignore */ }
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface PanelConnectionStatus {
|
|
65
|
+
label: string;
|
|
66
|
+
color: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface DevConnectSnapshot {
|
|
70
|
+
isSimulator?: boolean;
|
|
71
|
+
computerHost?: string;
|
|
72
|
+
daemonPort?: string;
|
|
73
|
+
streaming?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function buildPanelConnectionStatus(features: AnyDebugFeature[]): PanelConnectionStatus {
|
|
77
|
+
const devConnect = features.find((f) => f.name === 'devConnect');
|
|
78
|
+
if (!devConnect) {
|
|
79
|
+
return { label: 'offline desktop sync unavailable', color: Colors.textLight };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const snap = (devConnect.getSnapshot() ?? {}) as DevConnectSnapshot;
|
|
84
|
+
const host = snap.isSimulator ? 'localhost' : snap.computerHost?.trim();
|
|
85
|
+
const port = snap.daemonPort?.trim();
|
|
86
|
+
const target = host && port ? `${host}:${port}` : host || (port ? `port ${port}` : 'not configured');
|
|
87
|
+
return {
|
|
88
|
+
label: `${snap.streaming ? 'live' : 'offline'} ${target}`,
|
|
89
|
+
color: snap.streaming ? Colors.success : Colors.textLight,
|
|
90
|
+
};
|
|
91
|
+
} catch {
|
|
92
|
+
return { label: 'offline desktop sync unavailable', color: Colors.textLight };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ─── Main Component ────────────────────────────────────
|
|
97
|
+
|
|
43
98
|
interface FloatPanelViewProps {
|
|
44
99
|
features: AnyDebugFeature[];
|
|
45
100
|
panelOpen: boolean;
|
|
@@ -50,6 +105,8 @@ interface FloatPanelViewProps {
|
|
|
50
105
|
|
|
51
106
|
export function FloatPanelView({ features, panelOpen, onOpenPanel, onClosePanel, onClearAll }: FloatPanelViewProps) {
|
|
52
107
|
const [activeTab, setActiveTab] = useState(0);
|
|
108
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
109
|
+
const [filterBad, setFilterBad] = useState(false);
|
|
53
110
|
const tabLoaded = useRef(false);
|
|
54
111
|
|
|
55
112
|
// Restore last tab on mount
|
|
@@ -74,6 +131,8 @@ export function FloatPanelView({ features, panelOpen, onOpenPanel, onClosePanel,
|
|
|
74
131
|
tabCount: features.length,
|
|
75
132
|
onTabChange: useCallback((index: number) => {
|
|
76
133
|
tabLoaded.current = true;
|
|
134
|
+
setSearchQuery('');
|
|
135
|
+
setFilterBad(false);
|
|
77
136
|
setActiveTab(index);
|
|
78
137
|
const featureName = features[index]?.name;
|
|
79
138
|
if (featureName) {
|
|
@@ -115,7 +174,30 @@ export function FloatPanelView({ features, panelOpen, onOpenPanel, onClosePanel,
|
|
|
115
174
|
|
|
116
175
|
// Badge (first feature that returns one)
|
|
117
176
|
const envBadge = features.map((f) => f.badge?.()).find((b) => b != null) ?? null;
|
|
118
|
-
|
|
177
|
+
|
|
178
|
+
// Rail items with counts
|
|
179
|
+
const railItems: RailItem[] = features.map((f) => {
|
|
180
|
+
const b = f.badge?.();
|
|
181
|
+
return { id: f.name, label: f.label, dotColor: b?.color ?? null, count: snapshotCount(f) };
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const panelConnectionStatus = buildPanelConnectionStatus(features);
|
|
185
|
+
|
|
186
|
+
const handleClearAll = useCallback(() => {
|
|
187
|
+
setSearchQuery('');
|
|
188
|
+
setFilterBad(false);
|
|
189
|
+
onClearAll();
|
|
190
|
+
}, [onClearAll]);
|
|
191
|
+
|
|
192
|
+
// Active feature + summary
|
|
193
|
+
const activeFeature = features[activeTab];
|
|
194
|
+
const activeSnapshot = activeFeature?.getSnapshot();
|
|
195
|
+
const activeSummary = activeFeature ? buildFeatureSummary(activeFeature, activeSnapshot) : null;
|
|
196
|
+
|
|
197
|
+
// Filtered snapshot — reuse activeSnapshot to avoid double getSnapshot()
|
|
198
|
+
const filteredSnapshot = activeFeature
|
|
199
|
+
? filterFeatureSnapshot(activeFeature, activeSnapshot, searchQuery, filterBad ? 'bad' : 'all')
|
|
200
|
+
: null;
|
|
119
201
|
|
|
120
202
|
// Render active feature content
|
|
121
203
|
const renderFeatureContent = () => {
|
|
@@ -124,7 +206,7 @@ export function FloatPanelView({ features, panelOpen, onOpenPanel, onClosePanel,
|
|
|
124
206
|
}
|
|
125
207
|
const feature = features[activeTab];
|
|
126
208
|
if (!feature) return <Text style={styles.emptyText}>Feature not found</Text>;
|
|
127
|
-
const snapshot =
|
|
209
|
+
const snapshot = filteredSnapshot;
|
|
128
210
|
const TabComponent = feature.renderContent;
|
|
129
211
|
if (TabComponent) return <TabComponent snapshot={snapshot} feature={feature} />;
|
|
130
212
|
return (
|
|
@@ -134,6 +216,8 @@ export function FloatPanelView({ features, panelOpen, onOpenPanel, onClosePanel,
|
|
|
134
216
|
);
|
|
135
217
|
};
|
|
136
218
|
|
|
219
|
+
const showSearch = activeSummary ? (activeSummary.count != null && activeSummary.count > 0) : false;
|
|
220
|
+
|
|
137
221
|
return (
|
|
138
222
|
<DebugErrorBoundary onError={onClosePanel}>
|
|
139
223
|
<View style={styles.container} pointerEvents="box-none">
|
|
@@ -141,18 +225,35 @@ export function FloatPanelView({ features, panelOpen, onOpenPanel, onClosePanel,
|
|
|
141
225
|
{panelOpen && (
|
|
142
226
|
<DebugPanel
|
|
143
227
|
onClose={onClosePanel}
|
|
144
|
-
onClearAll={
|
|
228
|
+
onClearAll={handleClearAll}
|
|
229
|
+
syncLabel={panelConnectionStatus.label}
|
|
230
|
+
syncColor={panelConnectionStatus.color}
|
|
145
231
|
>
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
style={
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
232
|
+
<View style={styles.bodyRow}>
|
|
233
|
+
<FeatureRail items={railItems} activeIndex={activeTab} onSelectTab={switchTab} />
|
|
234
|
+
<View style={styles.contentColumn}>
|
|
235
|
+
{activeFeature && activeSummary && (
|
|
236
|
+
<FeatureIntroCard
|
|
237
|
+
title={activeFeature.label}
|
|
238
|
+
summary={activeSummary}
|
|
239
|
+
filterBad={filterBad}
|
|
240
|
+
onFilterBad={setFilterBad}
|
|
241
|
+
searchQuery={searchQuery}
|
|
242
|
+
onSearchChange={setSearchQuery}
|
|
243
|
+
showSearch={showSearch}
|
|
244
|
+
/>
|
|
245
|
+
)}
|
|
246
|
+
<Animated.View
|
|
247
|
+
style={[
|
|
248
|
+
styles.contentContainer,
|
|
249
|
+
{ opacity: contentOpacity, transform: [{ translateX: contentTranslateX }] },
|
|
250
|
+
]}
|
|
251
|
+
{...panHandlers}
|
|
252
|
+
>
|
|
253
|
+
{renderFeatureContent()}
|
|
254
|
+
</Animated.View>
|
|
255
|
+
</View>
|
|
256
|
+
</View>
|
|
156
257
|
</DebugPanel>
|
|
157
258
|
)}
|
|
158
259
|
</View>
|
|
@@ -169,6 +270,13 @@ const styles = StyleSheet.create({
|
|
|
169
270
|
bottom: 0,
|
|
170
271
|
zIndex: 999,
|
|
171
272
|
},
|
|
273
|
+
bodyRow: {
|
|
274
|
+
flex: 1,
|
|
275
|
+
flexDirection: 'row',
|
|
276
|
+
},
|
|
277
|
+
contentColumn: {
|
|
278
|
+
flex: 1,
|
|
279
|
+
},
|
|
172
280
|
contentContainer: { flex: 1 },
|
|
173
281
|
emptyText: {
|
|
174
282
|
padding: 20,
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import type { AnyDebugFeature } from '../../types';
|
|
2
|
+
|
|
3
|
+
export interface FeatureSummary {
|
|
4
|
+
capabilityText: string;
|
|
5
|
+
count?: number;
|
|
6
|
+
badCount?: number;
|
|
7
|
+
latestLabel?: string;
|
|
8
|
+
statusLabel?: string;
|
|
9
|
+
statusColor?: string;
|
|
10
|
+
filterMode?: 'all' | 'bad';
|
|
11
|
+
supportsBadFilter: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function buildFeatureSummary(
|
|
15
|
+
feature: AnyDebugFeature,
|
|
16
|
+
snapshot: unknown,
|
|
17
|
+
): FeatureSummary {
|
|
18
|
+
const name = feature.name;
|
|
19
|
+
|
|
20
|
+
if (name === 'network') return buildNetworkSummary(snapshot);
|
|
21
|
+
if (name === 'console') return buildConsoleSummary(snapshot);
|
|
22
|
+
if (name === 'navigation') return buildNavigationSummary(snapshot);
|
|
23
|
+
if (name === 'zustand') return buildZustandSummary(snapshot);
|
|
24
|
+
if (name === 'track') return buildTrackSummary(snapshot);
|
|
25
|
+
if (name === 'clipboard') return buildClipboardSummary(snapshot);
|
|
26
|
+
if (name === 'environment') return buildEnvironmentSummary(snapshot);
|
|
27
|
+
if (name === 'devConnect') return buildDevConnectSummary(snapshot);
|
|
28
|
+
if (name === 'sessionHistory') return buildSessionHistorySummary(snapshot);
|
|
29
|
+
if (name === 'thirdPartyLibs') return buildThirdPartyLibsSummary(snapshot);
|
|
30
|
+
if (name === 'native') return buildNativeSummary(snapshot);
|
|
31
|
+
|
|
32
|
+
return buildUnknownSummary(snapshot);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ─── Per-feature builders ──────────────────────────────
|
|
36
|
+
|
|
37
|
+
interface NetworkItem {
|
|
38
|
+
request?: { method?: string; url?: string };
|
|
39
|
+
response?: { status?: number };
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function buildNetworkSummary(snapshot: unknown): FeatureSummary {
|
|
44
|
+
const items = asArray(snapshot);
|
|
45
|
+
const count = items.length;
|
|
46
|
+
let badCount = 0;
|
|
47
|
+
let latestLabel: string | undefined;
|
|
48
|
+
|
|
49
|
+
if (count > 0) {
|
|
50
|
+
for (const item of items) {
|
|
51
|
+
const n = item as NetworkItem;
|
|
52
|
+
if (n.error || (n.response?.status ?? 0) >= 400) badCount++;
|
|
53
|
+
}
|
|
54
|
+
const last = items[items.length - 1] as NetworkItem;
|
|
55
|
+
const method = last.request?.method?.toUpperCase() ?? '';
|
|
56
|
+
const url = last.request?.url ?? '';
|
|
57
|
+
const status = last.response?.status;
|
|
58
|
+
const path = extractPath(url);
|
|
59
|
+
latestLabel = [method, path, status].filter(Boolean).join(' ');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
capabilityText: 'HTTP capture, status, duration, request and response body',
|
|
64
|
+
count,
|
|
65
|
+
badCount: badCount > 0 ? badCount : undefined,
|
|
66
|
+
latestLabel,
|
|
67
|
+
supportsBadFilter: count > 0,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface ConsoleItem {
|
|
72
|
+
level?: string;
|
|
73
|
+
data?: unknown[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function buildConsoleSummary(snapshot: unknown): FeatureSummary {
|
|
77
|
+
const items = asArray(snapshot);
|
|
78
|
+
const count = items.length;
|
|
79
|
+
let badCount = 0;
|
|
80
|
+
let latestLabel: string | undefined;
|
|
81
|
+
|
|
82
|
+
if (count > 0) {
|
|
83
|
+
for (const item of items) {
|
|
84
|
+
const lvl = (item as ConsoleItem).level ?? '';
|
|
85
|
+
if (lvl === 'warn' || lvl === 'error' || lvl === 'fatal') badCount++;
|
|
86
|
+
}
|
|
87
|
+
const last = items[items.length - 1] as ConsoleItem;
|
|
88
|
+
latestLabel = formatConsoleMessage(last.data);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
capabilityText: 'Console log capture with level filtering',
|
|
93
|
+
count,
|
|
94
|
+
badCount: badCount > 0 ? badCount : undefined,
|
|
95
|
+
latestLabel,
|
|
96
|
+
supportsBadFilter: count > 0,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface NavigationItem {
|
|
101
|
+
from?: string;
|
|
102
|
+
to?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildNavigationSummary(snapshot: unknown): FeatureSummary {
|
|
106
|
+
const items = asArray(snapshot);
|
|
107
|
+
const count = items.length;
|
|
108
|
+
let latestLabel: string | undefined;
|
|
109
|
+
|
|
110
|
+
if (count > 0) {
|
|
111
|
+
const last = items[items.length - 1] as NavigationItem;
|
|
112
|
+
const from = last.from ?? '?';
|
|
113
|
+
const to = last.to ?? '?';
|
|
114
|
+
latestLabel = `${from} → ${to}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
capabilityText: 'Screen navigation tracking with route history',
|
|
119
|
+
count,
|
|
120
|
+
latestLabel,
|
|
121
|
+
supportsBadFilter: false,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface ZustandItem {
|
|
126
|
+
action?: string;
|
|
127
|
+
storeName?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function buildZustandSummary(snapshot: unknown): FeatureSummary {
|
|
131
|
+
const items = asArray(snapshot);
|
|
132
|
+
const count = items.length;
|
|
133
|
+
let latestLabel: string | undefined;
|
|
134
|
+
|
|
135
|
+
if (count > 0) {
|
|
136
|
+
const last = items[items.length - 1] as ZustandItem;
|
|
137
|
+
const parts = [last.action, last.storeName].filter(Boolean);
|
|
138
|
+
latestLabel = parts.join(' @ ') || undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
capabilityText: 'State change tracking for Zustand stores',
|
|
143
|
+
count,
|
|
144
|
+
latestLabel,
|
|
145
|
+
supportsBadFilter: false,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface TrackItem {
|
|
150
|
+
eventName?: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildTrackSummary(snapshot: unknown): FeatureSummary {
|
|
154
|
+
const items = asArray(snapshot);
|
|
155
|
+
const count = items.length;
|
|
156
|
+
let latestLabel: string | undefined;
|
|
157
|
+
|
|
158
|
+
if (count > 0) {
|
|
159
|
+
const last = items[items.length - 1] as TrackItem;
|
|
160
|
+
latestLabel = last.eventName;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
capabilityText: 'Analytics event tracking and inspection',
|
|
165
|
+
count,
|
|
166
|
+
latestLabel,
|
|
167
|
+
supportsBadFilter: false,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function buildClipboardSummary(_snapshot: unknown): FeatureSummary {
|
|
172
|
+
return {
|
|
173
|
+
capabilityText: 'Clipboard event monitoring',
|
|
174
|
+
supportsBadFilter: false,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
interface EnvironmentSnap {
|
|
179
|
+
environments?: Array<{ id: string; label: string }>;
|
|
180
|
+
currentEnvironmentId?: string | null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function buildEnvironmentSummary(snapshot: unknown): FeatureSummary {
|
|
184
|
+
const env = (snapshot ?? {}) as EnvironmentSnap;
|
|
185
|
+
const envs = env.environments ?? [];
|
|
186
|
+
const current = envs.find((e) => e.id === env.currentEnvironmentId);
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
capabilityText: 'Environment configuration and switching',
|
|
190
|
+
count: envs.length || undefined,
|
|
191
|
+
latestLabel: current?.label,
|
|
192
|
+
statusLabel: current?.label,
|
|
193
|
+
supportsBadFilter: false,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface DevConnectSnap {
|
|
198
|
+
streaming?: boolean;
|
|
199
|
+
computerHost?: string;
|
|
200
|
+
daemonPort?: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function buildDevConnectSummary(snapshot: unknown): FeatureSummary {
|
|
204
|
+
const s = (snapshot ?? {}) as DevConnectSnap;
|
|
205
|
+
const host = [s.computerHost, s.daemonPort].filter(Boolean).join(':');
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
capabilityText: 'Desktop sync with daemon connection',
|
|
209
|
+
statusLabel: host ? `${s.streaming ? 'live' : 'offline'} ${host}` : s.streaming ? 'live' : undefined,
|
|
210
|
+
statusColor: s.streaming ? '#34C759' : undefined,
|
|
211
|
+
supportsBadFilter: false,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
interface SessionHistorySnap {
|
|
216
|
+
sessions?: unknown[];
|
|
217
|
+
currentSessionId?: string;
|
|
218
|
+
logCounts?: Record<string, unknown>;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function buildSessionHistorySummary(snapshot: unknown): FeatureSummary {
|
|
222
|
+
const s = (snapshot ?? {}) as SessionHistorySnap;
|
|
223
|
+
const count = s.sessions?.length;
|
|
224
|
+
return {
|
|
225
|
+
capabilityText: 'Session log recording and replay',
|
|
226
|
+
count: count || undefined,
|
|
227
|
+
latestLabel: s.currentSessionId,
|
|
228
|
+
supportsBadFilter: false,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function buildThirdPartyLibsSummary(snapshot: unknown): FeatureSummary {
|
|
233
|
+
const items = asArray(snapshot);
|
|
234
|
+
return {
|
|
235
|
+
capabilityText: 'Third-party library inspection and management',
|
|
236
|
+
count: items.length || undefined,
|
|
237
|
+
supportsBadFilter: false,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function buildNativeSummary(snapshot: unknown): FeatureSummary {
|
|
242
|
+
const items = asArray(snapshot);
|
|
243
|
+
let badCount = 0;
|
|
244
|
+
for (const item of items) {
|
|
245
|
+
const lvl = (item as { level?: string }).level ?? '';
|
|
246
|
+
if (lvl === 'warn' || lvl === 'error' || lvl === 'fatal') badCount++;
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
capabilityText: 'Native log capture',
|
|
250
|
+
count: items.length || undefined,
|
|
251
|
+
badCount: badCount > 0 ? badCount : undefined,
|
|
252
|
+
supportsBadFilter: items.length > 0,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function buildUnknownSummary(snapshot: unknown): FeatureSummary {
|
|
257
|
+
const items = asArray(snapshot);
|
|
258
|
+
return {
|
|
259
|
+
capabilityText: `${items.length} item${items.length !== 1 ? 's' : ''} captured`,
|
|
260
|
+
count: items.length || undefined,
|
|
261
|
+
supportsBadFilter: false,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ─── Helpers ───────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
function asArray(snap: unknown): unknown[] {
|
|
268
|
+
if (Array.isArray(snap)) return snap;
|
|
269
|
+
return [];
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function extractPath(url: string): string {
|
|
273
|
+
try {
|
|
274
|
+
const u = new URL(url);
|
|
275
|
+
return u.pathname + u.search;
|
|
276
|
+
} catch {
|
|
277
|
+
return url;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function formatConsoleMessage(data: unknown[] | undefined): string | undefined {
|
|
282
|
+
if (!data || data.length === 0) return undefined;
|
|
283
|
+
const joined = data
|
|
284
|
+
.map((d) => (typeof d === 'string' ? d : JSON.stringify(d)))
|
|
285
|
+
.join(' ')
|
|
286
|
+
.slice(0, 60);
|
|
287
|
+
return joined || undefined;
|
|
288
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AnyDebugFeature } from '../../types';
|
|
2
|
+
|
|
3
|
+
export function filterFeatureSnapshot(
|
|
4
|
+
feature: AnyDebugFeature,
|
|
5
|
+
snapshot: unknown,
|
|
6
|
+
query: string,
|
|
7
|
+
filterMode: 'all' | 'bad',
|
|
8
|
+
): unknown {
|
|
9
|
+
if (!Array.isArray(snapshot)) return snapshot;
|
|
10
|
+
|
|
11
|
+
const name = feature.name;
|
|
12
|
+
const supportsBad =
|
|
13
|
+
name === 'network' || name === 'console' || name === 'native';
|
|
14
|
+
|
|
15
|
+
return (snapshot as unknown[]).filter((item) => {
|
|
16
|
+
if (filterMode === 'bad' && supportsBad) {
|
|
17
|
+
if (!isBad(name, item as Record<string, unknown>)) return false;
|
|
18
|
+
}
|
|
19
|
+
if (query) {
|
|
20
|
+
const hay = extractSearchableText(item).toLowerCase();
|
|
21
|
+
if (!hay.includes(query.toLowerCase())) return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isBad(
|
|
28
|
+
featureName: string,
|
|
29
|
+
item: Record<string, unknown>,
|
|
30
|
+
): boolean {
|
|
31
|
+
if (featureName === 'network') {
|
|
32
|
+
const resp = item.response as Record<string, unknown> | undefined;
|
|
33
|
+
return !!(item.error || ((resp?.status as number) ?? 0) >= 400);
|
|
34
|
+
}
|
|
35
|
+
// console, native
|
|
36
|
+
const lvl = (item.level as string) ?? '';
|
|
37
|
+
return lvl === 'warn' || lvl === 'error' || lvl === 'fatal';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function extractSearchableText(item: unknown): string {
|
|
41
|
+
if (item == null) return '';
|
|
42
|
+
if (typeof item === 'string') return item;
|
|
43
|
+
if (typeof item === 'number' || typeof item === 'boolean') return String(item);
|
|
44
|
+
if (Array.isArray(item)) return item.map(extractSearchableText).join(' ');
|
|
45
|
+
const parts: string[] = [];
|
|
46
|
+
for (const val of Object.values(item as Record<string, unknown>)) {
|
|
47
|
+
const t = extractSearchableText(val);
|
|
48
|
+
if (t) parts.push(t);
|
|
49
|
+
}
|
|
50
|
+
return parts.join(' ');
|
|
51
|
+
}
|