react-native-inapp-inspector 2.3.9 → 2.3.11

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.
Files changed (65) hide show
  1. package/dist/commonjs/components/Inspector/DebuggingTab.d.ts +3 -0
  2. package/dist/commonjs/components/Inspector/DebuggingTab.js +682 -0
  3. package/dist/commonjs/components/Inspector/MainScreen.js +2 -0
  4. package/dist/commonjs/components/Inspector/NetworkDetail.js +2 -1
  5. package/dist/commonjs/components/Inspector/NetworkFilterModal.d.ts +19 -0
  6. package/dist/commonjs/components/Inspector/NetworkFilterModal.js +648 -0
  7. package/dist/commonjs/components/Inspector/NetworkTab.js +89 -147
  8. package/dist/commonjs/components/Inspector/SettingsPanel.js +12 -0
  9. package/dist/commonjs/components/Inspector/TabBar.js +9 -0
  10. package/dist/commonjs/components/LogCard.js +5 -26
  11. package/dist/commonjs/components/NetworkIcons.d.ts +2 -0
  12. package/dist/commonjs/components/NetworkIcons.js +13 -1
  13. package/dist/commonjs/components/QRCodeView.d.ts +9 -0
  14. package/dist/commonjs/components/QRCodeView.js +79 -0
  15. package/dist/commonjs/constants/index.js +3 -0
  16. package/dist/commonjs/constants/version.d.ts +1 -1
  17. package/dist/commonjs/constants/version.js +1 -1
  18. package/dist/commonjs/helpers/qrGenerator.d.ts +2 -0
  19. package/dist/commonjs/helpers/qrGenerator.js +170 -0
  20. package/dist/commonjs/index.js +2 -0
  21. package/dist/commonjs/styles/index.d.ts +11 -0
  22. package/dist/commonjs/styles/index.js +20 -5
  23. package/dist/commonjs/types/enums.d.ts +5 -0
  24. package/dist/commonjs/types/enums.js +5 -0
  25. package/dist/esm/components/Inspector/DebuggingTab.d.ts +3 -0
  26. package/dist/esm/components/Inspector/DebuggingTab.js +642 -0
  27. package/dist/esm/components/Inspector/MainScreen.js +2 -0
  28. package/dist/esm/components/Inspector/NetworkDetail.js +2 -1
  29. package/dist/esm/components/Inspector/NetworkFilterModal.d.ts +19 -0
  30. package/dist/esm/components/Inspector/NetworkFilterModal.js +607 -0
  31. package/dist/esm/components/Inspector/NetworkTab.js +91 -149
  32. package/dist/esm/components/Inspector/SettingsPanel.js +13 -1
  33. package/dist/esm/components/Inspector/TabBar.js +10 -1
  34. package/dist/esm/components/LogCard.js +5 -26
  35. package/dist/esm/components/NetworkIcons.d.ts +2 -0
  36. package/dist/esm/components/NetworkIcons.js +10 -0
  37. package/dist/esm/components/QRCodeView.d.ts +9 -0
  38. package/dist/esm/components/QRCodeView.js +42 -0
  39. package/dist/esm/constants/index.js +3 -0
  40. package/dist/esm/constants/version.d.ts +1 -1
  41. package/dist/esm/constants/version.js +1 -1
  42. package/dist/esm/helpers/qrGenerator.d.ts +2 -0
  43. package/dist/esm/helpers/qrGenerator.js +167 -0
  44. package/dist/esm/index.js +2 -0
  45. package/dist/esm/styles/index.d.ts +11 -0
  46. package/dist/esm/styles/index.js +20 -5
  47. package/dist/esm/types/enums.d.ts +5 -0
  48. package/dist/esm/types/enums.js +5 -0
  49. package/package.json +2 -2
  50. package/src/components/Inspector/DebuggingTab.tsx +755 -0
  51. package/src/components/Inspector/MainScreen.tsx +2 -0
  52. package/src/components/Inspector/NetworkDetail.tsx +2 -1
  53. package/src/components/Inspector/NetworkFilterModal.tsx +710 -0
  54. package/src/components/Inspector/NetworkTab.tsx +127 -204
  55. package/src/components/Inspector/SettingsPanel.tsx +20 -0
  56. package/src/components/Inspector/TabBar.tsx +11 -0
  57. package/src/components/LogCard.tsx +5 -30
  58. package/src/components/NetworkIcons.tsx +66 -0
  59. package/src/components/QRCodeView.tsx +71 -0
  60. package/src/constants/index.ts +3 -0
  61. package/src/constants/version.ts +1 -1
  62. package/src/helpers/qrGenerator.ts +184 -0
  63. package/src/index.tsx +2 -0
  64. package/src/styles/index.ts +20 -5
  65. package/src/types/enums.ts +5 -0
