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 +16 -1
- package/lib/module/VConsole.js +283 -46
- package/lib/module/VConsole.js.map +1 -1
- package/lib/module/core/xhrProxy.js +145 -7
- package/lib/module/core/xhrProxy.js.map +1 -1
- package/lib/typescript/src/VConsole.d.ts +6 -1
- package/lib/typescript/src/VConsole.d.ts.map +1 -1
- package/lib/typescript/src/core/xhrProxy.d.ts +1 -0
- package/lib/typescript/src/core/xhrProxy.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +2 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/VConsole.tsx +356 -53
- package/src/core/xhrProxy.ts +177 -8
- package/src/types.ts +2 -0
package/README.md
CHANGED
|
@@ -18,12 +18,27 @@ export default function App() {
|
|
|
18
18
|
return (
|
|
19
19
|
<>
|
|
20
20
|
{/* your app content */}
|
|
21
|
-
<VConsole
|
|
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.
|
package/lib/module/VConsole.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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:
|
|
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,
|
|
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:
|
|
305
|
-
log:
|
|
306
|
-
info:
|
|
307
|
-
warn:
|
|
308
|
-
error:
|
|
309
|
-
}), [
|
|
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: ["
|
|
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: "
|
|
428
|
-
}), /*#__PURE__*/_jsx(
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
})
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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'
|
|
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',
|