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.
Files changed (77) hide show
  1. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +29 -80
  2. package/dist/commonjs/components/AnalyticsDetail.js +668 -108
  3. package/dist/commonjs/components/AppHeaderLogo.js +15 -15
  4. package/dist/commonjs/components/ConsoleLogCard.js +112 -66
  5. package/dist/commonjs/components/CopyButton.js +15 -1
  6. package/dist/commonjs/components/DomainHeader.js +64 -32
  7. package/dist/commonjs/components/HighlightText.js +7 -1
  8. package/dist/commonjs/components/Inspector/AnalyticsTab.js +332 -221
  9. package/dist/commonjs/components/Inspector/ConsoleTab.js +162 -56
  10. package/dist/commonjs/components/Inspector/InspectorHeader.js +70 -119
  11. package/dist/commonjs/components/Inspector/LogDetail.js +53 -17
  12. package/dist/commonjs/components/Inspector/MainScreen.js +4 -0
  13. package/dist/commonjs/components/Inspector/NetworkDetail.js +24 -24
  14. package/dist/commonjs/components/Inspector/NetworkTab.js +4 -1
  15. package/dist/commonjs/components/Inspector/ReduxDetail.js +237 -42
  16. package/dist/commonjs/components/Inspector/ReduxTab.js +456 -35
  17. package/dist/commonjs/components/JsonViewer.js +26 -4
  18. package/dist/commonjs/components/LogCard.js +103 -11
  19. package/dist/commonjs/components/NetworkIcons.js +19 -10
  20. package/dist/commonjs/components/Toast.d.ts +3 -0
  21. package/dist/commonjs/components/Toast.js +152 -0
  22. package/dist/commonjs/components/TouchableScale.d.ts +1 -0
  23. package/dist/commonjs/components/TouchableScale.js +3 -3
  24. package/dist/commonjs/components/TreeNode.js +12 -2
  25. package/dist/commonjs/constants/index.js +6 -6
  26. package/dist/commonjs/constants/version.d.ts +1 -1
  27. package/dist/commonjs/constants/version.js +1 -1
  28. package/dist/commonjs/customHooks/reduxLogger.js +128 -5
  29. package/dist/commonjs/helpers/index.d.ts +4 -0
  30. package/dist/commonjs/helpers/index.js +107 -92
  31. package/dist/commonjs/helpers/toast.d.ts +4 -0
  32. package/dist/commonjs/helpers/toast.js +20 -0
  33. package/dist/commonjs/i18n/locales/en.json +49 -3
  34. package/dist/commonjs/styles/AppColors.d.ts +6 -0
  35. package/dist/commonjs/styles/AppColors.js +6 -0
  36. package/dist/commonjs/styles/index.d.ts +82 -15
  37. package/dist/commonjs/styles/index.js +92 -26
  38. package/dist/commonjs/types/interfaces.d.ts +7 -0
  39. package/dist/esm/components/AnalyticsDetail.js +670 -110
  40. package/dist/esm/components/AppHeaderLogo.js +15 -15
  41. package/dist/esm/components/ConsoleLogCard.js +114 -68
  42. package/dist/esm/components/CopyButton.js +15 -1
  43. package/dist/esm/components/DomainHeader.js +64 -32
  44. package/dist/esm/components/HighlightText.js +7 -1
  45. package/dist/esm/components/Inspector/AnalyticsTab.js +334 -223
  46. package/dist/esm/components/Inspector/ConsoleTab.js +163 -57
  47. package/dist/esm/components/Inspector/InspectorHeader.js +71 -120
  48. package/dist/esm/components/Inspector/LogDetail.js +55 -19
  49. package/dist/esm/components/Inspector/MainScreen.js +4 -0
  50. package/dist/esm/components/Inspector/NetworkDetail.js +25 -25
  51. package/dist/esm/components/Inspector/NetworkTab.js +4 -1
  52. package/dist/esm/components/Inspector/ReduxDetail.js +239 -44
  53. package/dist/esm/components/Inspector/ReduxTab.js +458 -37
  54. package/dist/esm/components/JsonViewer.js +26 -4
  55. package/dist/esm/components/LogCard.js +105 -13
  56. package/dist/esm/components/NetworkIcons.js +19 -10
  57. package/dist/esm/components/Toast.d.ts +3 -0
  58. package/dist/esm/components/Toast.js +117 -0
  59. package/dist/esm/components/TouchableScale.d.ts +1 -0
  60. package/dist/esm/components/TouchableScale.js +3 -3
  61. package/dist/esm/components/TreeNode.js +12 -2
  62. package/dist/esm/constants/index.js +6 -6
  63. package/dist/esm/constants/version.d.ts +1 -1
  64. package/dist/esm/constants/version.js +1 -1
  65. package/dist/esm/customHooks/reduxLogger.js +128 -5
  66. package/dist/esm/helpers/index.d.ts +4 -0
  67. package/dist/esm/helpers/index.js +102 -92
  68. package/dist/esm/helpers/toast.d.ts +4 -0
  69. package/dist/esm/helpers/toast.js +15 -0
  70. package/dist/esm/i18n/locales/en.json +49 -3
  71. package/dist/esm/styles/AppColors.d.ts +6 -0
  72. package/dist/esm/styles/AppColors.js +6 -0
  73. package/dist/esm/styles/index.d.ts +82 -15
  74. package/dist/esm/styles/index.js +92 -26
  75. package/dist/esm/types/interfaces.d.ts +7 -0
  76. package/ios/NetworkInspectorModule.m +0 -10
  77. package/package.json +13 -10
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  const react_1 = __importStar(require("react"));
40
40
  const react_native_1 = require("react-native");