@@ -1,99 +1,53 @@
1
1
  import React, { useCallback, useMemo, useRef } from 'react';
2
- import { Animated, FlatList, Pressable, ScrollView, Text, TextInput, View, } from 'react-native';
2
+ import { FlatList, Pressable, ScrollView, Text, TextInput, View, } from 'react-native';
3
3
  import { animateNextLayout, useInspector } from './InspectorContext';
4
- import useAccordion from '../../customHooks/useAccordion';
5
4
  import TouchableScale from '../TouchableScale';
6
5
  import AnimatedEntrance from '../AnimatedEntrance';
7
6
  import DomainHeader from '../DomainHeader';
8
7
  import LogCard from '../LogCard';
9
8
  import EmptyState from '../EmptyState';
10
9
  import EndOfListFooter from '../EndOfListFooter';
10
+ import NetworkFilterModal from './NetworkFilterModal';
11
11
  import styles from '../../styles';
12
12
  import { AppColors } from '../../styles/AppColors';
13
13
  import { AppFonts } from '../../styles/AppFonts';
14
- import { STATUS_FILTERS, METHOD_COLORS } from '../../constants';
14
+ import { METHOD_COLORS } from '../../constants';
15
15
  import { useTranslation } from '../../i18n';
16
16
  import { SearchIcon, ClearIcon, TrashIcon, SortArrowIcon, FilterIcon, ChevronIcon, CircleCheckIcon, CircleXIcon, CircleAlertIcon, LayersIcon, HeaderPauseIcon, ClockIcon, GlobeIcon, RequestIcon, ResponseIcon, HeadersIcon, AtomIcon, BoltIcon, ShieldAlertIcon, } from '../NetworkIcons';
