react-native-inapp-inspector 1.1.28 → 1.1.31
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/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +29 -80
- package/dist/commonjs/components/AnalyticsDetail.js +668 -108
- package/dist/commonjs/components/AppHeaderLogo.js +15 -15
- package/dist/commonjs/components/ConsoleLogCard.js +112 -66
- package/dist/commonjs/components/CopyButton.js +15 -1
- package/dist/commonjs/components/DomainHeader.js +64 -32
- package/dist/commonjs/components/HighlightText.js +7 -1
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +332 -221
- package/dist/commonjs/components/Inspector/ConsoleTab.js +162 -56
- package/dist/commonjs/components/Inspector/InspectorHeader.js +70 -119
- package/dist/commonjs/components/Inspector/LogDetail.js +53 -17
- package/dist/commonjs/components/Inspector/MainScreen.js +4 -0
- package/dist/commonjs/components/Inspector/NetworkDetail.js +24 -24
- package/dist/commonjs/components/Inspector/NetworkTab.js +4 -1
- package/dist/commonjs/components/Inspector/ReduxDetail.js +237 -42
- package/dist/commonjs/components/Inspector/ReduxTab.js +456 -35
- package/dist/commonjs/components/JsonViewer.js +26 -4
- package/dist/commonjs/components/LogCard.js +103 -11
- package/dist/commonjs/components/NetworkIcons.js +19 -10
- package/dist/commonjs/components/Toast.d.ts +3 -0
- package/dist/commonjs/components/Toast.js +152 -0
- package/dist/commonjs/components/TouchableScale.d.ts +1 -0
- package/dist/commonjs/components/TouchableScale.js +3 -3
- package/dist/commonjs/components/TreeNode.js +12 -2
- package/dist/commonjs/constants/index.js +6 -6
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/reduxLogger.js +128 -5
- package/dist/commonjs/helpers/index.d.ts +4 -0
- package/dist/commonjs/helpers/index.js +107 -92
- package/dist/commonjs/helpers/toast.d.ts +4 -0
- package/dist/commonjs/helpers/toast.js +20 -0
- package/dist/commonjs/i18n/locales/en.json +49 -3
- package/dist/commonjs/styles/AppColors.d.ts +6 -0
- package/dist/commonjs/styles/AppColors.js +6 -0
- package/dist/commonjs/styles/index.d.ts +82 -15
- package/dist/commonjs/styles/index.js +92 -26
- package/dist/commonjs/types/interfaces.d.ts +7 -0
- package/dist/esm/components/AnalyticsDetail.js +670 -110
- package/dist/esm/components/AppHeaderLogo.js +15 -15
- package/dist/esm/components/ConsoleLogCard.js +114 -68
- package/dist/esm/components/CopyButton.js +15 -1
- package/dist/esm/components/DomainHeader.js +64 -32
- package/dist/esm/components/HighlightText.js +7 -1
- package/dist/esm/components/Inspector/AnalyticsTab.js +334 -223
- package/dist/esm/components/Inspector/ConsoleTab.js +163 -57
- package/dist/esm/components/Inspector/InspectorHeader.js +71 -120
- package/dist/esm/components/Inspector/LogDetail.js +55 -19
- package/dist/esm/components/Inspector/MainScreen.js +4 -0
- package/dist/esm/components/Inspector/NetworkDetail.js +25 -25
- package/dist/esm/components/Inspector/NetworkTab.js +4 -1
- package/dist/esm/components/Inspector/ReduxDetail.js +239 -44
- package/dist/esm/components/Inspector/ReduxTab.js +458 -37
- package/dist/esm/components/JsonViewer.js +26 -4
- package/dist/esm/components/LogCard.js +105 -13
- package/dist/esm/components/NetworkIcons.js +19 -10
- package/dist/esm/components/Toast.d.ts +3 -0
- package/dist/esm/components/Toast.js +117 -0
- package/dist/esm/components/TouchableScale.d.ts +1 -0
- package/dist/esm/components/TouchableScale.js +3 -3
- package/dist/esm/components/TreeNode.js +12 -2
- package/dist/esm/constants/index.js +6 -6
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/reduxLogger.js +128 -5
- package/dist/esm/helpers/index.d.ts +4 -0
- package/dist/esm/helpers/index.js +102 -92
- package/dist/esm/helpers/toast.d.ts +4 -0
- package/dist/esm/helpers/toast.js +15 -0
- package/dist/esm/i18n/locales/en.json +49 -3
- package/dist/esm/styles/AppColors.d.ts +6 -0
- package/dist/esm/styles/AppColors.js +6 -0
- package/dist/esm/styles/index.d.ts +82 -15
- package/dist/esm/styles/index.js +92 -26
- package/dist/esm/types/interfaces.d.ts +7 -0
- package/ios/NetworkInspectorModule.m +0 -10
- package/package.json +13 -10
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { Image, Platform, StyleSheet, View, } from 'react-native';
|
|
3
3
|
import BrandSquareIcon from './BrandSquareIcon';
|
|
4
|
-
import { AppColors } from '../styles/AppColors';
|
|
5
4
|
export const AppHeaderLogo = ({ size = 46, customIcon, }) => {
|
|
6
5
|
const [loadError, setLoadError] = useState(false);
|
|
7
|
-
// 1. If customIcon is explicitly provided, render it directly
|
|
6
|
+
// 1. If customIcon is explicitly provided, render it directly edge-to-edge
|
|
8
7
|
if (customIcon) {
|
|
9
8
|
return (<View style={[logoStyles.container, { width: size, height: size }]}>
|
|
10
|
-
<Image source={customIcon} style={
|
|
9
|
+
<Image source={customIcon} style={logoStyles.image} resizeMode="cover"/>
|
|
11
10
|
</View>);
|
|
12
11
|
}
|
|
13
12
|
// 2. Dynamically query installed native app icon (AppIcon on iOS, ic_launcher on Android)
|
|
@@ -18,28 +17,29 @@ export const AppHeaderLogo = ({ size = 46, customIcon, }) => {
|
|
|
18
17
|
default: { uri: 'AppIcon' },
|
|
19
18
|
});
|
|
20
19
|
return (<View style={[logoStyles.container, { width: size, height: size }]}>
|
|
21
|
-
<Image source={nativeSource} style={
|
|
20
|
+
<Image source={nativeSource} style={logoStyles.image} resizeMode="cover" onError={() => setLoadError(true)}/>
|
|
22
21
|
</View>);
|
|
23
22
|
}
|
|
24
23
|
// 3. Fallback: Inspector's Signature Owl Brand Logo
|
|
25
24
|
return (<View style={[logoStyles.container, { width: size, height: size }]}>
|
|
26
|
-
<BrandSquareIcon size={size
|
|
25
|
+
<BrandSquareIcon size={size}/>
|
|
27
26
|
</View>);
|
|
28
27
|
};
|
|
29
28
|
const logoStyles = StyleSheet.create({
|
|
30
29
|
container: {
|
|
30
|
+
borderRadius: 10,
|
|
31
|
+
overflow: 'hidden',
|
|
32
|
+
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
|
33
|
+
borderWidth: 1,
|
|
34
|
+
borderColor: 'rgba(255, 255, 255, 0.28)',
|
|
35
|
+
padding: 2.5,
|
|
31
36
|
alignItems: 'center',
|
|
32
37
|
justifyContent: 'center',
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
shadowColor: AppColors.primaryBlack,
|
|
39
|
-
shadowOffset: { width: 0, height: 2 },
|
|
40
|
-
shadowOpacity: 0.15,
|
|
41
|
-
shadowRadius: 4,
|
|
42
|
-
elevation: 3,
|
|
38
|
+
},
|
|
39
|
+
image: {
|
|
40
|
+
width: '100%',
|
|
41
|
+
height: '100%',
|
|
42
|
+
borderRadius: 7.5,
|
|
43
43
|
},
|
|
44
44
|
});
|
|
45
45
|
export default AppHeaderLogo;
|
|
@@ -3,10 +3,10 @@ import { useTranslation } from '../i18n';
|
|
|
3
3
|
import { Pressable, StyleSheet, Text, View, } from 'react-native';
|
|
4
4
|
import { AppColors } from '../styles/AppColors';
|
|
5
5
|
import { AppFonts } from '../styles/AppFonts';
|
|
6
|
-
import { formatTime, getJsonContent, getJsonPreviewText, parseStackLine, } from '../helpers';
|
|
6
|
+
import { formatTime, getJsonContent, getJsonPreviewText, parseStackLine, openInVSCode, } from '../helpers';
|
|
7
7
|
import HighlightText from './HighlightText';
|
|
8
8
|
import CopyButton from './CopyButton';
|
|
9
|
-
import { ChevronIcon } from './NetworkIcons';
|
|
9
|
+
import { ChevronIcon, ExternalLinkIcon } from './NetworkIcons';
|
|
10
10
|
import { useInspector } from './Inspector/InspectorContext';
|
|
11
11
|
const getLogMessageWithBadges = (message, searchStr, textStyle, highlightStyle, numberOfLines) => {
|
|
12
12
|
if (!message)
|
|
@@ -20,37 +20,37 @@ const getLogMessageWithBadges = (message, searchStr, textStyle, highlightStyle,
|
|
|
20
20
|
const getTagDecorator = (tag) => {
|
|
21
21
|
const clean = tag.replace(/[\[\]]/g, '').trim().toUpperCase();
|
|
22
22
|
if (clean === 'AXIOS') {
|
|
23
|
-
return { color:
|
|
23
|
+
return { color: AppColors.emerald600, icon: '⚡', label: 'AXIOS' };
|
|
24
24
|
}
|
|
25
25
|
if (clean === 'API' || clean === 'FETCH' || clean === 'HTTP' || clean === 'NETWORK') {
|
|
26
|
-
return { color:
|
|
26
|
+
return { color: AppColors.sky600, icon: '🌐', label: clean };
|
|
27
27
|
}
|
|
28
28
|
if (clean === 'SAMPLE' || clean === 'BATCH') {
|
|
29
|
-
return { color:
|
|
29
|
+
return { color: AppColors.indigo600Alt, icon: '🎲', label: clean };
|
|
30
30
|
}
|
|
31
31
|
if (clean === 'REDUX' || clean === 'STORE' || clean === 'STATE') {
|
|
32
|
-
return { color:
|
|
32
|
+
return { color: AppColors.violet600, icon: '⚛️', label: clean };
|
|
33
33
|
}
|
|
34
34
|
if (clean === 'ANALYTICS' || clean === 'FIREBASE' || clean === 'GA4' || clean === 'GA') {
|
|
35
|
-
return { color:
|
|
35
|
+
return { color: AppColors.teal600, icon: '📊', label: clean };
|
|
36
36
|
}
|
|
37
37
|
if (clean === 'AUTH' || clean === 'TOKEN' || clean === 'SESSION') {
|
|
38
|
-
return { color:
|
|
38
|
+
return { color: AppColors.amber600, icon: '🔑', label: clean };
|
|
39
39
|
}
|
|
40
40
|
if (clean === 'APP') {
|
|
41
|
-
return { color:
|
|
41
|
+
return { color: AppColors.indigo600Alt, icon: '📱', label: 'APP' };
|
|
42
42
|
}
|
|
43
43
|
if (clean === 'TEST') {
|
|
44
|
-
return { color:
|
|
44
|
+
return { color: AppColors.emerald500, icon: '🧪', label: 'TEST' };
|
|
45
45
|
}
|
|
46
46
|
if (clean === 'WARN' || clean === 'WARNING') {
|
|
47
|
-
return { color:
|
|
47
|
+
return { color: AppColors.amber600, icon: '⚠️', label: 'WARN' };
|
|
48
48
|
}
|
|
49
49
|
if (clean === 'ERROR' || clean === 'CRASH' || clean === 'BUG') {
|
|
50
|
-
return { color:
|
|
50
|
+
return { color: AppColors.red600, icon: '💥', label: 'ERROR' };
|
|
51
51
|
}
|
|
52
52
|
if (clean === 'PERF' || clean === 'RENDER') {
|
|
53
|
-
return { color:
|
|
53
|
+
return { color: AppColors.violet500, icon: '⚡', label: clean };
|
|
54
54
|
}
|
|
55
55
|
return { color: AppColors.slate600, icon: '🏷️', label: clean };
|
|
56
56
|
};
|
|
@@ -89,51 +89,72 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
|
|
|
89
89
|
? parseStackLine(item.caller, true)
|
|
90
90
|
: null;
|
|
91
91
|
const getLogColors = () => {
|
|
92
|
-
const
|
|
93
|
-
|
|
92
|
+
const type = (item.type || 'log').toLowerCase();
|
|
93
|
+
const method = (item.sourceMethod || type).toLowerCase();
|
|
94
|
+
if (isAnalyticsError || type === 'error' || method === 'error') {
|
|
94
95
|
return {
|
|
95
|
-
border:
|
|
96
|
-
badgeBg:
|
|
97
|
-
badgeText:
|
|
96
|
+
border: '#EF4444',
|
|
97
|
+
badgeBg: '#FEE2E2',
|
|
98
|
+
badgeText: '#DC2626',
|
|
98
99
|
label: 'ERROR',
|
|
99
|
-
cardBg:
|
|
100
|
+
cardBg: '#FEF2F2',
|
|
101
|
+
methodBorder: '#FECACA',
|
|
102
|
+
methodBg: '#FEE2E2',
|
|
103
|
+
methodText: '#DC2626',
|
|
104
|
+
textColor: '#991B1B',
|
|
100
105
|
};
|
|
101
106
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
107
|
+
if (type === 'warn' || method === 'warn') {
|
|
108
|
+
return {
|
|
109
|
+
border: '#F59E0B',
|
|
110
|
+
badgeBg: '#FEF3C7',
|
|
111
|
+
badgeText: '#D97706',
|
|
112
|
+
label: 'WARN',
|
|
113
|
+
cardBg: '#FFFBEB',
|
|
114
|
+
methodBorder: '#FDE68A',
|
|
115
|
+
methodBg: '#FEF3C7',
|
|
116
|
+
methodText: '#D97706',
|
|
117
|
+
textColor: '#92400E',
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (type === 'debug' || method === 'debug') {
|
|
121
|
+
return {
|
|
122
|
+
border: '#8B5CF6',
|
|
123
|
+
badgeBg: '#EDE9FE',
|
|
124
|
+
badgeText: '#7C3AED',
|
|
125
|
+
label: 'DEBUG',
|
|
126
|
+
cardBg: '#F5F3FF',
|
|
127
|
+
methodBorder: '#DDD6FE',
|
|
128
|
+
methodBg: '#EDE9FE',
|
|
129
|
+
methodText: '#7C3AED',
|
|
130
|
+
textColor: '#4C1D95',
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (type === 'info' || method === 'info') {
|
|
134
|
+
return {
|
|
135
|
+
border: '#0EA5E9',
|
|
136
|
+
badgeBg: '#E0F2FE',
|
|
137
|
+
badgeText: '#0284C7',
|
|
138
|
+
label: 'INFO',
|
|
139
|
+
cardBg: '#F0F9FF',
|
|
140
|
+
methodBorder: '#BAE6FD',
|
|
141
|
+
methodBg: '#E0F2FE',
|
|
142
|
+
methodText: '#0284C7',
|
|
143
|
+
textColor: '#075985',
|
|
144
|
+
};
|
|
136
145
|
}
|
|
146
|
+
// Default / Standard console.log
|
|
147
|
+
return {
|
|
148
|
+
border: '#6366F1',
|
|
149
|
+
badgeBg: '#EEF2FF',
|
|
150
|
+
badgeText: '#4F46E5',
|
|
151
|
+
label: 'LOG',
|
|
152
|
+
cardBg: '#FFFFFF',
|
|
153
|
+
methodBorder: '#E0E7FF',
|
|
154
|
+
methodBg: '#EEF2FF',
|
|
155
|
+
methodText: '#4F46E5',
|
|
156
|
+
textColor: '#0F172A',
|
|
157
|
+
};
|
|
137
158
|
};
|
|
138
159
|
const colors = getLogColors();
|
|
139
160
|
const jsonPreview = jsonContent
|
|
@@ -147,6 +168,7 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
|
|
|
147
168
|
styles.card,
|
|
148
169
|
{
|
|
149
170
|
borderLeftColor: colors.border,
|
|
171
|
+
borderLeftWidth: 3.5,
|
|
150
172
|
backgroundColor: colors.cardBg,
|
|
151
173
|
},
|
|
152
174
|
pressed && styles.cardPressed,
|
|
@@ -155,18 +177,18 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
|
|
|
155
177
|
<View style={styles.headerLeft}>
|
|
156
178
|
<View style={[styles.typeChip, { backgroundColor: colors.badgeBg }]}>
|
|
157
179
|
<View style={[styles.typeDot, { backgroundColor: colors.badgeText }]}/>
|
|
158
|
-
<Text style={[styles.typeChipText, { color: colors.badgeText }]}>
|
|
180
|
+
<Text style={[styles.typeChipText, { color: colors.badgeText, fontFamily: AppFonts.interBold }]}>
|
|
159
181
|
{colors.label}
|
|
160
182
|
</Text>
|
|
161
183
|
</View>
|
|
162
184
|
<View style={[
|
|
163
185
|
styles.metaChip,
|
|
164
186
|
{
|
|
165
|
-
backgroundColor:
|
|
166
|
-
borderColor:
|
|
187
|
+
backgroundColor: colors.methodBg,
|
|
188
|
+
borderColor: colors.methodBorder,
|
|
167
189
|
},
|
|
168
190
|
]}>
|
|
169
|
-
<Text style={[styles.metaChipText, { color:
|
|
191
|
+
<Text style={[styles.metaChipText, { color: colors.methodText, fontFamily: AppFonts.interBold }]}>
|
|
170
192
|
console.
|
|
171
193
|
{('sourceMethod' in item ? item.sourceMethod : undefined) ||
|
|
172
194
|
item.type ||
|
|
@@ -176,11 +198,11 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
|
|
|
176
198
|
{jsonContent && (<View style={[
|
|
177
199
|
styles.metaChip,
|
|
178
200
|
{
|
|
179
|
-
backgroundColor:
|
|
180
|
-
borderColor:
|
|
201
|
+
backgroundColor: '#ECFDF5',
|
|
202
|
+
borderColor: '#A7F3D0',
|
|
181
203
|
},
|
|
182
204
|
]}>
|
|
183
|
-
<Text style={[styles.metaChipText, { color:
|
|
205
|
+
<Text style={[styles.metaChipText, { color: '#059669', fontFamily: AppFonts.interBold }]}>
|
|
184
206
|
{Array.isArray(jsonContent.data)
|
|
185
207
|
? `Array[${jsonContent.data.length}]`
|
|
186
208
|
: `Object{${Object.keys(jsonContent.data).length}}`}
|
|
@@ -195,7 +217,7 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
|
|
|
195
217
|
borderColor: `${AppColors.purple}3D`,
|
|
196
218
|
},
|
|
197
219
|
]}>
|
|
198
|
-
<Text style={[styles.metaChipText, { color: AppColors.purple }]}>
|
|
220
|
+
<Text style={[styles.metaChipText, { color: AppColors.purple, fontFamily: AppFonts.interBold }]}>
|
|
199
221
|
×{item.duplicateCount}
|
|
200
222
|
</Text>
|
|
201
223
|
</View>)}
|
|
@@ -226,18 +248,34 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
|
|
|
226
248
|
<Text style={styles.footerText}>{formatTime(item.timestamp)}</Text>
|
|
227
249
|
{parsedCaller && (<>
|
|
228
250
|
<View style={styles.footerDot}/>
|
|
229
|
-
<
|
|
251
|
+
<Pressable onPress={e => {
|
|
252
|
+
e.stopPropagation?.();
|
|
253
|
+
openInVSCode(parsedCaller.rawFilePath ||
|
|
254
|
+
parsedCaller.fullPath ||
|
|
255
|
+
parsedCaller.fileName, parsedCaller.lineNumber, parsedCaller.columnNumber);
|
|
256
|
+
}} hitSlop={8} style={{
|
|
257
|
+
flexDirection: 'row',
|
|
258
|
+
alignItems: 'center',
|
|
259
|
+
gap: 4,
|
|
260
|
+
maxWidth: 185,
|
|
261
|
+
backgroundColor: `${AppColors.sky600}10`,
|
|
262
|
+
borderColor: `${AppColors.sky600}2B`,
|
|
263
|
+
borderWidth: 1,
|
|
264
|
+
borderRadius: 5,
|
|
265
|
+
paddingHorizontal: 5,
|
|
266
|
+
paddingVertical: 1.5,
|
|
267
|
+
}}>
|
|
230
268
|
{parsedCaller.fileExt && parsedCaller.fileExt !== 'other' && (<View style={{
|
|
231
269
|
backgroundColor: parsedCaller.fileExt === 'tsx' || parsedCaller.fileExt === 'ts'
|
|
232
|
-
? `${AppColors.brandPurple}
|
|
233
|
-
: `${AppColors.teal600}
|
|
270
|
+
? `${AppColors.brandPurple}22`
|
|
271
|
+
: `${AppColors.teal600}22`,
|
|
234
272
|
borderRadius: 3,
|
|
235
273
|
paddingHorizontal: 3.5,
|
|
236
|
-
paddingVertical:
|
|
274
|
+
paddingVertical: 0.5,
|
|
237
275
|
}}>
|
|
238
276
|
<Text style={{
|
|
239
277
|
fontFamily: AppFonts.interBold,
|
|
240
|
-
fontSize: 8
|
|
278
|
+
fontSize: 8,
|
|
241
279
|
color: parsedCaller.fileExt === 'tsx' || parsedCaller.fileExt === 'ts'
|
|
242
280
|
? AppColors.brandPurple
|
|
243
281
|
: AppColors.teal600,
|
|
@@ -245,11 +283,19 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
|
|
|
245
283
|
{parsedCaller.fileExt.toUpperCase()}
|
|
246
284
|
</Text>
|
|
247
285
|
</View>)}
|
|
248
|
-
<Text style={[
|
|
286
|
+
<Text style={[
|
|
287
|
+
styles.footerText,
|
|
288
|
+
{
|
|
289
|
+
fontFamily: AppFonts.interBold,
|
|
290
|
+
color: AppColors.sky600,
|
|
291
|
+
fontSize: 9.5,
|
|
292
|
+
},
|
|
293
|
+
]} numberOfLines={1} ellipsizeMode="middle">
|
|
249
294
|
{parsedCaller.fileName}
|
|
250
295
|
{parsedCaller.lineNumber ? `:${parsedCaller.lineNumber}` : ''}
|
|
251
296
|
</Text>
|
|
252
|
-
|
|
297
|
+
<ExternalLinkIcon color={AppColors.sky600} size={8.5}/>
|
|
298
|
+
</Pressable>
|
|
253
299
|
</>)}
|
|
254
300
|
</View>
|
|
255
301
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import { Share } from 'react-native';
|
|
2
3
|
// Components
|
|
3
4
|
import TouchableScale from './TouchableScale';
|
|
4
5
|
// Helpers
|
|
@@ -16,6 +17,19 @@ const CopyButton = React.memo(({ value, label, iconType = 'copy' }) => {
|
|
|
16
17
|
setCopied(true);
|
|
17
18
|
setTimeout(() => setCopied(false), 1200);
|
|
18
19
|
}, [value, label]);
|
|
20
|
+
const handleLongPress = useCallback(() => {
|
|
21
|
+
try {
|
|
22
|
+
const resolvedValue = typeof value === 'function' ? value() : value;
|
|
23
|
+
const textToShare = typeof resolvedValue === 'string'
|
|
24
|
+
? resolvedValue
|
|
25
|
+
: JSON.stringify(resolvedValue, null, 2);
|
|
26
|
+
Share.share({
|
|
27
|
+
message: textToShare,
|
|
28
|
+
title: label,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch { }
|
|
32
|
+
}, [value, label]);
|
|
19
33
|
const containerStyle = [
|
|
20
34
|
styles.iconSquareBtn,
|
|
21
35
|
copied && styles.iconSquareBtnSuccess,
|
|
@@ -25,7 +39,7 @@ const CopyButton = React.memo(({ value, label, iconType = 'copy' }) => {
|
|
|
25
39
|
: iconType === 'fetch'
|
|
26
40
|
? FetchIcon
|
|
27
41
|
: CopyIcon;
|
|
28
|
-
return (<TouchableScale onPress={handlePress} hitSlop={12} style={containerStyle}>
|
|
42
|
+
return (<TouchableScale onPress={handlePress} onLongPress={handleLongPress} hitSlop={12} style={containerStyle}>
|
|
29
43
|
{copied ? (<CheckIcon color={AppColors.greenColor} size={14}/>) : (<IconComponent color={AppColors.grayTextWeak} size={14}/>)}
|
|
30
44
|
</TouchableScale>);
|
|
31
45
|
});
|
|
@@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react';
|
|
|
2
2
|
import { Animated, Pressable, View, Text } from 'react-native';
|
|
3
3
|
// Stylesheet
|
|
4
4
|
import { AppColors } from '../styles/AppColors';
|
|
5
|
+
import { AppFonts } from '../styles/AppFonts';
|
|
5
6
|
// Helpers
|
|
6
7
|
import { formatDateTime } from '../helpers';
|
|
7
8
|
// Assets
|
|
@@ -26,20 +27,75 @@ const DomainHeader = ({ pageName, color, stats, activeFilters, onToggleFilter, i
|
|
|
26
27
|
const pctSuccess = total > 0 ? Math.round((stats.success / total) * 100) : 0;
|
|
27
28
|
const pctFailed = total > 0 ? Math.round((stats.failed / total) * 100) : 0;
|
|
28
29
|
const pctLoading = total > 0 ? Math.round((stats.loading / total) * 100) : 0;
|
|
29
|
-
return (<Pressable style={
|
|
30
|
+
return (<Pressable style={[
|
|
31
|
+
styles.domainHeaderCard,
|
|
32
|
+
!isCollapsed && styles.domainHeaderCardExpanded,
|
|
33
|
+
]} onPress={() => onToggleCollapse(pageName)}>
|
|
30
34
|
<View style={styles.domainHeaderTopRow}>
|
|
31
35
|
<View style={styles.domainHeaderLeft}>
|
|
32
|
-
<Animated.View style={{ transform: [{ rotate: chevronRotate }] }}>
|
|
36
|
+
<Animated.View style={{ transform: [{ rotate: chevronRotate }], flexShrink: 0 }}>
|
|
33
37
|
<ChevronIcon color={AppColors.grayTextWeak} size={13}/>
|
|
34
38
|
</Animated.View>
|
|
35
|
-
<View style={[styles.domainIconWrap, { backgroundColor: `${color}18
|
|
39
|
+
<View style={[styles.domainIconWrap, { backgroundColor: `${color}18`, flexShrink: 0 }]}>
|
|
36
40
|
<ScreenIcon color={color} size={14}/>
|
|
37
41
|
</View>
|
|
38
|
-
<View style={{ flex: 1, justifyContent: 'center' }}>
|
|
39
|
-
<
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
<View style={{ flex: 1, justifyContent: 'center', minWidth: 0 }}>
|
|
43
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, minWidth: 0 }}>
|
|
44
|
+
<Text style={[styles.domainTitleText, { flexShrink: 1 }]} numberOfLines={1} ellipsizeMode="tail">
|
|
45
|
+
{pageName}
|
|
46
|
+
</Text>
|
|
47
|
+
{total > 0 && (<View style={{
|
|
48
|
+
flexDirection: 'row',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
gap: 4,
|
|
51
|
+
backgroundColor: stats.failed > 0
|
|
52
|
+
? AppColors.red100
|
|
53
|
+
: stats.loading > 0
|
|
54
|
+
? AppColors.amber100
|
|
55
|
+
: AppColors.emerald100,
|
|
56
|
+
paddingHorizontal: 5,
|
|
57
|
+
paddingVertical: 1.5,
|
|
58
|
+
borderRadius: 4,
|
|
59
|
+
flexShrink: 0,
|
|
60
|
+
}}>
|
|
61
|
+
<View style={{
|
|
62
|
+
width: 22,
|
|
63
|
+
height: 3.5,
|
|
64
|
+
borderRadius: 2,
|
|
65
|
+
backgroundColor: AppColors.gray200,
|
|
66
|
+
flexDirection: 'row',
|
|
67
|
+
overflow: 'hidden',
|
|
68
|
+
}}>
|
|
69
|
+
{pctSuccess > 0 && (<View style={{
|
|
70
|
+
width: `${pctSuccess}%`,
|
|
71
|
+
height: '100%',
|
|
72
|
+
backgroundColor: AppColors.emerald500,
|
|
73
|
+
}}/>)}
|
|
74
|
+
{pctFailed > 0 && (<View style={{
|
|
75
|
+
width: `${pctFailed}%`,
|
|
76
|
+
height: '100%',
|
|
77
|
+
backgroundColor: AppColors.red500,
|
|
78
|
+
}}/>)}
|
|
79
|
+
{pctLoading > 0 && (<View style={{
|
|
80
|
+
width: `${pctLoading}%`,
|
|
81
|
+
height: '100%',
|
|
82
|
+
backgroundColor: AppColors.amber500,
|
|
83
|
+
}}/>)}
|
|
84
|
+
</View>
|
|
85
|
+
<Text style={{
|
|
86
|
+
fontFamily: AppFonts.interBold,
|
|
87
|
+
fontSize: 8.5,
|
|
88
|
+
color: stats.failed > 0
|
|
89
|
+
? AppColors.redErrorText
|
|
90
|
+
: stats.loading > 0
|
|
91
|
+
? AppColors.amber800Warm
|
|
92
|
+
: AppColors.emerald700,
|
|
93
|
+
}}>
|
|
94
|
+
{pctSuccess}%
|
|
95
|
+
</Text>
|
|
96
|
+
</View>)}
|
|
97
|
+
</View>
|
|
98
|
+
<Text style={styles.domainSummaryText} numberOfLines={1} ellipsizeMode="tail">
|
|
43
99
|
{formatDateTime(timestamp)}
|
|
44
100
|
</Text>
|
|
45
101
|
</View>
|
|
@@ -94,30 +150,6 @@ const DomainHeader = ({ pageName, color, stats, activeFilters, onToggleFilter, i
|
|
|
94
150
|
})}
|
|
95
151
|
</View>
|
|
96
152
|
</View>
|
|
97
|
-
|
|
98
|
-
{total > 0 && (<View style={styles.domainProgressTrack}>
|
|
99
|
-
{pctSuccess > 0 && (<View style={[
|
|
100
|
-
styles.domainProgressSegment,
|
|
101
|
-
{
|
|
102
|
-
width: `${pctSuccess}%`,
|
|
103
|
-
backgroundColor: AppColors.greenColor,
|
|
104
|
-
},
|
|
105
|
-
]}/>)}
|
|
106
|
-
{pctFailed > 0 && (<View style={[
|
|
107
|
-
styles.domainProgressSegment,
|
|
108
|
-
{
|
|
109
|
-
width: `${pctFailed}%`,
|
|
110
|
-
backgroundColor: AppColors.errorColor,
|
|
111
|
-
},
|
|
112
|
-
]}/>)}
|
|
113
|
-
{pctLoading > 0 && (<View style={[
|
|
114
|
-
styles.domainProgressSegment,
|
|
115
|
-
{
|
|
116
|
-
width: `${pctLoading}%`,
|
|
117
|
-
backgroundColor: AppColors.darkOrange,
|
|
118
|
-
},
|
|
119
|
-
]}/>)}
|
|
120
|
-
</View>)}
|
|
121
153
|
</Pressable>);
|
|
122
154
|
};
|
|
123
155
|
export default DomainHeader;
|
|
@@ -3,6 +3,12 @@ import { Text } from 'react-native';
|
|
|
3
3
|
// Helpers
|
|
4
4
|
import { escapeRegex, handleOpenExternalLink } from '../helpers';
|
|
5
5
|
const HighlightText = React.memo(function HighlightText({ text, search, style, highlightStyle, detectLinks, numberOfLines, ...rest }) {
|
|
6
|
+
// Optimization: For huge strings (> 20KB) with no active search, bypass all splitting/regex overhead
|
|
7
|
+
if (!text || (text.length > 20000 && !search && !detectLinks)) {
|
|
8
|
+
return (<Text style={style} numberOfLines={numberOfLines} {...rest}>
|
|
9
|
+
{text}
|
|
10
|
+
</Text>);
|
|
11
|
+
}
|
|
6
12
|
// Regex to detect absolute URLs
|
|
7
13
|
const URL_REGEX = /(https?:\/\/[^\s]+)/g;
|
|
8
14
|
const renderNormalOrHighlighted = (subText, keyPrefix) => {
|
|
@@ -17,7 +23,7 @@ const HighlightText = React.memo(function HighlightText({ text, search, style, h
|
|
|
17
23
|
</Text>) : (<Text key={i}>{part}</Text>))}
|
|
18
24
|
</Text>);
|
|
19
25
|
};
|
|
20
|
-
if (detectLinks && text) {
|
|
26
|
+
if (detectLinks && text && text.length < 20000) {
|
|
21
27
|
const parts = text.split(URL_REGEX);
|
|
22
28
|
return (<Text style={style} numberOfLines={numberOfLines} {...rest}>
|
|
23
29
|
{parts.map((part, i) => {
|