41
+ const i18n_1 = require("../../i18n");
41
42
  const InspectorContext_1 = require("./InspectorContext");
42
43
  const TouchableScale_1 = __importDefault(require("../TouchableScale"));
43
44
  const AnimatedEntrance_1 = __importDefault(require("../AnimatedEntrance"));
@@ -48,46 +49,224 @@ const helpers_1 = require("../../helpers");
48
49
  const styles_1 = __importDefault(require("../../styles"));
49
50
  const AppColors_1 = require("../../styles/AppColors");
50
51
  const AppFonts_1 = require("../../styles/AppFonts");
52
+ const reduxLogger_1 = require("../../customHooks/reduxLogger");
51
53
  const NetworkIcons_1 = require("../NetworkIcons");
54
+ const getOriginBadge = (originType) => {
55
+ switch (originType) {
56
+ case 'saga':
57
+ return {
58
+ label: 'SAGA',
59
+ icon: '⚡',
60
+ bg: AppColors_1.AppColors.purple100,
61
+ text: AppColors_1.AppColors.brandPurple,
62
+ border: AppColors_1.AppColors.purple200,
63
+ };
64
+ case 'thunk':
65
+ return {
66
+ label: 'THUNK',
67
+ icon: '⚛️',
68
+ bg: AppColors_1.AppColors.amber100,
69
+ text: AppColors_1.AppColors.amber800Warm,
70
+ border: AppColors_1.AppColors.amber200,
71
+ };
72
+ case 'ui':
73
+ return {
74
+ label: 'UI',
75
+ icon: '📱',
76
+ bg: AppColors_1.AppColors.sky100,
77
+ text: AppColors_1.AppColors.sky600,
78
+ border: AppColors_1.AppColors.sky400,
79
+ };
80
+ case 'listener':
81
+ return {
82
+ label: 'LISTENER',
83
+ icon: '👂',
84
+ bg: AppColors_1.AppColors.teal100,
85
+ text: AppColors_1.AppColors.teal700,
86
+ border: AppColors_1.AppColors.teal400,
87
+ };
88
+ default:
89
+ return {
90
+ label: 'DIRECT',
91
+ icon: '⚡',
92
+ bg: AppColors_1.AppColors.slate100,
93
+ text: AppColors_1.AppColors.slate700,
94
+ border: AppColors_1.AppColors.slate200,
95
+ };
96
+ }
97
+ };
98
+ const getKeyChipStyle = (key) => {
99
+ const k = key.toLowerCase();
100
+ if (k.includes('load') || k.includes('pend') || k.includes('status')) {
101
+ return {
102
+ bg: AppColors_1.AppColors.amber100,
103
+ border: AppColors_1.AppColors.amber200,
104
+ text: AppColors_1.AppColors.amber800Warm,
105
+ dot: AppColors_1.AppColors.darkOrange,
106
+ };
107
+ }
108
+ if (k.includes('err') || k.includes('fail') || k.includes('reject')) {
109
+ return {
110
+ bg: AppColors_1.AppColors.red100,
111
+ border: AppColors_1.AppColors.errorBorder,
112
+ text: AppColors_1.AppColors.red600,
113
+ dot: AppColors_1.AppColors.errorColor,
114
+ };
115
+ }
116
+ if (k.includes('user') || k.includes('auth') || k.includes('token') || k.includes('profile')) {
117
+ return {
118
+ bg: AppColors_1.AppColors.indigo50,
119
+ border: AppColors_1.AppColors.indigo400,
120
+ text: AppColors_1.AppColors.indigo600Alt,
121
+ dot: AppColors_1.AppColors.indigo500,
122
+ };
123
+ }
124
+ if (k.includes('item') || k.includes('data') || k.includes('list') || k.includes('entit') || k.includes('count')) {
125
+ return {
126
+ bg: AppColors_1.AppColors.emeraldBg,
127
+ border: AppColors_1.AppColors.emeraldBorder,
128
+ text: AppColors_1.AppColors.emerald700,
129
+ dot: AppColors_1.AppColors.emerald500,
130
+ };
131
+ }
132
+ return {
133
+ bg: AppColors_1.AppColors.slate100,
134
+ border: AppColors_1.AppColors.slate200,
135
+ text: AppColors_1.AppColors.slate700,
136
+ dot: AppColors_1.AppColors.slate400,
137
+ };
138
+ };
52
139
  const ReduxTab = react_1.default.memo(() => {
140
+ const { t } = (0, i18n_1.useTranslation)();
53
141
  const { reduxState, reduxLastActionMap, reduxSearch, setReduxSearch, setSelectedReduxSlice, } = (0, InspectorContext_1.useInspector)();
54
142
  // Sort mode: 'latest' (newest updated first) vs 'alpha' (A-Z)
55
143
  const [sortMode, setSortMode] = (0, react_1.useState)('latest');
144
+ // Pause / Live Auto-Refresh State
145
+ const [isReduxPaused, setIsReduxPaused] = (0, react_1.useState)(!(0, reduxLogger_1.getReduxAutoRefresh)());
146
+ const handleTogglePause = (0, react_1.useCallback)(() => {
147
+ setIsReduxPaused(prev => {
148
+ const next = !prev;
149
+ (0, reduxLogger_1.setReduxAutoRefresh)(!next);
150
+ return next;
151
+ });
152
+ }, []);
56
153
  // Total state size calculation
57
154
  const totalStateSize = (0, react_1.useMemo)(() => {
58
155
  return (0, helpers_1.getSize)(reduxState);
59
156
  }, [reduxState]);
60
- // Compute slice items with exact timestamps
157
+ // Fetch full action history for timeline counts
158
+ const allActions = (0, react_1.useMemo)(() => {
159
+ return (0, reduxLogger_1.getActionHistory)();
160
+ }, [reduxLastActionMap]);
161
+ // Compute slice items with exact timestamps & rich details
61
162
  const sliceItems = (0, react_1.useMemo)(() => {
62
163
  if (!reduxState || typeof reduxState !== 'object')
63
164
  return [];
64
165
  const keys = Object.keys(reduxState);
65
166
  return keys.map(key => {
66
167
  const sliceVal = reduxState[key];
67
- const keysCount = sliceVal && typeof sliceVal === 'object'
68
- ? Object.keys(sliceVal).length
69
- : typeof sliceVal !== 'undefined'
70
- ? 1
71
- : 0;
72
- const lastAction = reduxLastActionMap[key];
73
- const updatedAt = lastAction?.updatedAt || 0;
168
+ const isArray = Array.isArray(sliceVal);
169
+ const isObject = sliceVal && typeof sliceVal === 'object';
170
+ let typeLabel = 'Primitive';
171
+ let keysCount = 0;
172
+ let topKeys = [];
173
+ let totalKeysCount = 0;
174
+ if (isArray) {
175
+ keysCount = sliceVal.length;
176
+ typeLabel = `Array [${keysCount}]`;
177
+ }
178
+ else if (isObject) {
179
+ const objKeys = Object.keys(sliceVal);
180
+ totalKeysCount = objKeys.length;
181
+ keysCount = totalKeysCount;
182
+ topKeys = objKeys.slice(0, 4);
183
+ typeLabel = `Object {${keysCount}}`;
184
+ }
185
+ else if (typeof sliceVal !== 'undefined') {
186
+ keysCount = 1;
187
+ typeLabel = typeof sliceVal;
188
+ }
189
+ // Determine state status
190
+ let status = 'live';
191
+ let statusMessage;
192
+ if (isObject) {
193
+ if (sliceVal.loading === true ||
194
+ sliceVal.isLoading === true ||
195
+ sliceVal.status === 'loading' ||
196
+ sliceVal.status === 'pending') {
197
+ status = 'loading';
198
+ statusMessage = 'Loading';
199
+ }
200
+ else if (sliceVal.error ||
201
+ sliceVal.hasError ||
202
+ sliceVal.status === 'error' ||
203
+ sliceVal.status === 'failed') {
204
+ status = 'error';
205
+ statusMessage = typeof sliceVal.error === 'string' ? sliceVal.error : 'Error';
206
+ }
207
+ else if (keysCount === 0) {
208
+ status = 'empty';
209
+ statusMessage = 'Empty';
210
+ }
211
+ }
212
+ const lastActionRaw = reduxLastActionMap[key];
213
+ const updatedAt = lastActionRaw?.updatedAt || 0;
214
+ // Count actions affecting this slice in timeline
215
+ const timelineCount = allActions.filter(action => {
216
+ if (!action.affectedSlices || action.affectedSlices.length === 0)
217
+ return true;
218
+ return action.affectedSlices.includes(key);
219
+ }).length;
220
+ let lastAction = undefined;
221
+ if (lastActionRaw) {
222
+ let payloadPreview;
223
+ if (lastActionRaw.payload !== undefined && lastActionRaw.payload !== null) {
224
+ try {
225
+ if (typeof lastActionRaw.payload === 'object') {
226
+ const pKeys = Object.keys(lastActionRaw.payload);
227
+ payloadPreview = `{ ${pKeys.slice(0, 3).join(', ')}${pKeys.length > 3 ? '...' : ''} }`;
228
+ }
229
+ else {
230
+ payloadPreview = String(lastActionRaw.payload);
231
+ }
232
+ }
233
+ catch { }
234
+ }
235
+ lastAction = {
236
+ type: lastActionRaw.type,
237
+ timestamp: lastActionRaw.timestamp,
238
+ updatedAt: lastActionRaw.updatedAt,
239
+ payloadPreview,
240
+ originType: lastActionRaw.originType,
241
+ callerFile: lastActionRaw.callerFile,
242
+ callerLine: lastActionRaw.callerLine,
243
+ callerCol: lastActionRaw.callerCol,
244
+ };
245
+ }
74
246
  return {
75
247
  id: `slice-${key}`,
76
248
  name: key,
77
249
  keysCount,
78
250
  sizeStr: (0, helpers_1.getSize)(sliceVal),
251
+ typeLabel,
252
+ topKeys,
253
+ totalKeysCount,
254
+ status,
255
+ statusMessage,
256
+ timelineCount,
79
257
  lastAction,
80
258
  updatedAt,
81
259
  };
82
260
  });
83
- }, [reduxState, reduxLastActionMap]);
261
+ }, [reduxState, reduxLastActionMap, allActions]);
84
262
  // Filter & Sort slices: by default, the most recently updated item is at the FIRST position