17
- const STATUS_META = {
18
- ALL: { color: AppColors.grayText, Icon: LayersIcon },
19
- '2xx': { color: AppColors.greenColor, Icon: CircleCheckIcon },
20
- '200': { color: AppColors.greenColor, Icon: CircleCheckIcon },
21
- '3xx': { color: AppColors.warningIconGold, Icon: CircleAlertIcon },
22
- '300': { color: AppColors.warningIconGold, Icon: CircleAlertIcon },
23
- '4xx': { color: AppColors.darkOrange, Icon: CircleAlertIcon },
24
- '400': { color: AppColors.darkOrange, Icon: CircleAlertIcon },
25
- '404': { color: AppColors.darkOrange, Icon: CircleAlertIcon },
26
- '5xx': { color: AppColors.errorColor, Icon: CircleXIcon },
27
- '500': { color: AppColors.errorColor, Icon: CircleXIcon },
28
- Failed: { color: AppColors.errorColor, Icon: CircleXIcon },
29
- };
30
- const getStatusMeta = (filter) => {
31
- if (STATUS_META[filter])
32
- return STATUS_META[filter];
33
- const num = parseInt(filter, 10);
34
- if (!isNaN(num)) {
35
- if (num >= 200 && num < 300)
36
- return { color: AppColors.greenColor, Icon: CircleCheckIcon };
37
- if (num >= 300 && num < 400)
38
- return { color: AppColors.warningIconGold, Icon: CircleAlertIcon };
39
- if (num >= 400 && num < 500)
40
- return { color: AppColors.darkOrange, Icon: CircleAlertIcon };
41
- if (num >= 500)
42
- return { color: AppColors.errorColor, Icon: CircleXIcon };
43
- }
44
- if (filter.startsWith('2'))
45
- return { color: AppColors.greenColor, Icon: CircleCheckIcon };
46
- if (filter.startsWith('3'))
47
- return { color: AppColors.warningIconGold, Icon: CircleAlertIcon };
48
- if (filter.startsWith('4'))
49
- return { color: AppColors.darkOrange, Icon: CircleAlertIcon };
50
- if (filter.startsWith('5'))
51
- return { color: AppColors.errorColor, Icon: CircleXIcon };
52
- return { color: AppColors.grayText, Icon: LayersIcon };
53
- };
54
- const FilterChip = React.memo(({ label, color, Icon, badge, active, onPress, }) => {
55
- const iconColor = active ? color : AppColors.grayTextWeak;
56
- return (<TouchableScale style={styles.statusFilterWrap} onPress={onPress} hitSlop={10}>
57
- <View style={[
58
- styles.statusFilterChip,
59
- {
60
- paddingHorizontal: 9,
61
- paddingVertical: 5,
62
- borderRadius: 7,
63
- borderWidth: 1,
64
- borderColor: active ? color : `${AppColors.grayBorderSecondary}`,
65
- backgroundColor: active ? `${color}14` : AppColors.grayBackground,
66
- },
67
- active && {
68
- shadowColor: color,
69
- shadowOffset: { width: 0, height: 1 },
70
- shadowOpacity: 0.2,
71
- shadowRadius: 2,
72
- elevation: 1.5,
73
- },
74
- ]}>
75
- {badge != null ? (<View style={[
76
- styles.methodBadgeMini,
77
- { backgroundColor: badge },
78
- ]}/>) : (Icon && (<Icon color={iconColor} size={13}/>))}
79
- <Text numberOfLines={1} style={[
80
- styles.statusFilterText,
81
- {
82
- color: active ? color : AppColors.grayText,
83
- fontFamily: active ? AppFonts.interBold : AppFonts.interMedium,
84
- },
85
- ]}>
86
- {label}
87
- </Text>
88
- </View>
89
- </TouchableScale>);
90
- });
91
17
  const NetworkTab = React.memo(() => {
92
18
  const { groupedData, search, setSearch, searchScope, setSearchScope, isRegexSearch, setIsRegexSearch, isCaseSensitive, setIsCaseSensitive, quickFilter, setQuickFilter, handleDelete, selectedLogs, sortOrder, setSortOrder, statusFilters, setStatusFilters, methodFilters, setMethodFilters, availableMethods, filteredLogs, logs, toggleSectionFilter, toggleSectionCollapse, minStart, totalRange, newLogIds, toggleSelect, setSelected, isNetworkPaused, setIsNetworkPaused, } = useInspector();
93
19
  const { t } = useTranslation();
94
- const filtersAccordion = useAccordion(false, 300, 260);
95
20
  const apisListRef = useRef(null);
21
+ const [isFilterModalOpen, setIsFilterModalOpen] = React.useState(false);
96
22
  const [isSearchFocused, setIsSearchFocused] = React.useState(false);
23
+ const modalFilterState = useMemo(() => ({
24
+ statusCodes: statusFilters.size > 0 ? new Set(statusFilters) : new Set(['all']),
25
+ methods: methodFilters.size > 0 ? new Set(methodFilters) : new Set(['all']),
26
+ latency: 'all',
27
+ protocol: 'all',
28
+ sortBy: sortOrder === 'newest' ? 'time_desc' : 'time_asc',
29
+ }), [statusFilters, methodFilters, sortOrder]);
30
+ const handleApplyNetworkFilters = useCallback((newFilters) => {
31
+ if (newFilters.statusCodes.has('all') ||
32
+ newFilters.statusCodes.size === 0) {
33
+ setStatusFilters(new Set());
34
+ }
35
+ else {
36
+ setStatusFilters(new Set(newFilters.statusCodes));
37
+ }
38
+ if (newFilters.methods.has('all') || newFilters.methods.size === 0) {
39
+ setMethodFilters(new Set());
40
+ }
41
+ else {
42
+ setMethodFilters(new Set([...newFilters.methods].map(m => m)));
43
+ }
44
+ if (newFilters.sortBy === 'time_asc') {
45
+ setSortOrder('oldest');
46
+ }
47
+ else {
48
+ setSortOrder('newest');
49
+ }
50
+ }, [setStatusFilters, setMethodFilters, setSortOrder]);
97
51
  const quickCounts = useMemo(() => {
98
52
  let errorCount = 0;
99
53
  let successCount = 0;
@@ -520,10 +474,12 @@ const NetworkTab = React.memo(() => {
520
474
 
521
475
  <TouchableScale style={[
522
476
  styles.toolbarBtn,
523
- filtersAccordion.isOpen &&
524
- styles.toolbarBtnActive,
525
- ]} onPress={filtersAccordion.toggleOpen} hitSlop={6}>
526
- <FilterIcon color={filtersAccordion.isOpen
477
+ (statusFilters.size > 0 || methodFilters.size > 0) && {
478
+ borderColor: AppColors.purple,
479
+ backgroundColor: `${AppColors.purple}15`,
480
+ },
481
+ ]} onPress={() => setIsFilterModalOpen(true)} hitSlop={6}>
482
+ <FilterIcon color={statusFilters.size > 0 || methodFilters.size > 0
527
483
  ? AppColors.purple
528
484
  : AppColors.grayTextStrong} size={16}/>
529
485
  {(statusFilters.size > 0 ||
@@ -685,6 +641,51 @@ const NetworkTab = React.memo(() => {
685
641
  </View>
686
642
  </TouchableScale>);
687
643
  })}
644
+
645
+ <TouchableScale onPress={() => setIsFilterModalOpen(true)}>
646
+ <View style={{
647
+ flexDirection: 'row',
648
+ alignItems: 'center',
649
+ paddingHorizontal: 10,
650
+ paddingVertical: 4.5,
651
+ borderRadius: 8,
652
+ backgroundColor: statusFilters.size > 0 || methodFilters.size > 0
653
+ ? `${AppColors.purple}20`
654
+ : AppColors.grayBackground,
655
+ borderWidth: 1,
656
+ borderColor: statusFilters.size > 0 || methodFilters.size > 0
657
+ ? AppColors.purple
658
+ : AppColors.grayBorderSecondary,
659
+ gap: 5,
660
+ }}>
661
+ <FilterIcon size={11} color={statusFilters.size > 0 || methodFilters.size > 0
662
+ ? AppColors.purple
663
+ : AppColors.grayText}/>
664
+ <Text style={{
665
+ fontFamily: AppFonts.interBold,
666
+ fontSize: 10.5,
667
+ color: statusFilters.size > 0 || methodFilters.size > 0
668
+ ? AppColors.purple
669
+ : AppColors.grayText,
670
+ }}>
671
+ More Filters
672
+ </Text>
673
+ {(statusFilters.size > 0 || methodFilters.size > 0) && (<View style={{
674
+ backgroundColor: AppColors.purple,
675
+ paddingHorizontal: 4.5,
676
+ paddingVertical: 1,
677
+ borderRadius: 6,
678
+ }}>
679
+ <Text style={{
680
+ fontFamily: AppFonts.interBold,
681
+ fontSize: 8.5,
682
+ color: AppColors.white,
683
+ }}>
684
+ {statusFilters.size + methodFilters.size}
685
+ </Text>
686
+ </View>)}
687
+ </View>
688
+ </TouchableScale>
688
689
  </ScrollView>
689
690
  </View>
690
691
 
@@ -833,86 +834,24 @@ const NetworkTab = React.memo(() => {
833
834
  </TouchableScale>
834
835
  </View>)}
835
836
 
836
- <Animated.View style={[
837
- filtersAccordion.bodyStyle,
838
- { overflow: 'hidden' },
839
- ]}>
840
- <View style={styles.filtersContainer}>
841
- <Text style={styles.filtersHeading}>
842
- STATUS
843
- </Text>
844
- <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.statusRowContent}>
845
- {STATUS_FILTERS.map(filter => {
846
- const isAll = filter === 'ALL';
847
- const active = isAll
848
- ? statusFilters.size === 0
849
- : statusFilters.has(filter);
850
- const meta = getStatusMeta(filter);
851
- return (<FilterChip key={filter} label={filter} color={meta.color} Icon={meta.Icon} active={active} onPress={() => {
852
- if (isAll) {
853
- setStatusFilters(new Set());
854
- }
855
- else {
856
- setStatusFilters(prev => {
857
- const next = new Set(prev);
858
- next.has(filter)
859
- ? next.delete(filter)
860
- : next.add(filter);
861
- return next;
862
- });
863
- }
864
- }}/>);
865
- })}
866
- </ScrollView>
867
-
868
- <Text style={[
869
- styles.filtersHeading,
870
- { marginTop: 16 },
871
- ]}>
872
- METHOD
873
- </Text>
874
- <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.statusRowContent}>
875
- {availableMethods.map(filter => {
876
- const isAll = filter === 'ALL';
877
- const active = isAll
878
- ? methodFilters.size === 0
879
- : methodFilters.has(filter);
880
- const methodColor = METHOD_COLORS[filter] ??
881
- METHOD_COLORS.ALL;
882
- return (<FilterChip key={filter} label={filter} color={methodColor} badge={methodColor} active={active} onPress={() => {
883
- if (isAll) {
884
- setMethodFilters(new Set());
885
- }
886
- else {
887
- setMethodFilters(prev => {
888
- const next = new Set(prev);
889
- next.has(filter)
890
- ? next.delete(filter)
891
- : next.add(filter);
892
- return next;
893
- });
894
- }
895
- }}/>);
896
- })}
897
- </ScrollView>
898
- </View>
899
- </Animated.View>
900
-
901
837
  {(search ||
902
838
  statusFilters.size > 0 ||
903
- methodFilters.size > 0) && (<Text style={styles.resultCount}>
839
+ methodFilters.size > 0 ||
840
+ quickFilter !== 'all') && (<Text style={styles.resultCount}>
904
841
  {filteredLogs.length === logs.length
905
842
  ? `${logs.length} requests`
906
843
  : `${filteredLogs.length} of ${logs.length} filtered requests`}
907
844
  </Text>)}
908
845
  </View>} ListEmptyComponent={<EmptyState isSearch={search.length > 0 ||
909
846
  statusFilters.size > 0 ||
910
- methodFilters.size > 0} searchQuery={search} customTitle={search.length > 0
847
+ methodFilters.size > 0 ||
848
+ quickFilter !== 'all'} searchQuery={search} customTitle={search.length > 0
911
849
  ? 'No matching API requests'
912
850
  : 'No network activity'} onClearSearch={() => {
913
851
  setSearch('');
914
852
  setStatusFilters(new Set());
915
853
  setMethodFilters(new Set());
854
+ setQuickFilter('all');
916
855
  setSearchScope('all');
917
856
  }}/>} ListFooterComponent={groupedData.length > 0 ? (<EndOfListFooter count={filteredLogs.length} label="requests"/>) : null} contentContainerStyle={[
918
857
  styles.listContent,
@@ -940,6 +879,9 @@ const NetworkTab = React.memo(() => {
940
879
  <ChevronIcon color={AppColors.white} size={18}/>
941
880
  </View>
942
881
  </TouchableScale>
882
+
883
+
884
+ <NetworkFilterModal visible={isFilterModalOpen} onClose={() => setIsFilterModalOpen(false)} filters={modalFilterState} onApply={handleApplyNetworkFilters} searchQuery={search}/>
943
885
  </View>);
944
886
  });
945
887
  export default NetworkTab;
@@ -17,7 +17,7 @@ import { clearPerformanceEvents } from '../../customHooks/performanceTracker';
17
17
  import { isReduxConnected } from '../../customHooks/reduxLogger';
18
18
  import { isAnalyticsConnected } from '../../customHooks/analyticsLogger';
19
19
  import { useTranslation } from '../../i18n';
20
- import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, ShieldAlertIcon, ForwardChevronIcon, ChevronDownIcon, NpmIcon, BoltIcon, BrainIcon, SmartphoneIcon, DatabaseIcon, } from '../NetworkIcons';
20
+ import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, ShieldAlertIcon, ForwardChevronIcon, ChevronDownIcon, NpmIcon, BoltIcon, BrainIcon, SmartphoneIcon, DatabaseIcon, QrCodeIcon, } from '../NetworkIcons';
21
21
  import { LIB_VERSION } from '../../constants';
22
22
  import { copyToClipboard } from '../../helpers';
23
23
  import { showToast } from '../../helpers/toast';
@@ -97,6 +97,13 @@ const SettingsPanel = () => {
97
97
  icon: 'storage',
98
98
  desc: 'AsyncStorage & MMKV key-value store viewer with full CRUD support',
99
99
  },
100
+ {
101
+ key: 'debugging',
102
+ label: 'Multi-Device Debugging',
103
+ category: 'diagnostic',
104
+ icon: 'debugging',
105
+ desc: 'QR Code bridge for direct Debug APK download & Metro live-reload sync',
106
+ },
100
107
  ];
