react-native-inapp-inspector 1.1.27 → 1.1.29
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 -46
- package/dist/commonjs/components/AppHeaderLogo.js +12 -15
- package/dist/commonjs/components/ConsoleLogCard.js +31 -7
- package/dist/commonjs/components/CopyButton.js +15 -1
- package/dist/commonjs/components/DomainHeader.js +56 -28
- package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
- package/dist/commonjs/components/ErrorBoundary.js +530 -100
- package/dist/commonjs/components/HighlightText.js +7 -1
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +190 -126
- package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -0
- package/dist/commonjs/components/Inspector/BundleTab.js +145 -21
- package/dist/commonjs/components/Inspector/CrashTab.js +0 -8
- package/dist/commonjs/components/Inspector/InspectorHeader.js +17 -3
- package/dist/commonjs/components/Inspector/LogDetail.js +8 -5
- package/dist/commonjs/components/Inspector/MainScreen.js +4 -0
- package/dist/commonjs/components/Inspector/NetworkDetail.js +65 -24
- package/dist/commonjs/components/Inspector/PerformanceTab.d.ts +5 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.js +588 -155
- package/dist/commonjs/components/Inspector/SettingsPanel.js +57 -22
- package/dist/commonjs/components/Inspector/TabBar.js +13 -1
- package/dist/commonjs/components/JsonViewer.js +25 -3
- package/dist/commonjs/components/LogCard.js +173 -40
- package/dist/commonjs/components/NetworkIcons.d.ts +112 -102
- 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 +1 -1
- 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/analyticsLogger.d.ts +1 -11
- package/dist/commonjs/customHooks/analyticsLogger.js +8 -1
- package/dist/commonjs/customHooks/bundleAnalyzer.js +121 -124
- package/dist/commonjs/customHooks/networkLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/networkLogger.js +16 -0
- package/dist/commonjs/customHooks/performanceTracker.d.ts +74 -0
- package/dist/commonjs/customHooks/performanceTracker.js +546 -392
- package/dist/commonjs/customHooks/reduxLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/reduxLogger.js +3 -1
- package/dist/commonjs/helpers/index.d.ts +4 -0
- package/dist/commonjs/helpers/index.js +92 -69
- package/dist/commonjs/helpers/toast.d.ts +4 -0
- package/dist/commonjs/helpers/toast.js +20 -0
- package/dist/commonjs/i18n/locales/en.json +229 -5
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +36 -2
- package/dist/commonjs/styles/index.d.ts +63 -15
- package/dist/commonjs/styles/index.js +79 -32
- package/dist/commonjs/types/interfaces.d.ts +3 -0
- package/dist/esm/components/AppHeaderLogo.js +12 -15
- package/dist/esm/components/ConsoleLogCard.js +33 -9
- package/dist/esm/components/CopyButton.js +15 -1
- package/dist/esm/components/DomainHeader.js +56 -28
- package/dist/esm/components/ErrorBoundary.d.ts +1 -1
- package/dist/esm/components/ErrorBoundary.js +498 -101
- package/dist/esm/components/HighlightText.js +7 -1
- package/dist/esm/components/Inspector/AnalyticsTab.js +191 -127
- package/dist/esm/components/Inspector/BundleTab.d.ts +1 -0
- package/dist/esm/components/Inspector/BundleTab.js +145 -23
- package/dist/esm/components/Inspector/CrashTab.js +0 -8
- package/dist/esm/components/Inspector/InspectorHeader.js +18 -4
- package/dist/esm/components/Inspector/LogDetail.js +10 -7
- package/dist/esm/components/Inspector/MainScreen.js +4 -0
- package/dist/esm/components/Inspector/NetworkDetail.js +66 -25
- package/dist/esm/components/Inspector/PerformanceTab.d.ts +5 -0
- package/dist/esm/components/Inspector/PerformanceTab.js +591 -158
- package/dist/esm/components/Inspector/SettingsPanel.js +57 -22
- package/dist/esm/components/Inspector/TabBar.js +13 -1
- package/dist/esm/components/JsonViewer.js +25 -3
- package/dist/esm/components/LogCard.js +175 -42
- package/dist/esm/components/NetworkIcons.d.ts +112 -102
- 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 +1 -1
- 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/analyticsLogger.d.ts +1 -11
- package/dist/esm/customHooks/analyticsLogger.js +6 -0
- package/dist/esm/customHooks/bundleAnalyzer.js +121 -124
- package/dist/esm/customHooks/networkLogger.d.ts +1 -0
- package/dist/esm/customHooks/networkLogger.js +16 -0
- package/dist/esm/customHooks/performanceTracker.d.ts +74 -0
- package/dist/esm/customHooks/performanceTracker.js +531 -391
- package/dist/esm/customHooks/reduxLogger.d.ts +1 -0
- package/dist/esm/customHooks/reduxLogger.js +1 -0
- package/dist/esm/helpers/index.d.ts +4 -0
- package/dist/esm/helpers/index.js +87 -69
- package/dist/esm/helpers/toast.d.ts +4 -0
- package/dist/esm/helpers/toast.js +15 -0
- package/dist/esm/i18n/locales/en.json +229 -5
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +24 -3
- package/dist/esm/styles/index.d.ts +63 -15
- package/dist/esm/styles/index.js +79 -32
- package/dist/esm/types/interfaces.d.ts +3 -0
- package/package.json +4 -1
|
@@ -13,8 +13,12 @@ import { clearNetworkLogs } from '../../customHooks/networkLogger';
|
|
|
13
13
|
import { clearConsoleLogs } from '../../customHooks/consoleLogger';
|
|
14
14
|
import { clearAnalyticsEvents } from '../../customHooks/analyticsLogger';
|
|
15
15
|
import { clearCrashRecords, } from '../../customHooks/crashHandler';
|
|
16
|
+
import { isReduxConnected } from '../../customHooks/reduxLogger';
|
|
17
|
+
import { isAnalyticsConnected } from '../../customHooks/analyticsLogger';
|
|
18
|
+
import { useTranslation } from '../../i18n';
|
|
16
19
|
import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, WhiteBackNavigation, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, ShieldAlertIcon, } from '../NetworkIcons';
|
|
17
20
|
const SettingsPanel = () => {
|
|
21
|
+
const { t } = useTranslation();
|
|
18
22
|
const { settingsPage, setSettingsPage, settingsActiveSubTab, setSettingsActiveSubTab, tabVisibility, toggleTabVisibility, defaultTab, setDefaultTab, isDark, setIsDark, modalHeightPercent, setModalHeightPercent, modalAnimationType, setModalAnimationType, showDuplicateLogs, setShowDuplicateLogs, showConsoleLevels, setShowConsoleLevels, resetToDefaults, storage, logs, consoleLogs, analyticsEvents, reduxState, maxNetworkLogs, setMaxNetworkLogs, maxConsoleLogs, setMaxConsoleLogs, reduxAutoRefresh, setReduxAutoRefreshState, reduxExpandDepth, setReduxExpandDepth, switchActiveTab, setSelected, setSelectedEvent, setReduxState, crashRecords, maxCrashLogs, setMaxCrashLogs, } = useInspector();
|
|
19
23
|
const isPersistent = isPersistentStorageAvailable();
|
|
20
24
|
const headerTopPadding = Platform.OS === 'ios' && modalHeightPercent >= 95 ? 44 : 0;
|
|
@@ -185,9 +189,14 @@ const SettingsPanel = () => {
|
|
|
185
189
|
</View>
|
|
186
190
|
|
|
187
191
|
{settingsTabs.map((tab, idx) => {
|
|
188
|
-
const
|
|
192
|
+
const isReduxAvail = isReduxConnected();
|
|
193
|
+
const isAnalyticsAvail = isAnalyticsConnected();
|
|
194
|
+
const isUnavailable = (tab.key === 'redux' && !isReduxAvail) ||
|
|
195
|
+
(tab.key === 'analytics' && !isAnalyticsAvail);
|
|
196
|
+
const isLocked = tab.key === 'apis' || isUnavailable;
|
|
197
|
+
const isVisible = tab.key === 'apis' ||
|
|
198
|
+
(Boolean(tabVisibility?.[tab.key]) && !isUnavailable);
|
|
189
199
|
const isLast = idx === settingsTabs.length - 1;
|
|
190
|
-
const isLocked = tab.key === 'apis';
|
|
191
200
|
return (<View key={tab.key} style={{
|
|
192
201
|
flexDirection: 'row',
|
|
193
202
|
alignItems: 'center',
|
|
@@ -203,6 +212,7 @@ const SettingsPanel = () => {
|
|
|
203
212
|
flexDirection: 'row',
|
|
204
213
|
alignItems: 'center',
|
|
205
214
|
gap: 8,
|
|
215
|
+
flexWrap: 'wrap',
|
|
206
216
|
}}>
|
|
207
217
|
{/* Small icon tile */}
|
|
208
218
|
<View style={{
|
|
@@ -251,8 +261,28 @@ const SettingsPanel = () => {
|
|
|
251
261
|
}}>
|
|
252
262
|
{tab.label}
|
|
253
263
|
</Text>
|
|
264
|
+
{/* Unavailable badge */}
|
|
265
|
+
{isUnavailable && (<View style={{
|
|
266
|
+
backgroundColor: `${AppColors.amber500}18`,
|
|
267
|
+
borderRadius: 4,
|
|
268
|
+
paddingHorizontal: 5,
|
|
269
|
+
paddingVertical: 1.5,
|
|
270
|
+
borderWidth: 1,
|
|
271
|
+
borderColor: `${AppColors.amber500}35`,
|
|
272
|
+
}}>
|
|
273
|
+
<Text style={{
|
|
274
|
+
fontFamily: AppFonts.interBold,
|
|
275
|
+
fontSize: 8,
|
|
276
|
+
color: AppColors.amber700,
|
|
277
|
+
letterSpacing: 0.3,
|
|
278
|
+
}}>
|
|
279
|
+
{tab.key === 'redux'
|
|
280
|
+
? t('settings.notConnectedBadge')
|
|
281
|
+
: t('settings.notDetectedBadge')}
|
|
282
|
+
</Text>
|
|
283
|
+
</View>)}
|
|
254
284
|
{/* #6 — badge marks the configured default tab */}
|
|
255
|
-
{tab.key === defaultTab && (<View style={{
|
|
285
|
+
{tab.key === defaultTab && !isUnavailable && (<View style={{
|
|
256
286
|
flexDirection: 'row',
|
|
257
287
|
alignItems: 'center',
|
|
258
288
|
backgroundColor: `${AppColors.purple}14`,
|
|
@@ -281,21 +311,21 @@ const SettingsPanel = () => {
|
|
|
281
311
|
</View>)}
|
|
282
312
|
|
|
283
313
|
{/* Settings gear icon next to label */}
|
|
284
|
-
<TouchableScale onPress={() => {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
314
|
+
{!isUnavailable && (<TouchableScale onPress={() => {
|
|
315
|
+
animateNextLayout();
|
|
316
|
+
setSettingsPage(tab.key);
|
|
317
|
+
}} hitSlop={8} style={{
|
|
318
|
+
marginLeft: 4,
|
|
319
|
+
padding: 4,
|
|
320
|
+
borderRadius: 6,
|
|
321
|
+
backgroundColor: AppColors.purpleShade50,
|
|
322
|
+
borderWidth: 1,
|
|
323
|
+
borderColor: `${AppColors.purple}26`,
|
|
324
|
+
alignItems: 'center',
|
|
325
|
+
justifyContent: 'center',
|
|
326
|
+
}}>
|
|
327
|
+
<SettingsIcon color={AppColors.purple} size={10}/>
|
|
328
|
+
</TouchableScale>)}
|
|
299
329
|
</View>
|
|
300
330
|
|
|
301
331
|
{/* Visibility Switch in VISIBILITY column */}
|
|
@@ -345,12 +375,17 @@ const SettingsPanel = () => {
|
|
|
345
375
|
</TouchableScale>
|
|
346
376
|
{isLocked && (<Text style={{
|
|
347
377
|
fontFamily: AppFonts.interBold,
|
|
348
|
-
fontSize:
|
|
349
|
-
color:
|
|
350
|
-
|
|
378
|
+
fontSize: 7.5,
|
|
379
|
+
color: isUnavailable
|
|
380
|
+
? AppColors.amber700
|
|
381
|
+
: AppColors.grayTextWeak,
|
|
382
|
+
letterSpacing: 0.3,
|
|
351
383
|
marginTop: 3,
|
|
384
|
+
textAlign: 'right',
|
|
352
385
|
}}>
|
|
353
|
-
|
|
386
|
+
{tab.key === 'apis'
|
|
387
|
+
? t('settings.requiredBadge')
|
|
388
|
+
: t('settings.readOnlyBadge')}
|
|
354
389
|
</Text>)}
|
|
355
390
|
</View>
|
|
356
391
|
</View>);
|
|
@@ -5,8 +5,12 @@ import TouchableScale from '../TouchableScale';
|
|
|
5
5
|
import styles from '../../styles';
|
|
6
6
|
import { AppColors } from '../../styles/AppColors';
|
|
7
7
|
import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, } from '../NetworkIcons';
|
|
8
|
+
import { isReduxConnected } from '../../customHooks/reduxLogger';
|
|
9
|
+
import { isAnalyticsConnected } from '../../customHooks/analyticsLogger';
|
|
8
10
|
const TabBar = React.memo(() => {
|
|
9
11
|
const { activeTab, switchActiveTab, tabVisibility, logs, consoleLogs, analyticsEvents, crashRecords, lastReadApisCount, lastReadLogsCount, lastReadCrashesCount, unreadPulseAnim, } = useInspector();
|
|
12
|
+
const isReduxAvail = isReduxConnected();
|
|
13
|
+
const isAnalyticsAvail = isAnalyticsConnected();
|
|
10
14
|
return (<View style={styles.tabBarContainer}>
|
|
11
15
|
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingRight: 16 }}>
|
|
12
16
|
{[
|
|
@@ -53,7 +57,15 @@ const TabBar = React.memo(() => {
|
|
|
53
57
|
icon: 'crash',
|
|
54
58
|
},
|
|
55
59
|
]
|
|
56
|
-
.filter(tab =>
|
|
60
|
+
.filter(tab => {
|
|
61
|
+
if (!tabVisibility?.[tab.key])
|
|
62
|
+
return false;
|
|
63
|
+
if (tab.key === 'redux' && !isReduxAvail)
|
|
64
|
+
return false;
|
|
65
|
+
if (tab.key === 'analytics' && !isAnalyticsAvail)
|
|
66
|
+
return false;
|
|
67
|
+
return true;
|
|
68
|
+
})
|
|
57
69
|
.map(tab => {
|
|
58
70
|
const isActive = activeTab === tab.key;
|
|
59
71
|
const iconColor = isActive
|
|
@@ -57,7 +57,7 @@ const JsonTableRow = React.memo(({ itemKey, val, search, }) => {
|
|
|
57
57
|
// ── JsonViewer Component ─────────────────────────────────────────────────────
|
|
58
58
|
const JsonViewer = React.memo(({ data, search, forceOpen, defaultExpandDepth, wrap, fullHeight = false, maxHeight, mode: externalMode, onModeChange, hideTabs = false, }) => {
|
|
59
59
|
const { t } = useTranslation();
|
|
60
|
-
const [internalMode, setInternalMode] = useState('
|
|
60
|
+
const [internalMode, setInternalMode] = useState('raw');
|
|
61
61
|
const mode = externalMode ?? internalMode;
|
|
62
62
|
const setMode = (newMode) => {
|
|
63
63
|
if (onModeChange) {
|
|
@@ -78,6 +78,10 @@ const JsonViewer = React.memo(({ data, search, forceOpen, defaultExpandDepth, wr
|
|
|
78
78
|
return String(data);
|
|
79
79
|
}
|
|
80
80
|
}, [data]);
|
|
81
|
+
const [showFullRaw, setShowFullRaw] = useState(false);
|
|
82
|
+
const RAW_LIMIT = 50000;
|
|
83
|
+
const isTruncated = rawText.length > RAW_LIMIT && !showFullRaw;
|
|
84
|
+
const displayRawText = isTruncated ? rawText.slice(0, RAW_LIMIT) : rawText;
|
|
81
85
|
useEffect(() => {
|
|
82
86
|
if (externalMode) {
|
|
83
87
|
setInternalMode(externalMode);
|
|
@@ -148,7 +152,7 @@ const JsonViewer = React.memo(({ data, search, forceOpen, defaultExpandDepth, wr
|
|
|
148
152
|
<View style={contentWrapperStyle}>
|
|
149
153
|
{mode === 'pretty' && (isEmpty ? (<View style={localStyles.emptyTable}>
|
|
150
154
|
<Text style={localStyles.emptyTableText}>
|
|
151
|
-
{t('network.
|
|
155
|
+
{t('network.jsonViewer.emptyPayload')}
|
|
152
156
|
</Text>
|
|
153
157
|
</View>) : (wrap ? (fullHeight ? (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ flexGrow: 1 }}>
|
|
154
158
|
<View style={[styles.codeBlock, { width: '100%' }]}>{tree}</View>
|
|
@@ -163,12 +167,30 @@ const JsonViewer = React.memo(({ data, search, forceOpen, defaultExpandDepth, wr
|
|
|
163
167
|
</ScrollView>))))}
|
|
164
168
|
|
|
165
169
|
{mode === 'raw' && (<ScrollView style={scrollStyle} contentContainerStyle={localStyles.rawContainer} showsVerticalScrollIndicator={true} nestedScrollEnabled={true}>
|
|
166
|
-
<HighlightText text={
|
|
170
|
+
<HighlightText text={displayRawText} search={search} detectLinks={rawText.length < 20000} style={localStyles.rawPlainText} selectable={true} highlightStyle={{
|
|
167
171
|
backgroundColor: AppColors.yellowHighlight,
|
|
168
172
|
color: AppColors.primaryBlack,
|
|
169
173
|
borderRadius: 3,
|
|
170
174
|
paddingHorizontal: 2,
|
|
171
175
|
}}/>
|
|
176
|
+
{isTruncated && (<TouchableOpacity onPress={() => setShowFullRaw(true)} style={{
|
|
177
|
+
marginTop: 10,
|
|
178
|
+
backgroundColor: `${AppColors.brandPurple}15`,
|
|
179
|
+
paddingVertical: 8,
|
|
180
|
+
paddingHorizontal: 12,
|
|
181
|
+
borderRadius: 6,
|
|
182
|
+
alignItems: 'center',
|
|
183
|
+
borderWidth: 1,
|
|
184
|
+
borderColor: `${AppColors.brandPurple}30`,
|
|
185
|
+
}}>
|
|
186
|
+
<Text style={{
|
|
187
|
+
fontFamily: AppFonts.interBold,
|
|
188
|
+
fontSize: 11,
|
|
189
|
+
color: AppColors.brandPurple,
|
|
190
|
+
}}>
|
|
191
|
+
Showing first 50 KB ({Math.round(rawText.length / 1024)} KB total) · Tap to load full
|
|
192
|
+
</Text>
|
|
193
|
+
</TouchableOpacity>)}
|
|
172
194
|
</ScrollView>)}
|
|
173
195
|
|
|
174
196
|
{mode === 'table' && (fullHeight ? (<ScrollView style={scrollStyle}>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
|
-
import { Animated, View, Pressable, Text, StyleSheet } from 'react-native';
|
|
2
|
+
import { Alert, Animated, Linking, View, Pressable, Text, StyleSheet, } from 'react-native';
|
|
3
3
|
import Svg, { Path } from 'react-native-svg';
|
|
4
4
|
import { AppColors } from '../styles/AppColors';
|
|
5
5
|
import { METHOD_COLORS } from '../constants';
|
|
6
|
-
import { getStatusColor, getDurationColor,
|
|
6
|
+
import { getStatusColor, getDurationColor, formatDateTime, getSize, } from '../helpers';
|
|
7
7
|
import { CalendarIcon, ClockIcon, SizeIcon } from './NetworkIcons';
|
|
8
|
+
import { AppFonts } from '../styles/AppFonts';
|
|
8
9
|
import styles from '../styles';
|
|
9
10
|
import HighlightText from './HighlightText';
|
|
10
11
|
import TouchableScale from './TouchableScale';
|
|
@@ -12,6 +13,27 @@ import { useTranslation } from '../i18n';
|
|
|
12
13
|
const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, timelineTotalRange, isNew, isSelected, onToggleSelect, searchStr, }) {
|
|
13
14
|
const { t } = useTranslation();
|
|
14
15
|
const methodColor = METHOD_COLORS[item.method] ?? METHOD_COLORS.ALL;
|
|
16
|
+
const handleOpenUrl = (e) => {
|
|
17
|
+
e?.stopPropagation?.();
|
|
18
|
+
Alert.alert(t('common.openInBrowser') || 'Open in Browser', `${t('common.openInBrowserPrompt') || 'Are you sure you want to open this URL in your external browser?'}\n\n${item.url}`, [
|
|
19
|
+
{ text: t('common.cancel') || 'Cancel', style: 'cancel' },
|
|
20
|
+
{
|
|
21
|
+
text: t('common.open') || 'Open',
|
|
22
|
+
onPress: () => {
|
|
23
|
+
Linking.canOpenURL(item.url)
|
|
24
|
+
.then(supported => {
|
|
25
|
+
if (supported) {
|
|
26
|
+
Linking.openURL(item.url);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
Linking.openURL(item.url).catch(() => { });
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.catch(() => { });
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
};
|
|
15
37
|
const isFailed = item.status === 0 || (item.status != null && item.status >= 400);
|
|
16
38
|
const isLoading = item.status == null;
|
|
17
39
|
const statusColor = getStatusColor(item.status);
|
|
@@ -37,10 +59,6 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
|
|
|
37
59
|
}).start();
|
|
38
60
|
}
|
|
39
61
|
}, [isNew]);
|
|
40
|
-
const path = getPath(item.url);
|
|
41
|
-
const baseUrl = getBaseUrl(item.url) || item.url;
|
|
42
|
-
const slug = path && path !== '/' ? path : item.url;
|
|
43
|
-
const showSlug = slug !== baseUrl && slug !== item.url;
|
|
44
62
|
const triggeredAt = formatDateTime(item.startTime);
|
|
45
63
|
const isJson = item.url.split('?')[0].toLowerCase().endsWith('.json');
|
|
46
64
|
return (<TouchableScale onPress={onPress} style={[
|
|
@@ -51,7 +69,7 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
|
|
|
51
69
|
},
|
|
52
70
|
]}>
|
|
53
71
|
<View style={styles.cardBody}>
|
|
54
|
-
{/* Row 1: Header (Checkbox, Serial, Method Badge,
|
|
72
|
+
{/* Row 1: Header (Checkbox, Serial, Method Badge, Client Tag, Status Pill) */}
|
|
55
73
|
<View style={styles.cardHeaderRow}>
|
|
56
74
|
<View style={styles.cardHeaderLeft}>
|
|
57
75
|
<Pressable onPress={() => onToggleSelect(item.id)} hitSlop={12} style={[
|
|
@@ -71,7 +89,122 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
|
|
|
71
89
|
</Text>
|
|
72
90
|
</View>
|
|
73
91
|
|
|
74
|
-
|
|
92
|
+
{item.client && (<View style={[
|
|
93
|
+
styles.chip,
|
|
94
|
+
{
|
|
95
|
+
backgroundColor: item.client === 'axios'
|
|
96
|
+
? `${AppColors.purple}14`
|
|
97
|
+
: item.client === 'apollo' || item.client === 'graphql'
|
|
98
|
+
? `${AppColors.pink500}14`
|
|
99
|
+
: item.client === 'xhr'
|
|
100
|
+
? `${AppColors.amber500}14`
|
|
101
|
+
: `${AppColors.sky500}14`,
|
|
102
|
+
borderColor: item.client === 'axios'
|
|
103
|
+
? `${AppColors.purple}30`
|
|
104
|
+
: item.client === 'apollo' || item.client === 'graphql'
|
|
105
|
+
? `${AppColors.pink500}30`
|
|
106
|
+
: item.client === 'xhr'
|
|
107
|
+
? `${AppColors.amber500}30`
|
|
108
|
+
: `${AppColors.sky500}30`,
|
|
109
|
+
paddingHorizontal: 4.5,
|
|
110
|
+
paddingVertical: 1,
|
|
111
|
+
borderRadius: 4,
|
|
112
|
+
},
|
|
113
|
+
]}>
|
|
114
|
+
<Text style={[
|
|
115
|
+
styles.chipText,
|
|
116
|
+
{
|
|
117
|
+
fontFamily: AppFonts.interBold,
|
|
118
|
+
fontSize: 8.5,
|
|
119
|
+
color: item.client === 'axios'
|
|
120
|
+
? AppColors.purple
|
|
121
|
+
: item.client === 'apollo' || item.client === 'graphql'
|
|
122
|
+
? AppColors.pink500
|
|
123
|
+
: item.client === 'xhr'
|
|
124
|
+
? AppColors.amber700
|
|
125
|
+
: AppColors.sky600,
|
|
126
|
+
},
|
|
127
|
+
]}>
|
|
128
|
+
{item.client.toUpperCase()}
|
|
129
|
+
</Text>
|
|
130
|
+
</View>)}
|
|
131
|
+
|
|
132
|
+
{/* Protocol / HTTPS Badge */}
|
|
133
|
+
<View style={[
|
|
134
|
+
styles.chip,
|
|
135
|
+
{
|
|
136
|
+
backgroundColor: item.url.toLowerCase().startsWith('https')
|
|
137
|
+
? '#ECFDF5'
|
|
138
|
+
: '#FFFBEB',
|
|
139
|
+
borderColor: item.url.toLowerCase().startsWith('https')
|
|
140
|
+
? '#A7F3D0'
|
|
141
|
+
: '#FDE68A',
|
|
142
|
+
paddingHorizontal: 4,
|
|
143
|
+
paddingVertical: 1,
|
|
144
|
+
borderRadius: 4,
|
|
145
|
+
},
|
|
146
|
+
]}>
|
|
147
|
+
<Text style={[
|
|
148
|
+
styles.chipText,
|
|
149
|
+
{
|
|
150
|
+
fontFamily: AppFonts.interBold,
|
|
151
|
+
fontSize: 8,
|
|
152
|
+
color: item.url.toLowerCase().startsWith('https')
|
|
153
|
+
? '#059669'
|
|
154
|
+
: '#D97706',
|
|
155
|
+
},
|
|
156
|
+
]}>
|
|
157
|
+
{item.url.toLowerCase().startsWith('https') ? 'HTTPS' : 'HTTP'}
|
|
158
|
+
</Text>
|
|
159
|
+
</View>
|
|
160
|
+
|
|
161
|
+
{/* GraphQL Indicator */}
|
|
162
|
+
{(item.url.toLowerCase().includes('graphql') ||
|
|
163
|
+
item.client === 'apollo' ||
|
|
164
|
+
item.client === 'graphql') && (<View style={[
|
|
165
|
+
styles.chip,
|
|
166
|
+
{
|
|
167
|
+
backgroundColor: '#FDF2F8',
|
|
168
|
+
borderColor: '#FBCFE8',
|
|
169
|
+
paddingHorizontal: 4,
|
|
170
|
+
paddingVertical: 1,
|
|
171
|
+
borderRadius: 4,
|
|
172
|
+
},
|
|
173
|
+
]}>
|
|
174
|
+
<Text style={[
|
|
175
|
+
styles.chipText,
|
|
176
|
+
{
|
|
177
|
+
fontFamily: AppFonts.interBold,
|
|
178
|
+
fontSize: 8,
|
|
179
|
+
color: '#DB2777',
|
|
180
|
+
},
|
|
181
|
+
]}>
|
|
182
|
+
GQL
|
|
183
|
+
</Text>
|
|
184
|
+
</View>)}
|
|
185
|
+
|
|
186
|
+
{/* In-Line Duration / Latency Pill */}
|
|
187
|
+
{item.duration != null && !isFailed && (<View style={[
|
|
188
|
+
styles.chip,
|
|
189
|
+
{
|
|
190
|
+
backgroundColor: `${durationColor}12`,
|
|
191
|
+
borderColor: `${durationColor}2E`,
|
|
192
|
+
paddingHorizontal: 4.5,
|
|
193
|
+
paddingVertical: 1,
|
|
194
|
+
borderRadius: 4,
|
|
195
|
+
},
|
|
196
|
+
]}>
|
|
197
|
+
<Text style={[
|
|
198
|
+
styles.chipText,
|
|
199
|
+
{
|
|
200
|
+
fontFamily: AppFonts.interBold,
|
|
201
|
+
fontSize: 8.5,
|
|
202
|
+
color: durationColor,
|
|
203
|
+
},
|
|
204
|
+
]}>
|
|
205
|
+
{item.duration}ms
|
|
206
|
+
</Text>
|
|
207
|
+
</View>)}
|
|
75
208
|
</View>
|
|
76
209
|
|
|
77
210
|
<View style={[
|
|
@@ -108,42 +241,42 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
|
|
|
108
241
|
</View>
|
|
109
242
|
</View>
|
|
110
243
|
|
|
111
|
-
{/* Row 2:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
244
|
+
{/* Row 2: Full URL Capsule Container (Clickable with link prompt) */}
|
|
245
|
+
<View style={styles.cardSlugBox}>
|
|
246
|
+
<Pressable onPress={handleOpenUrl} style={styles.slugLeft} hitSlop={6}>
|
|
247
|
+
<Text style={styles.slugTag}>URL ↗</Text>
|
|
248
|
+
<HighlightText text={item.url} search={searchStr} style={[styles.slugText, { color: AppColors.skyBlue, textDecorationLine: 'underline' }]} highlightStyle={styles.highlight} numberOfLines={2} ellipsizeMode="middle"/>
|
|
249
|
+
</Pressable>
|
|
117
250
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
251
|
+
<View style={styles.slugRight}>
|
|
252
|
+
{isJson && (<View style={[
|
|
253
|
+
styles.chip,
|
|
254
|
+
{
|
|
255
|
+
backgroundColor: `${AppColors.darkOrange}12`,
|
|
256
|
+
borderColor: `${AppColors.darkOrange}28`,
|
|
257
|
+
},
|
|
258
|
+
]}>
|
|
259
|
+
<Text style={[styles.chipText, { color: AppColors.darkOrange }]}>
|
|
260
|
+
.json
|
|
261
|
+
</Text>
|
|
262
|
+
</View>)}
|
|
130
263
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
264
|
+
{item.duplicateCount != null && item.duplicateCount > 1 && (<View style={[
|
|
265
|
+
styles.chip,
|
|
266
|
+
{
|
|
267
|
+
backgroundColor: `${AppColors.purple}12`,
|
|
268
|
+
borderColor: `${AppColors.purple}28`,
|
|
269
|
+
},
|
|
270
|
+
]}>
|
|
271
|
+
<Text style={[
|
|
272
|
+
styles.chipText,
|
|
273
|
+
{ color: AppColors.purple, fontWeight: '700' },
|
|
274
|
+
]}>
|
|
275
|
+
×{item.duplicateCount}
|
|
276
|
+
</Text>
|
|
277
|
+
</View>)}
|
|
278
|
+
</View>
|
|
279
|
+
</View>
|
|
147
280
|
|
|
148
281
|
{/* Row 3: Footer (Timestamp on Left, Response Size & Duration on Right) */}
|
|
149
282
|
<View style={styles.cardFooterRow}>
|