85
263
  const filteredSlices = (0, react_1.useMemo)(() => {
86
264
  let list = sliceItems;
87
265
  if (reduxSearch.trim().length > 0) {
88
266
  const q = reduxSearch.toLowerCase();
89
267
  list = list.filter(item => item.name.toLowerCase().includes(q) ||
90
- (item.lastAction && item.lastAction.type.toLowerCase().includes(q)));
268
+ (item.lastAction && item.lastAction.type.toLowerCase().includes(q)) ||
269
+ item.topKeys.some(k => k.toLowerCase().includes(q)));
91
270
  }
92
271
  return [...list].sort((a, b) => {
93
272
  if (sortMode === 'latest') {
@@ -120,7 +299,7 @@ const ReduxTab = react_1.default.memo(() => {
120
299
  reduxTabStyles.card,
121
300
  isRecentlyUpdated && reduxTabStyles.cardRecentlyUpdated,
122
301
  ]}>
123
- {/* Top row: Badge + Slice Name + Timestamp + Chevron */}
302
+ {/* Top row: Badge + Slice Name + Status + Timestamp + Chevron */}
124
303
  <react_native_1.View style={reduxTabStyles.cardHeader}>
125
304
  <react_native_1.View style={reduxTabStyles.sliceBadge}>
126
305
  <react_native_1.Text style={reduxTabStyles.sliceBadgeText}>SLICE</react_native_1.Text>
@@ -128,6 +307,18 @@ const ReduxTab = react_1.default.memo(() => {
128
307
 
129
308
  <HighlightText_1.default text={item.name} search={reduxSearch} style={reduxTabStyles.sliceName} highlightStyle={reduxTabStyles.highlight}/>
130
309
 
310
+ {/* Status Badge */}
311
+ {item.status === 'loading' ? (<react_native_1.View style={reduxTabStyles.loadingPill}>
312
+ <react_native_1.Text style={reduxTabStyles.loadingPillText}>⏳ Loading</react_native_1.Text>
313
+ </react_native_1.View>) : item.status === 'error' ? (<react_native_1.View style={reduxTabStyles.errorPill}>
314
+ <react_native_1.Text style={reduxTabStyles.errorPillText}>⚠️ Error</react_native_1.Text>
315
+ </react_native_1.View>) : item.status === 'empty' ? (<react_native_1.View style={reduxTabStyles.emptyPill}>
316
+ <react_native_1.Text style={reduxTabStyles.emptyPillText}>Empty</react_native_1.Text>
317
+ </react_native_1.View>) : (<react_native_1.View style={reduxTabStyles.livePill}>
318
+ <react_native_1.View style={reduxTabStyles.liveDot}/>
319
+ <react_native_1.Text style={reduxTabStyles.livePillText}>Live</react_native_1.Text>
320
+ </react_native_1.View>)}
321
+
131
322
  {item.lastAction?.timestamp && (<react_native_1.View style={reduxTabStyles.timePill}>
132
323
  <NetworkIcons_1.ClockIcon color={AppColors_1.AppColors.purple} size={10}/>
133
324
  <react_native_1.Text style={reduxTabStyles.timeText}>
@@ -141,27 +332,116 @@ const ReduxTab = react_1.default.memo(() => {
141
332
  {/* Middle row: Stats pills */}
142
333
  <react_native_1.View style={reduxTabStyles.statsRow}>
143
334
  <react_native_1.View style={reduxTabStyles.pill}>
144
- <react_native_1.Text style={reduxTabStyles.pillLabel}>Keys:</react_native_1.Text>
145
- <react_native_1.Text style={reduxTabStyles.pillValue}>{item.keysCount}</react_native_1.Text>
335
+ <NetworkIcons_1.LayersIcon color={AppColors_1.AppColors.grayTextWeak} size={11}/>
336
+ <react_native_1.Text style={reduxTabStyles.pillValue}>{item.typeLabel}</react_native_1.Text>
146
337
  </react_native_1.View>
147
338
  <react_native_1.View style={reduxTabStyles.pill}>
148
339
  <react_native_1.Text style={reduxTabStyles.pillLabel}>Size:</react_native_1.Text>
149
340
  <react_native_1.Text style={reduxTabStyles.pillValue}>{item.sizeStr}</react_native_1.Text>
150
341
  </react_native_1.View>
151
- <react_native_1.View style={reduxTabStyles.livePill}>
152
- <react_native_1.View style={reduxTabStyles.liveDot}/>
153
- <react_native_1.Text style={reduxTabStyles.livePillText}>Live</react_native_1.Text>
154
- </react_native_1.View>
342
+ {item.timelineCount > 0 && (<react_native_1.View style={reduxTabStyles.pill}>
343
+ <react_native_1.Text style={reduxTabStyles.pillLabel}>Actions:</react_native_1.Text>
344
+ <react_native_1.Text style={reduxTabStyles.pillValue}>{item.timelineCount}</react_native_1.Text>
345
+ </react_native_1.View>)}
155
346
  </react_native_1.View>
156
347
 
157
- {/* Bottom row: Last Dispatched Action */}
348
+ {/* Keys Preview Chips (if object has keys) */}
349
+ {item.topKeys.length > 0 && (<react_native_1.View style={reduxTabStyles.keysContainer}>
350
+ <react_native_1.Text style={reduxTabStyles.keysHeading}>Keys:</react_native_1.Text>
351
+ <react_native_1.View style={reduxTabStyles.keysWrap}>
352
+ {item.topKeys.map((k, kIdx) => {
353
+ const chipStyle = getKeyChipStyle(k);
354
+ return (<react_native_1.View key={kIdx} style={[
355
+ reduxTabStyles.keyChip,
356
+ {
357
+ backgroundColor: chipStyle.bg,
358
+ borderColor: chipStyle.border,
359
+ },
360
+ ]}>
361
+ <react_native_1.View style={{
362
+ width: 5,
363
+ height: 5,
364
+ borderRadius: 2.5,
365
+ backgroundColor: chipStyle.dot,
366
+ }}/>
367
+ <react_native_1.Text style={[
368
+ reduxTabStyles.keyChipText,
369
+ { color: chipStyle.text },
370
+ ]} numberOfLines={1}>
371
+ {k}
372
+ </react_native_1.Text>
373
+ </react_native_1.View>);
374
+ })}
375
+ {item.totalKeysCount > item.topKeys.length && (<react_native_1.View style={reduxTabStyles.keyMoreChip}>
376
+ <react_native_1.Text style={reduxTabStyles.keyMoreChipText}>
377
+ +{item.totalKeysCount - item.topKeys.length}
378
+ </react_native_1.Text>
379
+ </react_native_1.View>)}
380
+ </react_native_1.View>
381
+ </react_native_1.View>)}
382
+
383
+ {/* Bottom row: Last Dispatched Action with Origin & Trigger Line */}
158
384
  {item.lastAction && (<react_native_1.View style={reduxTabStyles.lastActionRow}>
159
- <react_native_1.Text style={reduxTabStyles.lastActionLabel}>Last Action:</react_native_1.Text>
160
- <HighlightText_1.default text={item.lastAction.type} search={reduxSearch} style={reduxTabStyles.lastActionValue} highlightStyle={reduxTabStyles.highlight} numberOfLines={1}/>
385
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 5, flex: 1, minWidth: 0, flexWrap: 'wrap' }}>
386
+ <NetworkIcons_1.BoltIcon color={AppColors_1.AppColors.brandPurple} size={12}/>
387
+ <react_native_1.Text style={reduxTabStyles.lastActionLabel}>{t('redux.last', 'Last')}:</react_native_1.Text>
388
+
389
+ {/* Origin Badge */}
390
+ {item.lastAction.originType && (<react_native_1.View style={{
391
+ flexDirection: 'row',
392
+ alignItems: 'center',
393
+ gap: 2.5,
394
+ backgroundColor: getOriginBadge(item.lastAction.originType).bg,
395
+ paddingHorizontal: 4.5,
396
+ paddingVertical: 1.5,
397
+ borderRadius: 3.5,
398
+ borderWidth: 1,
399
+ borderColor: getOriginBadge(item.lastAction.originType).border,
400
+ }}>
401
+ <react_native_1.Text style={{ fontSize: 8.5 }}>
402
+ {getOriginBadge(item.lastAction.originType).icon}
403
+ </react_native_1.Text>
404
+ <react_native_1.Text style={{
405
+ fontFamily: AppFonts_1.AppFonts.interBold,
406
+ fontSize: 8,
407
+ color: getOriginBadge(item.lastAction.originType).text,
408
+ letterSpacing: 0.3,
409
+ }}>
410
+ {getOriginBadge(item.lastAction.originType).label}
411
+ </react_native_1.Text>
412
+ </react_native_1.View>)}
413
+
414
+ <HighlightText_1.default text={item.lastAction.type} search={reduxSearch} style={reduxTabStyles.lastActionValue} highlightStyle={reduxTabStyles.highlight} numberOfLines={1}/>
415
+
416
+ {/* Triggered from file preview */}
417
+ {item.lastAction.callerFile && (<react_native_1.Pressable onPress={() => (0, helpers_1.openInVSCode)(item.lastAction.callerFile, item.lastAction.callerLine, item.lastAction.callerCol)} hitSlop={6} style={{
418
+ flexDirection: 'row',
419
+ alignItems: 'center',
420
+ gap: 2,
421
+ backgroundColor: AppColors_1.AppColors.sky100,
422
+ paddingHorizontal: 4.5,
423
+ paddingVertical: 1.5,
424
+ borderRadius: 3,
425
+ borderWidth: 0.5,
426
+ borderColor: AppColors_1.AppColors.sky400,
427
+ }}>
428
+ <react_native_1.Text style={{
429
+ fontFamily: AppFonts_1.AppFonts.interMedium,
430
+ fontSize: 8.5,
431
+ color: AppColors_1.AppColors.sky600,
432
+ }}>
433
+ 📄 {item.lastAction.callerFile.split('/').pop()}:{item.lastAction.callerLine || 1}
434
+ </react_native_1.Text>
435
+ </react_native_1.Pressable>)}
436
+
437
+ {item.lastAction.payloadPreview && (<react_native_1.Text style={reduxTabStyles.payloadPreviewText} numberOfLines={1}>
438
+ {item.lastAction.payloadPreview}
439
+ </react_native_1.Text>)}
440
+ </react_native_1.View>
161
441
  </react_native_1.View>)}
162
442
  </TouchableScale_1.default>
163
443
  </AnimatedEntrance_1.default>);
164
- }, [reduxSearch, setSelectedReduxSlice]);
444
+ }, [reduxSearch, setSelectedReduxSlice, t]);
165
445
  if (!reduxState) {
166
446
  return (<react_native_1.View style={styles_1.default.emptyContainer}>
167
447
  <react_native_1.View style={styles_1.default.emptyIconWrap}>
@@ -186,8 +466,24 @@ const ReduxTab = react_1.default.memo(() => {
186
466
  <react_native_1.Text style={reduxTabStyles.statBigVal}>{totalStateSize}</react_native_1.Text>
187
467
  </react_native_1.View>
188
468
  <react_native_1.View style={reduxTabStyles.statDivider}/>
189
- <react_native_1.View style={[reduxTabStyles.statCol, { flex: 1.5 }]}>
190
- <react_native_1.Text style={reduxTabStyles.statHeading}>LAST ACTION</react_native_1.Text>
469
+ <react_native_1.View style={[reduxTabStyles.statCol, { flex: 1.6 }]}>
470
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
471
+ <react_native_1.Text style={reduxTabStyles.statHeading}>LAST ACTION</react_native_1.Text>
472
+ {lastGlobalAction?.originType && (<react_native_1.View style={{
473
+ backgroundColor: getOriginBadge(lastGlobalAction.originType).bg,
474
+ paddingHorizontal: 4,
475
+ paddingVertical: 1,
476
+ borderRadius: 3,
477
+ }}>
478
+ <react_native_1.Text style={{
479
+ fontFamily: AppFonts_1.AppFonts.interBold,
480
+ fontSize: 7.5,
481
+ color: getOriginBadge(lastGlobalAction.originType).text,
482
+ }}>
483
+ {getOriginBadge(lastGlobalAction.originType).label}
484
+ </react_native_1.Text>
485
+ </react_native_1.View>)}
486
+ </react_native_1.View>
191
487
  <react_native_1.Text style={reduxTabStyles.statLastAction} numberOfLines={1}>
192
488
  {lastGlobalAction ? lastGlobalAction.type : 'Initial'}
193
489
  </react_native_1.Text>
@@ -208,6 +504,19 @@ const ReduxTab = react_1.default.memo(() => {
208
504
  </react_native_1.Pressable>)}
209
505
  </react_native_1.View>
210
506
 
507
+ {/* Pause / Resume Live Updates Button */}
508
+ <react_native_1.TouchableOpacity style={[
509
+ styles_1.default.toolbarBtn,
510
+ isReduxPaused && {
511
+ backgroundColor: `${AppColors_1.AppColors.darkOrange}1F`,
512
+ borderColor: AppColors_1.AppColors.darkOrange,
513
+ },
514
+ ]} onPress={handleTogglePause} hitSlop={6}>
515
+ <NetworkIcons_1.HeaderPauseIcon isPaused={isReduxPaused} color={isReduxPaused
516
+ ? AppColors_1.AppColors.darkOrange
517
+ : AppColors_1.AppColors.grayTextStrong} size={16}/>
518
+ </react_native_1.TouchableOpacity>
519
+
211
520
  {/* Sort Button */}
212
521
  <react_native_1.TouchableOpacity style={[
213
522
  styles_1.default.toolbarBtn,
@@ -221,11 +530,16 @@ const ReduxTab = react_1.default.memo(() => {
221
530
  <react_native_1.Text style={reduxTabStyles.resultCount}>
222
531
  Showing {filteredSlices.length} of {sliceItems.length} state slices
223
532
  </react_native_1.Text>
224
- <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
225
- {sortMode === 'latest' ? (<NetworkIcons_1.BoltIcon color={AppColors_1.AppColors.brandPurple} size={11}/>) : (<NetworkIcons_1.TextAaIcon color={AppColors_1.AppColors.brandPurple} size={11}/>)}
226
- <react_native_1.Text style={reduxTabStyles.sortLabel}>
227
- {sortMode === 'latest' ? 'Newest Updates First' : 'Alphabetical (A-Z)'}
228
- </react_native_1.Text>
533
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
534
+ {isReduxPaused && (<react_native_1.View style={reduxTabStyles.pausedBannerPill}>
535
+ <react_native_1.Text style={reduxTabStyles.pausedBannerText}>PAUSED</react_native_1.Text>
536
+ </react_native_1.View>)}
537
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
538
+ {sortMode === 'latest' ? (<NetworkIcons_1.BoltIcon color={AppColors_1.AppColors.brandPurple} size={11}/>) : (<NetworkIcons_1.TextAaIcon color={AppColors_1.AppColors.brandPurple} size={11}/>)}
539
+ <react_native_1.Text style={reduxTabStyles.sortLabel}>
540
+ {sortMode === 'latest' ? 'Newest Updates First' : 'Alphabetical (A-Z)'}
541
+ </react_native_1.Text>
542
+ </react_native_1.View>
229
543
  </react_native_1.View>
230
544
  </react_native_1.View>
231
545
  </react_native_1.View>
@@ -428,17 +742,104 @@ const reduxTabStyles = react_native_1.StyleSheet.create({
428
742
  livePillText: {
429
743
  fontFamily: AppFonts_1.AppFonts.interBold,
430
744
  fontSize: 10,
431
- color: '#047857',
745
+ color: AppColors_1.AppColors.emerald700,
432
746
  },
433
- lastActionRow: {
747
+ loadingPill: {
748
+ backgroundColor: AppColors_1.AppColors.amber100,
749
+ paddingHorizontal: 6,
750
+ paddingVertical: 3,
751
+ borderRadius: 5,
752
+ borderWidth: 1,
753
+ borderColor: AppColors_1.AppColors.amber200,
754
+ },
755
+ loadingPillText: {
756
+ fontFamily: AppFonts_1.AppFonts.interBold,
757
+ fontSize: 9.5,
758
+ color: AppColors_1.AppColors.amber800Warm,
759
+ },
760
+ errorPill: {
761
+ backgroundColor: AppColors_1.AppColors.red100,
762
+ paddingHorizontal: 6,
763
+ paddingVertical: 3,
764
+ borderRadius: 5,
765
+ borderWidth: 1,
766
+ borderColor: AppColors_1.AppColors.errorBorder,
767
+ },
768
+ errorPillText: {
769
+ fontFamily: AppFonts_1.AppFonts.interBold,
770
+ fontSize: 9.5,
771
+ color: AppColors_1.AppColors.red600,
772
+ },
773
+ emptyPill: {
774
+ backgroundColor: AppColors_1.AppColors.grayBackground,
775
+ paddingHorizontal: 6,
776
+ paddingVertical: 3,
777
+ borderRadius: 5,
778
+ borderWidth: 1,
779
+ borderColor: AppColors_1.AppColors.dividerColor,
780
+ },
781
+ emptyPillText: {
782
+ fontFamily: AppFonts_1.AppFonts.interMedium,
783
+ fontSize: 9.5,
784
+ color: AppColors_1.AppColors.grayTextWeak,
785
+ },
786
+ keysContainer: {
434
787
  flexDirection: 'row',
435
788
  alignItems: 'center',
436
789
  gap: 6,
790
+ marginTop: 4,
791
+ marginBottom: 4,
792
+ },
793
+ keysHeading: {
794
+ fontFamily: AppFonts_1.AppFonts.interMedium,
795
+ fontSize: 10,
796
+ color: AppColors_1.AppColors.grayTextWeak,
797
+ },
798
+ keysWrap: {
799
+ flexDirection: 'row',
800
+ flexWrap: 'wrap',
801
+ gap: 4,
802
+ flex: 1,
803
+ },
804
+ keyChip: {
805
+ flexDirection: 'row',
806
+ alignItems: 'center',
807
+ gap: 4,
808
+ backgroundColor: AppColors_1.AppColors.slate100,
809
+ paddingHorizontal: 6,
810
+ paddingVertical: 2.5,
811
+ borderRadius: 5,
812
+ borderWidth: 1,
813
+ borderColor: AppColors_1.AppColors.slate200,
814
+ maxWidth: 120,
815
+ },
816
+ keyChipText: {
817
+ fontFamily: AppFonts_1.AppFonts.interBold,
818
+ fontSize: 9.5,
819
+ color: AppColors_1.AppColors.slate700,
820
+ },
821
+ keyMoreChip: {
822
+ backgroundColor: AppColors_1.AppColors.purple100,
823
+ paddingHorizontal: 5,
824
+ paddingVertical: 2,
825
+ borderRadius: 4,
826
+ borderWidth: 1,
827
+ borderColor: AppColors_1.AppColors.purple200,
828
+ },
829
+ keyMoreChipText: {
830
+ fontFamily: AppFonts_1.AppFonts.interBold,
831
+ fontSize: 9,
832
+ color: AppColors_1.AppColors.brandPurple,
833
+ },
834
+ lastActionRow: {
835
+ flexDirection: 'row',
836
+ alignItems: 'center',
837
+ gap: 5,
437
838
  backgroundColor: AppColors_1.AppColors.grayBackground,
438
839
  borderRadius: 6,
439
840
  paddingHorizontal: 8,
440
- paddingVertical: 4,
441
- marginTop: 2,
841
+ paddingVertical: 5,
842
+ marginTop: 4,
442
843
  borderWidth: 1,
443
844
  borderColor: AppColors_1.AppColors.dividerColor,
444
845
  },
@@ -448,15 +849,35 @@ const reduxTabStyles = react_native_1.StyleSheet.create({
448
849
  color: AppColors_1.AppColors.grayTextWeak,
449
850
  },
450
851
  lastActionValue: {
451
- flex: 1,
452
852
  fontFamily: AppFonts_1.AppFonts.interBold,
453
853
  fontSize: 11,
454
854
  color: AppColors_1.AppColors.primaryBlack,
455
855
  },
856
+ payloadPreviewText: {
857
+ flex: 1,
858
+ fontFamily: AppFonts_1.AppFonts.interRegular,
859
+ fontSize: 10,
860
+ color: AppColors_1.AppColors.grayTextWeak,
861
+ marginLeft: 4,
862
+ },
456
863
  highlight: {
457
- backgroundColor: '#FEF08A',
458
- color: '#854D0E',
864
+ backgroundColor: AppColors_1.AppColors.yellow200,
865
+ color: AppColors_1.AppColors.yellow800,
866
+ fontFamily: AppFonts_1.AppFonts.interBold,
867
+ },
868
+ pausedBannerPill: {
869
+ backgroundColor: AppColors_1.AppColors.amber100,
870
+ paddingHorizontal: 6,
871
+ paddingVertical: 2,
872
+ borderRadius: 4,
873
+ borderWidth: 1,
874
+ borderColor: AppColors_1.AppColors.amber200,
875
+ },
876
+ pausedBannerText: {
459
877
  fontFamily: AppFonts_1.AppFonts.interBold,
878
+ fontSize: 9,
879
+ color: AppColors_1.AppColors.amber800Warm,
880
+ letterSpacing: 0.5,
460
881
  },
461
882
  });
462
883
  exports.default = ReduxTab;