101
108
  const [stagedTabVisibility, setStagedTabVisibility] = useState(() => ({
102
109
  apis: true,
@@ -108,6 +115,7 @@ const SettingsPanel = () => {
108
115
  crash: Boolean(tabVisibility?.crash),
109
116
  device: Boolean(tabVisibility?.device),
110
117
  storage: Boolean(tabVisibility?.storage),
118
+ debugging: Boolean(tabVisibility?.debugging ?? true),
111
119
  }));
112
120
  useEffect(() => {
113
121
  setStagedTabVisibility({
@@ -120,6 +128,7 @@ const SettingsPanel = () => {
120
128
  crash: Boolean(tabVisibility?.crash),
121
129
  device: Boolean(tabVisibility?.device),
122
130
  storage: Boolean(tabVisibility?.storage),
131
+ debugging: Boolean(tabVisibility?.debugging ?? true),
123
132
  });
124
133
  }, [tabVisibility]);
125
134
  const hasUnsavedChanges = useMemo(() => {
@@ -507,6 +516,9 @@ const SettingsPanel = () => {
507
516
  {moduleItem.icon === 'storage' && (<DatabaseIcon color={isChecked
508
517
  ? AppColors.purple
509
518
  : AppColors.grayTextWeak} size={16}/>)}
519
+ {moduleItem.icon === 'debugging' && (<QrCodeIcon color={isChecked
520
+ ? AppColors.purple
521
+ : AppColors.grayTextWeak} size={16}/>)}
510
522
  </View>
511
523
 
512
524
 
@@ -4,7 +4,7 @@ import { useInspector } from './InspectorContext';
4
4
  import styles from '../../styles';
5
5
  import { AppColors } from '../../styles/AppColors';
6
6
  import TouchableScale from '../TouchableScale';
7
- import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, SmartphoneIcon, DatabaseIcon, } from '../NetworkIcons';
7
+ import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, SmartphoneIcon, DatabaseIcon, QrCodeIcon, } from '../NetworkIcons';
8
8
  import { isReduxConnected } from '../../customHooks/reduxLogger';
9
9
  import { isAnalyticsConnected } from '../../customHooks/analyticsLogger';
10
10
  const TabBar = React.memo(() => {
@@ -68,8 +68,16 @@ const TabBar = React.memo(() => {
68
68
  count: 0,
69
69
  icon: 'storage',
70
70
  },
71
+ {
72
+ key: 'debugging',
73
+ label: 'Debugging',
74
+ count: 0,
75
+ icon: 'debugging',
76
+ },
71
77
  ]
72
78
  .filter(tab => {
79
+ if (tab.key === 'debugging')
80
+ return true;
73
81
  if (!tabVisibility?.[tab.key])
74
82
  return false;
75
83
  if (tab.key === 'redux' && !isReduxAvail)
@@ -112,6 +120,7 @@ const TabBar = React.memo(() => {
112
120
  {tab.icon === 'crash' && (<CrashIcon color={iconColor} size={14}/>)}
113
121
  {tab.icon === 'device' && (<SmartphoneIcon color={iconColor} size={14}/>)}
114
122
  {tab.icon === 'storage' && (<DatabaseIcon color={iconColor} size={14}/>)}
123
+ {tab.icon === 'debugging' && (<QrCodeIcon color={iconColor} size={14}/>)}
115
124
  <Text numberOfLines={1} ellipsizeMode="tail" style={[
116
125
  styles.contentTabButtonText,
117
126
  isActive &&
@@ -198,29 +198,6 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
198
198
  GQL
199
199
  </Text>
200
200
  </View>)}
201
-
202
-
203
- {item.duration != null && !isFailed && (<View style={[
204
- styles.chip,
205
- {
206
- backgroundColor: `${durationColor}12`,
207
- borderColor: `${durationColor}2E`,
208
- paddingHorizontal: 4.5,
209
- paddingVertical: 1,
210
- borderRadius: 4,
211
- },
212
- ]}>
213
- <Text style={[
214
- styles.chipText,
215
- {
216
- fontFamily: AppFonts.interBold,
217
- fontSize: 8.5,
218
- color: durationColor,
219
- },
220
- ]}>
221
- {item.duration}ms
222
- </Text>
223
- </View>)}
224
201
  </View>
225
202
 
226
203
  <View style={[
@@ -239,6 +216,7 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
239
216
  : isLoading
240
217
  ? `${AppColors.darkOrange}30`
241
218
  : `${statusColor}30`,
219
+ flexShrink: 0,
242
220
  },
243
221
  ]}>
244
222
  {renderStatusIcon()}
@@ -272,6 +250,7 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
272
250
  alignItems: 'center',
273
251
  justifyContent: 'center',
274
252
  marginRight: 4,
253
+ flexShrink: 0,
275
254
  }}>
276
255
  <GlobeIcon color={AppColors.skyBlue} size={11}/>
277
256
  </View>
@@ -310,8 +289,8 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
310
289
 
311
290
 
312
291
  <View style={styles.cardFooterRow}>
313
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexShrink: 1, minWidth: 0 }}>
314
- <View style={styles.cardDateRow}>
292
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flex: 1, minWidth: 0, marginRight: 8 }}>
293
+ <View style={[styles.cardDateRow, { flexShrink: 0 }]}>
315
294
  <CalendarIcon color={AppColors.grayTextWeak} size={10}/>
316
295
  <Text style={styles.cardDateText}>{triggeredAt}</Text>
317
296
  </View>
@@ -328,7 +307,7 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
328
307
  paddingVertical: 1,
329
308
  borderRadius: 4,
330
309
  flexShrink: 1,
331
- maxWidth: 160,
310
+ minWidth: 0,
332
311
  },
333
312
  ]}>
