react-native-vconsole 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,12 +18,27 @@ export default function App() {
18
18
  return (
19
19
  <>
20
20
  {/* your app content */}
21
- <VConsole enable={true} exclude={['localhost:8081']} />
21
+ <VConsole
22
+ enable={true}
23
+ exclude={{
24
+ domains: ['localhost:8081'],
25
+ ip: true,
26
+ }}
27
+ />
22
28
  </>
23
29
  );
24
30
  }
25
31
  ```
26
32
 
33
+ ## VConsole Props
34
+
35
+ | Prop | Type | Default | Description |
36
+ | --- | --- | --- | --- |
37
+ | `enable` | `boolean` | `true` | Whether to enable and render vConsole. |
38
+ | `exclude` | `{ domains?: string[]; ip?: boolean }` | `{}` | Network capture exclusion rules. |
39
+ | `exclude.domains` | `string[]` | `[]` | Hosts to exclude from Network tab capture, keeping previous host-based matching behavior (e.g. `localhost:8081`). |
40
+ | `exclude.ip` | `boolean` | `false` | When `true`, requests whose hostname is an IP address (IPv4/IPv6) will be skipped in Network tab capture. |
41
+
27
42
  ## Features
28
43
 
29
44
  - Draggable floating button (`vConsole`) with screen-boundary constraints.
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
 
3
3
  import { useEffect, useMemo, useRef, useState } from 'react';
4
- import { Animated, Clipboard, Dimensions, FlatList, NativeModules, PanResponder, Platform, Pressable, StatusBar, StyleSheet, Text, ToastAndroid, View, ScrollView } from 'react-native';
4
+ import { Animated, Clipboard, Dimensions, FlatList, Keyboard, NativeModules, PanResponder, Platform, Pressable, TextInput, StatusBar, StyleSheet, Text, ToastAndroid, View, ScrollView } from 'react-native';
5
5
  import { clearLogEntries, getLogEntries, installConsoleProxy, subscribeLogEntries, uninstallConsoleProxy } from "./core/consoleProxy.js";
6
6
  import { clearNetworkEntries, getNetworkEntries, installXhrProxy, subscribeNetworkEntries, uninstallXhrProxy } from "./core/xhrProxy.js";
7
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
8
8
  const BUTTON_WIDTH = 88;
9
9
  const BUTTON_HEIGHT = 36;
10
10
  const PANEL_HEIGHT_RATIO = 7 / 9;
11
- const EMPTY_FILTER = [];
11
+ const EMPTY_EXCLUDE = {};
12
12
  const LOG_SUB_TABS = ['All', 'log', 'info', 'warn', 'error'];
13
13
  const ROOT_TABS = ['Log', 'Network', 'System', 'App'];
14
14
  const LOG_THEME = {
@@ -61,6 +61,17 @@ function formatMemorySize(bytes) {
61
61
  }
62
62
  return `${mb.toFixed(2)} MB`;
63
63
  }
64
+ function formatLogTime(timestamp) {
65
+ const date = new Date(timestamp);
66
+ if (Number.isNaN(date.getTime())) {
67
+ return '--:--:--.---';
68
+ }
69
+ const hh = String(date.getHours()).padStart(2, '0');
70
+ const mm = String(date.getMinutes()).padStart(2, '0');
71
+ const ss = String(date.getSeconds()).padStart(2, '0');
72
+ const ms = String(date.getMilliseconds()).padStart(3, '0');
73
+ return `${hh}:${mm}:${ss}.${ms}`;
74
+ }
64
75
  function prettyText(value) {
65
76
  if (value === undefined) {
66
77
  return '';
@@ -74,10 +85,74 @@ function prettyText(value) {
74
85
  return String(value);
75
86
  }
76
87
  }
88
+ function isNetworkErrorEntry(item) {
89
+ return item.isError === true;
90
+ }
77
91
  function buildNetworkCopyText(item) {
78
92
  const status = item.status ?? '-';
79
93
  const duration = typeof item.durationMs === 'number' ? `${item.durationMs}ms` : '-';
80
- return [`${item.method} ${item.url}`, `status ${status} duration ${duration}`, `request headers\n${prettyText(item.requestHeaders)}`, `request body\n${prettyText(item.requestBody)}`, `response headers\n${prettyText(item.responseHeaders)}`, `response data\n${prettyText(item.responseData)}`].join('\n');
94
+ const isError = isNetworkErrorEntry(item);
95
+ const segments = [`${item.method} ${item.url}`, `status ${status} duration ${duration}`, `request headers\n${prettyText(item.requestHeaders)}`, `request body\n${prettyText(item.requestBody)}`];
96
+ if (isError) {
97
+ segments.push(`error reason\n${item.errorReason ?? 'Network request failed'}`);
98
+ } else {
99
+ segments.push(`response headers\n${prettyText(item.responseHeaders)}`);
100
+ segments.push(`response data\n${prettyText(item.responseData)}`);
101
+ }
102
+ return segments.join('\n');
103
+ }
104
+ const FORBIDDEN_RETRY_HEADERS = new Set(['host', 'content-length', 'accept-encoding', 'connection', 'origin', 'referer']);
105
+ function normalizeRetryUrl(rawUrl) {
106
+ if (!rawUrl) {
107
+ return '';
108
+ }
109
+ if (/^\/\//.test(rawUrl)) {
110
+ return `https:${rawUrl}`;
111
+ }
112
+ return rawUrl;
113
+ }
114
+ function buildRetryHeaders(headers) {
115
+ const nextHeaders = {};
116
+ if (!headers) {
117
+ return nextHeaders;
118
+ }
119
+ Object.entries(headers).forEach(([key, value]) => {
120
+ if (!FORBIDDEN_RETRY_HEADERS.has(key.toLowerCase())) {
121
+ nextHeaders[key] = value;
122
+ }
123
+ });
124
+ return nextHeaders;
125
+ }
126
+ function buildRetryBody(payload, method) {
127
+ if (method === 'GET' || method === 'HEAD' || payload == null) {
128
+ return undefined;
129
+ }
130
+ if (typeof payload === 'string') {
131
+ return payload;
132
+ }
133
+ if (typeof payload === 'number' || typeof payload === 'boolean') {
134
+ return String(payload);
135
+ }
136
+ if (typeof FormData !== 'undefined' && payload instanceof FormData) {
137
+ return payload;
138
+ }
139
+ if (typeof URLSearchParams !== 'undefined' && payload instanceof URLSearchParams) {
140
+ return payload;
141
+ }
142
+ if (typeof Blob !== 'undefined' && payload instanceof Blob) {
143
+ return payload;
144
+ }
145
+ if (typeof ArrayBuffer !== 'undefined' && payload instanceof ArrayBuffer) {
146
+ return payload;
147
+ }
148
+ if (ArrayBuffer.isView(payload)) {
149
+ return payload;
150
+ }
151
+ try {
152
+ return JSON.stringify(payload);
153
+ } catch {
154
+ return String(payload);
155
+ }
81
156
  }
82
157
  function ObjectTree({
83
158
  value,
@@ -166,7 +241,7 @@ function useFlatListRefs() {
166
241
  }
167
242
  export function VConsole({
168
243
  enable = true,
169
- exclude = EMPTY_FILTER
244
+ exclude = EMPTY_EXCLUDE
170
245
  }) {
171
246
  const nativeModule = NativeModules.Vconsole;
172
247
  const {
@@ -201,6 +276,11 @@ export function VConsole({
201
276
  const [logSubTab, setLogSubTab] = useState('All');
202
277
  const [logEntries, setLogEntries] = useState([]);
203
278
  const [networkEntries, setNetworkEntries] = useState([]);
279
+ const [logFilterInput, setLogFilterInput] = useState('');
280
+ const [networkFilterInput, setNetworkFilterInput] = useState('');
281
+ const [debouncedLogFilter, setDebouncedLogFilter] = useState('');
282
+ const [debouncedNetworkFilter, setDebouncedNetworkFilter] = useState('');
283
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
204
284
  const [expandedMap, setExpandedMap] = useState({});
205
285
  const [systemInfo, setSystemInfo] = useState(null);
206
286
  const [appInfo, setAppInfo] = useState(null);
@@ -208,7 +288,8 @@ export function VConsole({
208
288
  const panelTranslateY = useRef(new Animated.Value(panelHeight)).current;
209
289
  const logListRefs = useFlatListRefs();
210
290
  const networkListRef = useRef(null);
211
- const normalizedExclude = useMemo(() => exclude.map(item => item.trim().toLowerCase()).filter(Boolean), [exclude]);
291
+ const normalizedExcludeDomains = useMemo(() => (exclude.domains ?? []).map(item => item.trim().toLowerCase()).filter(Boolean), [exclude.domains]);
292
+ const shouldExcludeIp = exclude.ip === true;
212
293
  useEffect(() => {
213
294
  if (!enable) {
214
295
  setPanelVisible(false);
@@ -216,7 +297,8 @@ export function VConsole({
216
297
  }
217
298
  installConsoleProxy();
218
299
  installXhrProxy({
219
- excludeHosts: normalizedExclude
300
+ excludeHosts: normalizedExcludeDomains,
301
+ excludeIp: shouldExcludeIp
220
302
  });
221
303
  const unsubscribeLog = subscribeLogEntries(setLogEntries);
222
304
  const unsubscribeNetwork = subscribeNetworkEntries(setNetworkEntries);
@@ -228,7 +310,7 @@ export function VConsole({
228
310
  uninstallConsoleProxy();
229
311
  uninstallXhrProxy();
230
312
  };
231
- }, [enable, normalizedExclude]);
313
+ }, [enable, normalizedExcludeDomains, shouldExcludeIp]);
232
314
  useEffect(() => {
233
315
  dragPosition.stopAnimation(value => {
234
316
  const nextX = clamp(value.x, minX, maxX);
@@ -251,6 +333,32 @@ export function VConsole({
251
333
  nativeModule?.getAppInfo?.().then(result => setAppInfo(result)).catch(() => undefined);
252
334
  }
253
335
  }, [activeTab, appInfo, nativeModule, panelVisible, systemInfo]);
336
+ useEffect(() => {
337
+ const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
338
+ const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
339
+ const showSubscription = Keyboard.addListener(showEvent, event => {
340
+ setKeyboardHeight(event.endCoordinates?.height ?? 0);
341
+ });
342
+ const hideSubscription = Keyboard.addListener(hideEvent, () => {
343
+ setKeyboardHeight(0);
344
+ });
345
+ return () => {
346
+ showSubscription.remove();
347
+ hideSubscription.remove();
348
+ };
349
+ }, []);
350
+ useEffect(() => {
351
+ const timer = setTimeout(() => {
352
+ setDebouncedLogFilter(logFilterInput);
353
+ }, 1000);
354
+ return () => clearTimeout(timer);
355
+ }, [logFilterInput]);
356
+ useEffect(() => {
357
+ const timer = setTimeout(() => {
358
+ setDebouncedNetworkFilter(networkFilterInput);
359
+ }, 1000);
360
+ return () => clearTimeout(timer);
361
+ }, [networkFilterInput]);
254
362
  const panResponder = useMemo(() => PanResponder.create({
255
363
  onMoveShouldSetPanResponder: () => true,
256
364
  onPanResponderGrant: () => {
@@ -300,13 +408,27 @@ export function VConsole({
300
408
  }
301
409
  });
302
410
  };
411
+ const normalizedLogFilter = debouncedLogFilter.trim().toLowerCase();
412
+ const normalizedNetworkFilter = debouncedNetworkFilter.trim().toLowerCase();
413
+ const filteredLogEntries = useMemo(() => {
414
+ if (!normalizedLogFilter) {
415
+ return logEntries;
416
+ }
417
+ return logEntries.filter(item => item.text.toLowerCase().includes(normalizedLogFilter));
418
+ }, [logEntries, normalizedLogFilter]);
419
+ const filteredNetworkEntries = useMemo(() => {
420
+ if (!normalizedNetworkFilter) {
421
+ return networkEntries;
422
+ }
423
+ return networkEntries.filter(item => item.url.toLowerCase().includes(normalizedNetworkFilter));
424
+ }, [networkEntries, normalizedNetworkFilter]);
303
425
  const logDataByTab = useMemo(() => ({
304
- All: logEntries,
305
- log: logEntries.filter(item => item.level === 'log'),
306
- info: logEntries.filter(item => item.level === 'info'),
307
- warn: logEntries.filter(item => item.level === 'warn'),
308
- error: logEntries.filter(item => item.level === 'error')
309
- }), [logEntries]);
426
+ All: filteredLogEntries,
427
+ log: filteredLogEntries.filter(item => item.level === 'log'),
428
+ info: filteredLogEntries.filter(item => item.level === 'info'),
429
+ warn: filteredLogEntries.filter(item => item.level === 'warn'),
430
+ error: filteredLogEntries.filter(item => item.level === 'error')
431
+ }), [filteredLogEntries]);
310
432
  const onToggleNode = key => {
311
433
  setExpandedMap(prev => ({
312
434
  ...prev,
@@ -335,6 +457,27 @@ export function VConsole({
335
457
  animated: true
336
458
  });
337
459
  };
460
+ const retryNetworkRequest = item => {
461
+ const method = (item.method || 'GET').toUpperCase();
462
+ const url = normalizeRetryUrl(item.url);
463
+ if (!url) {
464
+ console.error('[vConsole] Retry failed: empty request URL');
465
+ return;
466
+ }
467
+ const headers = buildRetryHeaders(item.requestHeaders);
468
+ const body = buildRetryBody(item.requestBody, method);
469
+ const hasContentType = Object.keys(headers).some(key => key.toLowerCase() === 'content-type');
470
+ if (body && typeof body === 'string' && typeof item.requestBody === 'object' && item.requestBody !== null && !hasContentType) {
471
+ headers['Content-Type'] = 'application/json';
472
+ }
473
+ fetch(url, {
474
+ method,
475
+ headers,
476
+ body: body
477
+ }).catch(error => {
478
+ console.error('[vConsole] Retry request failed', error);
479
+ });
480
+ };
338
481
  const renderRootTab = tab => /*#__PURE__*/_jsx(Pressable, {
339
482
  style: [styles.topTabButton, activeTab === tab && styles.topTabButtonActive],
340
483
  onPress: () => setActiveTab(tab),
@@ -365,7 +508,10 @@ export function VConsole({
365
508
  style: [styles.logLevelText, {
366
509
  color: levelTheme.color
367
510
  }],
368
- children: ["[", item.level.toUpperCase(), "]"]
511
+ children: ["[", item.level.toUpperCase(), "]", /*#__PURE__*/_jsxs(Text, {
512
+ style: styles.logTimeText,
513
+ children: [' ', formatLogTime(item.timestamp)]
514
+ })]
369
515
  }), /*#__PURE__*/_jsx(View, {
370
516
  style: styles.logPayload,
371
517
  children: item.args.map((arg, index) => /*#__PURE__*/_jsx(ObjectTree, {
@@ -388,8 +534,13 @@ export function VConsole({
388
534
  const renderNetworkItem = ({
389
535
  item
390
536
  }) => {
537
+ const isError = isNetworkErrorEntry(item);
538
+ const startedTime = formatLogTime(item.startedAt);
539
+ const finishedTime = typeof item.finishedAt === 'number' ? formatLogTime(item.finishedAt) : '-';
391
540
  return /*#__PURE__*/_jsxs(View, {
392
- style: styles.listItem,
541
+ style: [styles.listItem, isError ? {
542
+ backgroundColor: LOG_THEME.error.backgroundColor
543
+ } : null],
393
544
  children: [/*#__PURE__*/_jsxs(View, {
394
545
  style: styles.listItemMain,
395
546
  children: [/*#__PURE__*/_jsxs(Text, {
@@ -397,7 +548,10 @@ export function VConsole({
397
548
  children: [item.method, " ", item.url]
398
549
  }), /*#__PURE__*/_jsxs(Text, {
399
550
  style: styles.networkLabel,
400
- children: ["Status: ", item.status ?? '-', ' ', "Duration:", ' ', typeof item.durationMs === 'number' ? `${item.durationMs}ms` : '-']
551
+ children: ["Time: ", startedTime, finishedTime !== '-' ? ` ~ ${finishedTime}` : '', ' ', "Duration:", ' ', typeof item.durationMs === 'number' ? `${item.durationMs}ms` : '-']
552
+ }), /*#__PURE__*/_jsxs(Text, {
553
+ style: styles.networkLabel,
554
+ children: ["Status: ", item.status ?? '-']
401
555
  }), /*#__PURE__*/_jsxs(View, {
402
556
  style: styles.networkBlock,
403
557
  children: [/*#__PURE__*/_jsx(Text, {
@@ -420,30 +574,41 @@ export function VConsole({
420
574
  expandedMap: expandedMap,
421
575
  onToggle: onToggleNode
422
576
  })]
423
- }), /*#__PURE__*/_jsxs(View, {
577
+ }), isError ? /*#__PURE__*/_jsxs(View, {
424
578
  style: styles.networkBlock,
425
579
  children: [/*#__PURE__*/_jsx(Text, {
426
- style: styles.networkLabel,
427
- children: "Response Headers"
428
- }), /*#__PURE__*/_jsx(ObjectTree, {
429
- value: item.responseHeaders,
430
- nodeKey: `${item.id}.responseHeaders`,
431
- expandedMap: expandedMap,
432
- onToggle: onToggleNode
580
+ style: [styles.networkLabel, styles.networkErrorLabel],
581
+ children: "Error Reason"
582
+ }), /*#__PURE__*/_jsx(Text, {
583
+ style: styles.networkErrorText,
584
+ children: item.errorReason ?? 'Network request failed'
433
585
  })]
434
- }), /*#__PURE__*/_jsxs(View, {
435
- style: styles.networkBlock,
436
- children: [/*#__PURE__*/_jsx(Text, {
437
- style: styles.networkLabel,
438
- children: "Response Data"
439
- }), /*#__PURE__*/_jsx(ScrollView, {
440
- horizontal: true,
441
- children: /*#__PURE__*/_jsx(ObjectTree, {
442
- value: item.responseData ?? '',
443
- nodeKey: `${item.id}.responseData`,
586
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
587
+ children: [/*#__PURE__*/_jsxs(View, {
588
+ style: styles.networkBlock,
589
+ children: [/*#__PURE__*/_jsx(Text, {
590
+ style: styles.networkLabel,
591
+ children: "Response Headers"
592
+ }), /*#__PURE__*/_jsx(ObjectTree, {
593
+ value: item.responseHeaders,
594
+ nodeKey: `${item.id}.responseHeaders`,
444
595
  expandedMap: expandedMap,
445
596
  onToggle: onToggleNode
446
- })
597
+ })]
598
+ }), /*#__PURE__*/_jsxs(View, {
599
+ style: styles.networkBlock,
600
+ children: [/*#__PURE__*/_jsx(Text, {
601
+ style: styles.networkLabel,
602
+ children: "Response Data"
603
+ }), /*#__PURE__*/_jsx(ScrollView, {
604
+ horizontal: true,
605
+ children: /*#__PURE__*/_jsx(ObjectTree, {
606
+ value: item.responseData ?? '',
607
+ nodeKey: `${item.id}.responseData`,
608
+ expandedMap: expandedMap,
609
+ onToggle: onToggleNode
610
+ })
611
+ })]
447
612
  })]
448
613
  })]
449
614
  }), /*#__PURE__*/_jsx(Pressable, {
@@ -453,11 +618,18 @@ export function VConsole({
453
618
  style: styles.copyButtonText,
454
619
  children: "Copy"
455
620
  })
621
+ }), /*#__PURE__*/_jsx(Pressable, {
622
+ style: styles.retryButton,
623
+ onPress: () => retryNetworkRequest(item),
624
+ children: /*#__PURE__*/_jsx(Text, {
625
+ style: styles.retryButtonText,
626
+ children: "Retry"
627
+ })
456
628
  })]
457
629
  });
458
630
  };
459
- const renderLogPanel = () => /*#__PURE__*/_jsxs(View, {
460
- style: styles.contentArea,
631
+ const renderLogPanel = visible => /*#__PURE__*/_jsxs(View, {
632
+ style: [styles.contentArea, visible ? {} : styles.hidden],
461
633
  children: [/*#__PURE__*/_jsx(View, {
462
634
  style: styles.subTabRow,
463
635
  children: LOG_SUB_TABS.map(tab => /*#__PURE__*/_jsx(Pressable, {
@@ -480,6 +652,16 @@ export function VConsole({
480
652
  ItemSeparatorComponent: ListSeparator
481
653
  })
482
654
  }, tab))
655
+ }), /*#__PURE__*/_jsx(View, {
656
+ style: styles.filterInputWrap,
657
+ children: /*#__PURE__*/_jsx(TextInput, {
658
+ style: styles.filterInput,
659
+ textAlignVertical: "center",
660
+ value: logFilterInput,
661
+ onChangeText: setLogFilterInput,
662
+ placeholder: "filter...",
663
+ placeholderTextColor: "#999999"
664
+ })
483
665
  }), /*#__PURE__*/_jsxs(View, {
484
666
  style: styles.actionsRow,
485
667
  children: [renderActionButton('Clear', () => {
@@ -488,14 +670,23 @@ export function VConsole({
488
670
  }), renderActionButton('Top', scrollLogTop), renderActionButton('Bottom', scrollLogBottom), renderActionButton('Hide', closePanel)]
489
671
  })]
490
672
  });
491
- const renderNetworkPanel = () => /*#__PURE__*/_jsxs(View, {
492
- style: styles.contentArea,
673
+ const renderNetworkPanel = visible => /*#__PURE__*/_jsxs(View, {
674
+ style: [styles.contentArea, visible ? {} : styles.hidden],
493
675
  children: [/*#__PURE__*/_jsx(FlatList, {
494
676
  ref: networkListRef,
495
- data: networkEntries,
677
+ data: filteredNetworkEntries,
496
678
  keyExtractor: item => `network-${item.id}`,
497
679
  renderItem: renderNetworkItem,
498
680
  ItemSeparatorComponent: ListSeparator
681
+ }), /*#__PURE__*/_jsx(View, {
682
+ style: styles.filterInputWrap,
683
+ children: /*#__PURE__*/_jsx(TextInput, {
684
+ style: styles.filterInput,
685
+ value: networkFilterInput,
686
+ onChangeText: setNetworkFilterInput,
687
+ placeholder: "filter",
688
+ placeholderTextColor: "#999999"
689
+ })
499
690
  }), /*#__PURE__*/_jsxs(View, {
500
691
  style: styles.actionsRow,
501
692
  children: [renderActionButton('Clear', () => {
@@ -504,8 +695,8 @@ export function VConsole({
504
695
  }), renderActionButton('Top', scrollNetworkTop), renderActionButton('Bottom', scrollNetworkBottom), renderActionButton('Hide', closePanel)]
505
696
  })]
506
697
  });
507
- const renderSystemPanel = () => /*#__PURE__*/_jsxs(View, {
508
- style: styles.contentArea,
698
+ const renderSystemPanel = visible => /*#__PURE__*/_jsxs(View, {
699
+ style: [styles.contentArea, visible ? {} : styles.hidden],
509
700
  children: [/*#__PURE__*/_jsxs(View, {
510
701
  style: styles.infoCard,
511
702
  children: [/*#__PURE__*/_jsxs(Text, {
@@ -535,8 +726,8 @@ export function VConsole({
535
726
  children: renderActionButton('Hide', closePanel)
536
727
  })]
537
728
  });
538
- const renderAppPanel = () => /*#__PURE__*/_jsxs(View, {
539
- style: styles.contentArea,
729
+ const renderAppPanel = visible => /*#__PURE__*/_jsxs(View, {
730
+ style: [styles.contentArea, visible ? {} : styles.hidden],
540
731
  children: [/*#__PURE__*/_jsxs(View, {
541
732
  style: styles.infoCard,
542
733
  children: [/*#__PURE__*/_jsxs(Text, {
@@ -578,6 +769,7 @@ export function VConsole({
578
769
  }), /*#__PURE__*/_jsxs(Animated.View, {
579
770
  style: [styles.panel, {
580
771
  height: panelHeight,
772
+ marginBottom: keyboardHeight,
581
773
  transform: [{
582
774
  translateY: panelTranslateY
583
775
  }]
@@ -585,7 +777,7 @@ export function VConsole({
585
777
  children: [/*#__PURE__*/_jsx(View, {
586
778
  style: styles.topTabRow,
587
779
  children: ROOT_TABS.map(renderRootTab)
588
- }), activeTab === 'Log' ? renderLogPanel() : null, activeTab === 'Network' ? renderNetworkPanel() : null, activeTab === 'System' ? renderSystemPanel() : null, activeTab === 'App' ? renderAppPanel() : null]
780
+ }), renderLogPanel(activeTab === 'Log'), renderNetworkPanel(activeTab === 'Network'), renderSystemPanel(activeTab === 'System'), renderAppPanel(activeTab === 'App')]
589
781
  })]
590
782
  }) : null]
591
783
  });
@@ -701,6 +893,11 @@ const styles = StyleSheet.create({
701
893
  fontWeight: '700',
702
894
  marginBottom: 4
703
895
  },
896
+ logTimeText: {
897
+ fontSize: 11,
898
+ fontWeight: '400',
899
+ color: '#888888'
900
+ },
704
901
  logPayload: {
705
902
  flex: 1
706
903
  },
@@ -718,6 +915,20 @@ const styles = StyleSheet.create({
718
915
  fontSize: 11,
719
916
  color: '#333333'
720
917
  },
918
+ retryButton: {
919
+ position: 'absolute',
920
+ right: 8,
921
+ top: 40,
922
+ borderWidth: StyleSheet.hairlineWidth,
923
+ borderColor: '#D0D0D0',
924
+ borderRadius: 6,
925
+ paddingVertical: 4,
926
+ paddingHorizontal: 8
927
+ },
928
+ retryButtonText: {
929
+ fontSize: 11,
930
+ color: '#333333'
931
+ },
721
932
  valuePrimitive: {
722
933
  color: '#222222',
723
934
  fontSize: 12,
@@ -780,6 +991,32 @@ const styles = StyleSheet.create({
780
991
  color: '#444444',
781
992
  marginBottom: 2
782
993
  },
994
+ networkErrorLabel: {
995
+ color: LOG_THEME.error.color,
996
+ fontWeight: '600'
997
+ },
998
+ networkErrorText: {
999
+ color: LOG_THEME.error.color,
1000
+ fontSize: 12
1001
+ },
1002
+ filterInputWrap: {
1003
+ borderTopWidth: StyleSheet.hairlineWidth,
1004
+ borderTopColor: '#E1E1E1',
1005
+ paddingHorizontal: 8,
1006
+ paddingTop: 8,
1007
+ paddingBottom: 6
1008
+ },
1009
+ filterInput: {
1010
+ height: 34,
1011
+ borderWidth: StyleSheet.hairlineWidth,
1012
+ borderColor: '#D0D0D0',
1013
+ borderRadius: 8,
1014
+ paddingHorizontal: 10,
1015
+ fontSize: 12,
1016
+ color: '#222222',
1017
+ backgroundColor: '#FFFFFF',
1018
+ paddingVertical: 0
1019
+ },
783
1020
  actionsRow: {
784
1021
  borderTopWidth: StyleSheet.hairlineWidth,
785
1022
  borderTopColor: '#E1E1E1',