334
313
  <PinIcon color={AppColors.skyBlue} size={8.5}/>
@@ -133,3 +133,5 @@ export declare const ShieldCheckIcon: ({ color, size, }: IconProps) => React.JSX
133
133
  export declare const DatabaseIcon: ({ color, size, }: IconProps) => React.JSX.Element;
134
134
  export declare const PencilIcon: ({ color, size, }: IconProps) => React.JSX.Element;
135
135
  export declare const PlusIcon: ({ color, size, }: IconProps) => React.JSX.Element;
136
+ export declare const LockIcon: ({ color, size, }: IconProps) => React.JSX.Element;
137
+ export declare const QrCodeIcon: ({ color, size, }: IconProps) => React.JSX.Element;
@@ -730,3 +730,13 @@ export const PencilIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => (<
730
730
  export const PlusIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
731
731
  <Path d="M12 5v14M5 12h14" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
732
732
  </Svg>);
733
+ export const LockIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
734
+ <Rect x="3" y="11" width="18" height="11" rx="2" ry="2" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
735
+ <Path d="M7 11V7a5 5 0 0 1 10 0v4" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
736
+ </Svg>);
737
+ export const QrCodeIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
738
+ <Rect x="3" y="3" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2"/>
739
+ <Rect x="14" y="3" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2"/>
740
+ <Rect x="3" y="14" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2"/>
741
+ <Path d="M14 14h3v3h-3zM18 18h3v3h-3zM14 19h3v2h-3zM19 14h2v3h-2z" fill={color}/>
742
+ </Svg>);
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface QRCodeViewProps {
3
+ value: string;
4
+ size?: number;
5
+ color?: string;
6
+ backgroundColor?: string;
7
+ }
8
+ export declare const QRCodeView: React.FC<QRCodeViewProps>;
9
+ export default QRCodeView;
@@ -0,0 +1,42 @@
1
+ import React, { useMemo } from 'react';
2
+ import { View, StyleSheet } from 'react-native';
3
+ import Svg, { Rect, G } from 'react-native-svg';
4
+ import { generateQRMatrix } from '../helpers/qrGenerator';
5
+ import { AppColors } from '../styles/AppColors';
6
+ export const QRCodeView = ({ value, size = 180, color = AppColors.primaryBlack, backgroundColor = AppColors.white, }) => {
7
+ const matrix = useMemo(() => generateQRMatrix(value), [value]);
8
+ const numCells = matrix.length;
9
+ const cellSize = size / numCells;
10
+ return (<View style={[
11
+ styles.container,
12
+ {
13
+ width: size + 16,
14
+ height: size + 16,
15
+ backgroundColor,
16
+ },
17
+ ]}>
18
+ <Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
19
+ <G>
20
+ {matrix.map((row, r) => row.map((cell, c) => {
21
+ if (!cell)
22
+ return null;
23
+ return (<Rect key={`${r}-${c}`} x={c * cellSize} y={r * cellSize} width={cellSize + 0.2} height={cellSize + 0.2} fill={color}/>);
24
+ }))}
25
+ </G>
26
+ </Svg>
27
+ </View>);
28
+ };
29
+ const styles = StyleSheet.create({
30
+ container: {
31
+ padding: 8,
32
+ borderRadius: 14,
33
+ alignItems: 'center',
34
+ justifyContent: 'center',
35
+ shadowColor: AppColors.black,
36
+ shadowOffset: { width: 0, height: 2 },
37
+ shadowOpacity: 0.1,
38
+ shadowRadius: 6,
39
+ elevation: 3,
40
+ },
41
+ });
42
+ export default QRCodeView;
@@ -18,6 +18,9 @@ export const METHOD_COLORS = {
18
18
  PUT: '#D97706',
19
19
  PATCH: '#7C3AED',
20
20
  DELETE: '#DC2626',
21
+ QUERY: '#0284C7',
22
+ OPTIONS: '#475569',
23
+ HEAD: '#0891B2',
21
24
  };
22
25
  export const DOMAIN_COLORS = AppColors.domainColors;
23
26
  export const DURATION_FAST_MS = 200;
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "2.3.9";
1
+ export declare const LIB_VERSION = "2.3.11";
@@ -1 +1 @@
1
- export const LIB_VERSION = '2.3.9';
1
+ export const LIB_VERSION = '2.3.11';
@@ -0,0 +1,2 @@
1
+ export type QRECC = 'L' | 'M' | 'Q' | 'H';
2
+ export declare function generateQRMatrix(text: string, ecc?: QRECC): boolean[][];