react-native-vconsole 0.3.1 → 0.5.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 +301 -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 +376 -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,16 +1,18 @@
|
|
|
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
|
+
const NETWORK_DURATION_WARN_THRESHOLD_MS = 1000;
|
|
15
|
+
const NETWORK_DURATION_SEVERE_THRESHOLD_MS = 3000;
|
|
14
16
|
const LOG_THEME = {
|
|
15
17
|
log: {
|
|
16
18
|
backgroundColor: '#FFFFFF',
|
|
@@ -61,6 +63,17 @@ function formatMemorySize(bytes) {
|
|
|
61
63
|
}
|
|
62
64
|
return `${mb.toFixed(2)} MB`;
|
|
63
65
|
}
|
|
66
|
+
function formatLogTime(timestamp) {
|
|
67
|
+
const date = new Date(timestamp);
|
|
68
|
+
if (Number.isNaN(date.getTime())) {
|
|
69
|
+
return '--:--:--.---';
|
|
70
|
+
}
|
|
71
|
+
const hh = String(date.getHours()).padStart(2, '0');
|
|
72
|
+
const mm = String(date.getMinutes()).padStart(2, '0');
|
|
73
|
+
const ss = String(date.getSeconds()).padStart(2, '0');
|
|
74
|
+
const ms = String(date.getMilliseconds()).padStart(3, '0');
|
|
75
|
+
return `${hh}:${mm}:${ss}.${ms}`;
|
|
76
|
+
}
|
|
64
77
|
function prettyText(value) {
|
|
65
78
|
if (value === undefined) {
|
|
66
79
|
return '';
|
|
@@ -74,10 +87,89 @@ function prettyText(value) {
|
|
|
74
87
|
return String(value);
|
|
75
88
|
}
|
|
76
89
|
}
|
|
90
|
+
function isNetworkErrorEntry(item) {
|
|
91
|
+
return item.isError === true;
|
|
92
|
+
}
|
|
93
|
+
function getNetworkItemBackgroundColor(item) {
|
|
94
|
+
if (isNetworkErrorEntry(item)) {
|
|
95
|
+
return LOG_THEME.error.backgroundColor;
|
|
96
|
+
}
|
|
97
|
+
if (typeof item.durationMs !== 'number') {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
if (item.durationMs >= NETWORK_DURATION_SEVERE_THRESHOLD_MS) {
|
|
101
|
+
return LOG_THEME.error.backgroundColor;
|
|
102
|
+
}
|
|
103
|
+
if (item.durationMs >= NETWORK_DURATION_WARN_THRESHOLD_MS) {
|
|
104
|
+
return LOG_THEME.warn.backgroundColor;
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
77
108
|
function buildNetworkCopyText(item) {
|
|
78
109
|
const status = item.status ?? '-';
|
|
79
110
|
const duration = typeof item.durationMs === 'number' ? `${item.durationMs}ms` : '-';
|
|
80
|
-
|
|
111
|
+
const isError = isNetworkErrorEntry(item);
|
|
112
|
+
const segments = [`${item.method} ${item.url}`, `status ${status} duration ${duration}`, `request headers\n${prettyText(item.requestHeaders)}`, `request body\n${prettyText(item.requestBody)}`];
|
|
113
|
+
if (isError) {
|
|
114
|
+
segments.push(`error reason\n${item.errorReason ?? 'Network request failed'}`);
|
|
115
|
+
} else {
|
|
116
|
+
segments.push(`response headers\n${prettyText(item.responseHeaders)}`);
|
|
117
|
+
segments.push(`response data\n${prettyText(item.responseData)}`);
|
|
118
|
+
}
|
|
119
|
+
return segments.join('\n');
|
|
120
|
+
}
|
|
121
|
+
const FORBIDDEN_RETRY_HEADERS = new Set(['host', 'content-length', 'accept-encoding', 'connection', 'origin', 'referer']);
|
|
122
|
+
function normalizeRetryUrl(rawUrl) {
|
|
123
|
+
if (!rawUrl) {
|
|
124
|
+
return '';
|
|
125
|
+
}
|
|
126
|
+
if (/^\/\//.test(rawUrl)) {
|
|
127
|
+
return `https:${rawUrl}`;
|
|
128
|
+
}
|
|
129
|
+
return rawUrl;
|
|
130
|
+
}
|
|
131
|
+
function buildRetryHeaders(headers) {
|
|
132
|
+
const nextHeaders = {};
|
|
133
|
+
if (!headers) {
|
|
134
|
+
return nextHeaders;
|
|
135
|
+
}
|
|
136
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
137
|
+
if (!FORBIDDEN_RETRY_HEADERS.has(key.toLowerCase())) {
|
|
138
|
+
nextHeaders[key] = value;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return nextHeaders;
|
|
142
|
+
}
|
|
143
|
+
function buildRetryBody(payload, method) {
|
|
144
|
+
if (method === 'GET' || method === 'HEAD' || payload == null) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
if (typeof payload === 'string') {
|
|
148
|
+
return payload;
|
|
149
|
+
}
|
|
150
|
+
if (typeof payload === 'number' || typeof payload === 'boolean') {
|
|
151
|
+
return String(payload);
|
|
152
|
+
}
|
|
153
|
+
if (typeof FormData !== 'undefined' && payload instanceof FormData) {
|
|
154
|
+
return payload;
|
|
155
|
+
}
|
|
156
|
+
if (typeof URLSearchParams !== 'undefined' && payload instanceof URLSearchParams) {
|
|
157
|
+
return payload;
|
|
158
|
+
}
|
|
159
|
+
if (typeof Blob !== 'undefined' && payload instanceof Blob) {
|
|
160
|
+
return payload;
|
|
161
|
+
}
|
|
162
|
+
if (typeof ArrayBuffer !== 'undefined' && payload instanceof ArrayBuffer) {
|
|
163
|
+
return payload;
|
|
164
|
+
}
|
|
165
|
+
if (ArrayBuffer.isView(payload)) {
|
|
166
|
+
return payload;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
return JSON.stringify(payload);
|
|
170
|
+
} catch {
|
|
171
|
+
return String(payload);
|
|
172
|
+
}
|
|
81
173
|
}
|
|
82
174
|
function ObjectTree({
|
|
83
175
|
value,
|
|
@@ -166,7 +258,7 @@ function useFlatListRefs() {
|
|
|
166
258
|
}
|
|
167
259
|
export function VConsole({
|
|
168
260
|
enable = true,
|
|
169
|
-
exclude =
|
|
261
|
+
exclude = EMPTY_EXCLUDE
|
|
170
262
|
}) {
|
|
171
263
|
const nativeModule = NativeModules.Vconsole;
|
|
172
264
|
const {
|
|
@@ -201,6 +293,11 @@ export function VConsole({
|
|
|
201
293
|
const [logSubTab, setLogSubTab] = useState('All');
|
|
202
294
|
const [logEntries, setLogEntries] = useState([]);
|
|
203
295
|
const [networkEntries, setNetworkEntries] = useState([]);
|
|
296
|
+
const [logFilterInput, setLogFilterInput] = useState('');
|
|
297
|
+
const [networkFilterInput, setNetworkFilterInput] = useState('');
|
|
298
|
+
const [debouncedLogFilter, setDebouncedLogFilter] = useState('');
|
|
299
|
+
const [debouncedNetworkFilter, setDebouncedNetworkFilter] = useState('');
|
|
300
|
+
const [keyboardHeight, setKeyboardHeight] = useState(0);
|
|
204
301
|
const [expandedMap, setExpandedMap] = useState({});
|
|
205
302
|
const [systemInfo, setSystemInfo] = useState(null);
|
|
206
303
|
const [appInfo, setAppInfo] = useState(null);
|
|
@@ -208,7 +305,8 @@ export function VConsole({
|
|
|
208
305
|
const panelTranslateY = useRef(new Animated.Value(panelHeight)).current;
|
|
209
306
|
const logListRefs = useFlatListRefs();
|
|
210
307
|
const networkListRef = useRef(null);
|
|
211
|
-
const
|
|
308
|
+
const normalizedExcludeDomains = useMemo(() => (exclude.domains ?? []).map(item => item.trim().toLowerCase()).filter(Boolean), [exclude.domains]);
|
|
309
|
+
const shouldExcludeIp = exclude.ip === true;
|
|
212
310
|
useEffect(() => {
|
|
213
311
|
if (!enable) {
|
|
214
312
|
setPanelVisible(false);
|
|
@@ -216,7 +314,8 @@ export function VConsole({
|
|
|
216
314
|
}
|
|
217
315
|
installConsoleProxy();
|
|
218
316
|
installXhrProxy({
|
|
219
|
-
excludeHosts:
|
|
317
|
+
excludeHosts: normalizedExcludeDomains,
|
|
318
|
+
excludeIp: shouldExcludeIp
|
|
220
319
|
});
|
|
221
320
|
const unsubscribeLog = subscribeLogEntries(setLogEntries);
|
|
222
321
|
const unsubscribeNetwork = subscribeNetworkEntries(setNetworkEntries);
|
|
@@ -228,7 +327,7 @@ export function VConsole({
|
|
|
228
327
|
uninstallConsoleProxy();
|
|
229
328
|
uninstallXhrProxy();
|
|
230
329
|
};
|
|
231
|
-
}, [enable,
|
|
330
|
+
}, [enable, normalizedExcludeDomains, shouldExcludeIp]);
|
|
232
331
|
useEffect(() => {
|
|
233
332
|
dragPosition.stopAnimation(value => {
|
|
234
333
|
const nextX = clamp(value.x, minX, maxX);
|
|
@@ -251,6 +350,32 @@ export function VConsole({
|
|
|
251
350
|
nativeModule?.getAppInfo?.().then(result => setAppInfo(result)).catch(() => undefined);
|
|
252
351
|
}
|
|
253
352
|
}, [activeTab, appInfo, nativeModule, panelVisible, systemInfo]);
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
|
|
355
|
+
const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
|
|
356
|
+
const showSubscription = Keyboard.addListener(showEvent, event => {
|
|
357
|
+
setKeyboardHeight(event.endCoordinates?.height ?? 0);
|
|
358
|
+
});
|
|
359
|
+
const hideSubscription = Keyboard.addListener(hideEvent, () => {
|
|
360
|
+
setKeyboardHeight(0);
|
|
361
|
+
});
|
|
362
|
+
return () => {
|
|
363
|
+
showSubscription.remove();
|
|
364
|
+
hideSubscription.remove();
|
|
365
|
+
};
|
|
366
|
+
}, []);
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
const timer = setTimeout(() => {
|
|
369
|
+
setDebouncedLogFilter(logFilterInput);
|
|
370
|
+
}, 1000);
|
|
371
|
+
return () => clearTimeout(timer);
|
|
372
|
+
}, [logFilterInput]);
|
|
373
|
+
useEffect(() => {
|
|
374
|
+
const timer = setTimeout(() => {
|
|
375
|
+
setDebouncedNetworkFilter(networkFilterInput);
|
|
376
|
+
}, 1000);
|
|
377
|
+
return () => clearTimeout(timer);
|
|
378
|
+
}, [networkFilterInput]);
|
|
254
379
|
const panResponder = useMemo(() => PanResponder.create({
|
|
255
380
|
onMoveShouldSetPanResponder: () => true,
|
|
256
381
|
onPanResponderGrant: () => {
|
|
@@ -300,13 +425,27 @@ export function VConsole({
|
|
|
300
425
|
}
|
|
301
426
|
});
|
|
302
427
|
};
|
|
428
|
+
const normalizedLogFilter = debouncedLogFilter.trim().toLowerCase();
|
|
429
|
+
const normalizedNetworkFilter = debouncedNetworkFilter.trim().toLowerCase();
|
|
430
|
+
const filteredLogEntries = useMemo(() => {
|
|
431
|
+
if (!normalizedLogFilter) {
|
|
432
|
+
return logEntries;
|
|
433
|
+
}
|
|
434
|
+
return logEntries.filter(item => item.text.toLowerCase().includes(normalizedLogFilter));
|
|
435
|
+
}, [logEntries, normalizedLogFilter]);
|
|
436
|
+
const filteredNetworkEntries = useMemo(() => {
|
|
437
|
+
if (!normalizedNetworkFilter) {
|
|
438
|
+
return networkEntries;
|
|
439
|
+
}
|
|
440
|
+
return networkEntries.filter(item => item.url.toLowerCase().includes(normalizedNetworkFilter));
|
|
441
|
+
}, [networkEntries, normalizedNetworkFilter]);
|
|
303
442
|
const logDataByTab = useMemo(() => ({
|
|
304
|
-
All:
|
|
305
|
-
log:
|
|
306
|
-
info:
|
|
307
|
-
warn:
|
|
308
|
-
error:
|
|
309
|
-
}), [
|
|
443
|
+
All: filteredLogEntries,
|
|
444
|
+
log: filteredLogEntries.filter(item => item.level === 'log'),
|
|
445
|
+
info: filteredLogEntries.filter(item => item.level === 'info'),
|
|
446
|
+
warn: filteredLogEntries.filter(item => item.level === 'warn'),
|
|
447
|
+
error: filteredLogEntries.filter(item => item.level === 'error')
|
|
448
|
+
}), [filteredLogEntries]);
|
|
310
449
|
const onToggleNode = key => {
|
|
311
450
|
setExpandedMap(prev => ({
|
|
312
451
|
...prev,
|
|
@@ -335,6 +474,27 @@ export function VConsole({
|
|
|
335
474
|
animated: true
|
|
336
475
|
});
|
|
337
476
|
};
|
|
477
|
+
const retryNetworkRequest = item => {
|
|
478
|
+
const method = (item.method || 'GET').toUpperCase();
|
|
479
|
+
const url = normalizeRetryUrl(item.url);
|
|
480
|
+
if (!url) {
|
|
481
|
+
console.error('[vConsole] Retry failed: empty request URL');
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const headers = buildRetryHeaders(item.requestHeaders);
|
|
485
|
+
const body = buildRetryBody(item.requestBody, method);
|
|
486
|
+
const hasContentType = Object.keys(headers).some(key => key.toLowerCase() === 'content-type');
|
|
487
|
+
if (body && typeof body === 'string' && typeof item.requestBody === 'object' && item.requestBody !== null && !hasContentType) {
|
|
488
|
+
headers['Content-Type'] = 'application/json';
|
|
489
|
+
}
|
|
490
|
+
fetch(url, {
|
|
491
|
+
method,
|
|
492
|
+
headers,
|
|
493
|
+
body: body
|
|
494
|
+
}).catch(error => {
|
|
495
|
+
console.error('[vConsole] Retry request failed', error);
|
|
496
|
+
});
|
|
497
|
+
};
|
|
338
498
|
const renderRootTab = tab => /*#__PURE__*/_jsx(Pressable, {
|
|
339
499
|
style: [styles.topTabButton, activeTab === tab && styles.topTabButtonActive],
|
|
340
500
|
onPress: () => setActiveTab(tab),
|
|
@@ -365,7 +525,10 @@ export function VConsole({
|
|
|
365
525
|
style: [styles.logLevelText, {
|
|
366
526
|
color: levelTheme.color
|
|
367
527
|
}],
|
|
368
|
-
children: ["[", item.level.toUpperCase(), "]"
|
|
528
|
+
children: ["[", item.level.toUpperCase(), "]", /*#__PURE__*/_jsxs(Text, {
|
|
529
|
+
style: styles.logTimeText,
|
|
530
|
+
children: [' ', formatLogTime(item.timestamp)]
|
|
531
|
+
})]
|
|
369
532
|
}), /*#__PURE__*/_jsx(View, {
|
|
370
533
|
style: styles.logPayload,
|
|
371
534
|
children: item.args.map((arg, index) => /*#__PURE__*/_jsx(ObjectTree, {
|
|
@@ -388,8 +551,14 @@ export function VConsole({
|
|
|
388
551
|
const renderNetworkItem = ({
|
|
389
552
|
item
|
|
390
553
|
}) => {
|
|
554
|
+
const isError = isNetworkErrorEntry(item);
|
|
555
|
+
const backgroundColor = getNetworkItemBackgroundColor(item);
|
|
556
|
+
const startedTime = formatLogTime(item.startedAt);
|
|
557
|
+
const finishedTime = typeof item.finishedAt === 'number' ? formatLogTime(item.finishedAt) : '-';
|
|
391
558
|
return /*#__PURE__*/_jsxs(View, {
|
|
392
|
-
style: styles.listItem,
|
|
559
|
+
style: [styles.listItem, backgroundColor ? {
|
|
560
|
+
backgroundColor
|
|
561
|
+
} : null],
|
|
393
562
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
394
563
|
style: styles.listItemMain,
|
|
395
564
|
children: [/*#__PURE__*/_jsxs(Text, {
|
|
@@ -397,7 +566,10 @@ export function VConsole({
|
|
|
397
566
|
children: [item.method, " ", item.url]
|
|
398
567
|
}), /*#__PURE__*/_jsxs(Text, {
|
|
399
568
|
style: styles.networkLabel,
|
|
400
|
-
children: ["
|
|
569
|
+
children: ["Time: ", startedTime, finishedTime !== '-' ? ` ~ ${finishedTime}` : '', ' ', "Duration:", ' ', typeof item.durationMs === 'number' ? `${item.durationMs}ms` : '-']
|
|
570
|
+
}), /*#__PURE__*/_jsxs(Text, {
|
|
571
|
+
style: styles.networkLabel,
|
|
572
|
+
children: ["Status: ", item.status ?? '-']
|
|
401
573
|
}), /*#__PURE__*/_jsxs(View, {
|
|
402
574
|
style: styles.networkBlock,
|
|
403
575
|
children: [/*#__PURE__*/_jsx(Text, {
|
|
@@ -420,30 +592,41 @@ export function VConsole({
|
|
|
420
592
|
expandedMap: expandedMap,
|
|
421
593
|
onToggle: onToggleNode
|
|
422
594
|
})]
|
|
423
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
595
|
+
}), isError ? /*#__PURE__*/_jsxs(View, {
|
|
424
596
|
style: styles.networkBlock,
|
|
425
597
|
children: [/*#__PURE__*/_jsx(Text, {
|
|
426
|
-
style: styles.networkLabel,
|
|
427
|
-
children: "
|
|
428
|
-
}), /*#__PURE__*/_jsx(
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
expandedMap: expandedMap,
|
|
432
|
-
onToggle: onToggleNode
|
|
598
|
+
style: [styles.networkLabel, styles.networkErrorLabel],
|
|
599
|
+
children: "Error Reason"
|
|
600
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
601
|
+
style: styles.networkErrorText,
|
|
602
|
+
children: item.errorReason ?? 'Network request failed'
|
|
433
603
|
})]
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
nodeKey: `${item.id}.responseData`,
|
|
604
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
605
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
606
|
+
style: styles.networkBlock,
|
|
607
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
608
|
+
style: styles.networkLabel,
|
|
609
|
+
children: "Response Headers"
|
|
610
|
+
}), /*#__PURE__*/_jsx(ObjectTree, {
|
|
611
|
+
value: item.responseHeaders,
|
|
612
|
+
nodeKey: `${item.id}.responseHeaders`,
|
|
444
613
|
expandedMap: expandedMap,
|
|
445
614
|
onToggle: onToggleNode
|
|
446
|
-
})
|
|
615
|
+
})]
|
|
616
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
617
|
+
style: styles.networkBlock,
|
|
618
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
619
|
+
style: styles.networkLabel,
|
|
620
|
+
children: "Response Data"
|
|
621
|
+
}), /*#__PURE__*/_jsx(ScrollView, {
|
|
622
|
+
horizontal: true,
|
|
623
|
+
children: /*#__PURE__*/_jsx(ObjectTree, {
|
|
624
|
+
value: item.responseData ?? '',
|
|
625
|
+
nodeKey: `${item.id}.responseData`,
|
|
626
|
+
expandedMap: expandedMap,
|
|
627
|
+
onToggle: onToggleNode
|
|
628
|
+
})
|
|
629
|
+
})]
|
|
447
630
|
})]
|
|
448
631
|
})]
|
|
449
632
|
}), /*#__PURE__*/_jsx(Pressable, {
|
|
@@ -453,11 +636,18 @@ export function VConsole({
|
|
|
453
636
|
style: styles.copyButtonText,
|
|
454
637
|
children: "Copy"
|
|
455
638
|
})
|
|
639
|
+
}), /*#__PURE__*/_jsx(Pressable, {
|
|
640
|
+
style: styles.retryButton,
|
|
641
|
+
onPress: () => retryNetworkRequest(item),
|
|
642
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
643
|
+
style: styles.retryButtonText,
|
|
644
|
+
children: "Retry"
|
|
645
|
+
})
|
|
456
646
|
})]
|
|
457
647
|
});
|
|
458
648
|
};
|
|
459
|
-
const renderLogPanel =
|
|
460
|
-
style: styles.contentArea,
|
|
649
|
+
const renderLogPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
650
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
461
651
|
children: [/*#__PURE__*/_jsx(View, {
|
|
462
652
|
style: styles.subTabRow,
|
|
463
653
|
children: LOG_SUB_TABS.map(tab => /*#__PURE__*/_jsx(Pressable, {
|
|
@@ -480,6 +670,16 @@ export function VConsole({
|
|
|
480
670
|
ItemSeparatorComponent: ListSeparator
|
|
481
671
|
})
|
|
482
672
|
}, tab))
|
|
673
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
674
|
+
style: styles.filterInputWrap,
|
|
675
|
+
children: /*#__PURE__*/_jsx(TextInput, {
|
|
676
|
+
style: styles.filterInput,
|
|
677
|
+
textAlignVertical: "center",
|
|
678
|
+
value: logFilterInput,
|
|
679
|
+
onChangeText: setLogFilterInput,
|
|
680
|
+
placeholder: "filter...",
|
|
681
|
+
placeholderTextColor: "#999999"
|
|
682
|
+
})
|
|
483
683
|
}), /*#__PURE__*/_jsxs(View, {
|
|
484
684
|
style: styles.actionsRow,
|
|
485
685
|
children: [renderActionButton('Clear', () => {
|
|
@@ -488,14 +688,23 @@ export function VConsole({
|
|
|
488
688
|
}), renderActionButton('Top', scrollLogTop), renderActionButton('Bottom', scrollLogBottom), renderActionButton('Hide', closePanel)]
|
|
489
689
|
})]
|
|
490
690
|
});
|
|
491
|
-
const renderNetworkPanel =
|
|
492
|
-
style: styles.contentArea,
|
|
691
|
+
const renderNetworkPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
692
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
493
693
|
children: [/*#__PURE__*/_jsx(FlatList, {
|
|
494
694
|
ref: networkListRef,
|
|
495
|
-
data:
|
|
695
|
+
data: filteredNetworkEntries,
|
|
496
696
|
keyExtractor: item => `network-${item.id}`,
|
|
497
697
|
renderItem: renderNetworkItem,
|
|
498
698
|
ItemSeparatorComponent: ListSeparator
|
|
699
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
700
|
+
style: styles.filterInputWrap,
|
|
701
|
+
children: /*#__PURE__*/_jsx(TextInput, {
|
|
702
|
+
style: styles.filterInput,
|
|
703
|
+
value: networkFilterInput,
|
|
704
|
+
onChangeText: setNetworkFilterInput,
|
|
705
|
+
placeholder: "filter",
|
|
706
|
+
placeholderTextColor: "#999999"
|
|
707
|
+
})
|
|
499
708
|
}), /*#__PURE__*/_jsxs(View, {
|
|
500
709
|
style: styles.actionsRow,
|
|
501
710
|
children: [renderActionButton('Clear', () => {
|
|
@@ -504,8 +713,8 @@ export function VConsole({
|
|
|
504
713
|
}), renderActionButton('Top', scrollNetworkTop), renderActionButton('Bottom', scrollNetworkBottom), renderActionButton('Hide', closePanel)]
|
|
505
714
|
})]
|
|
506
715
|
});
|
|
507
|
-
const renderSystemPanel =
|
|
508
|
-
style: styles.contentArea,
|
|
716
|
+
const renderSystemPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
717
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
509
718
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
510
719
|
style: styles.infoCard,
|
|
511
720
|
children: [/*#__PURE__*/_jsxs(Text, {
|
|
@@ -535,8 +744,8 @@ export function VConsole({
|
|
|
535
744
|
children: renderActionButton('Hide', closePanel)
|
|
536
745
|
})]
|
|
537
746
|
});
|
|
538
|
-
const renderAppPanel =
|
|
539
|
-
style: styles.contentArea,
|
|
747
|
+
const renderAppPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
748
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
540
749
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
541
750
|
style: styles.infoCard,
|
|
542
751
|
children: [/*#__PURE__*/_jsxs(Text, {
|
|
@@ -578,6 +787,7 @@ export function VConsole({
|
|
|
578
787
|
}), /*#__PURE__*/_jsxs(Animated.View, {
|
|
579
788
|
style: [styles.panel, {
|
|
580
789
|
height: panelHeight,
|
|
790
|
+
marginBottom: keyboardHeight,
|
|
581
791
|
transform: [{
|
|
582
792
|
translateY: panelTranslateY
|
|
583
793
|
}]
|
|
@@ -585,7 +795,7 @@ export function VConsole({
|
|
|
585
795
|
children: [/*#__PURE__*/_jsx(View, {
|
|
586
796
|
style: styles.topTabRow,
|
|
587
797
|
children: ROOT_TABS.map(renderRootTab)
|
|
588
|
-
}), activeTab === 'Log'
|
|
798
|
+
}), renderLogPanel(activeTab === 'Log'), renderNetworkPanel(activeTab === 'Network'), renderSystemPanel(activeTab === 'System'), renderAppPanel(activeTab === 'App')]
|
|
589
799
|
})]
|
|
590
800
|
}) : null]
|
|
591
801
|
});
|
|
@@ -701,6 +911,11 @@ const styles = StyleSheet.create({
|
|
|
701
911
|
fontWeight: '700',
|
|
702
912
|
marginBottom: 4
|
|
703
913
|
},
|
|
914
|
+
logTimeText: {
|
|
915
|
+
fontSize: 11,
|
|
916
|
+
fontWeight: '400',
|
|
917
|
+
color: '#888888'
|
|
918
|
+
},
|
|
704
919
|
logPayload: {
|
|
705
920
|
flex: 1
|
|
706
921
|
},
|
|
@@ -718,6 +933,20 @@ const styles = StyleSheet.create({
|
|
|
718
933
|
fontSize: 11,
|
|
719
934
|
color: '#333333'
|
|
720
935
|
},
|
|
936
|
+
retryButton: {
|
|
937
|
+
position: 'absolute',
|
|
938
|
+
right: 8,
|
|
939
|
+
top: 40,
|
|
940
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
941
|
+
borderColor: '#D0D0D0',
|
|
942
|
+
borderRadius: 6,
|
|
943
|
+
paddingVertical: 4,
|
|
944
|
+
paddingHorizontal: 8
|
|
945
|
+
},
|
|
946
|
+
retryButtonText: {
|
|
947
|
+
fontSize: 11,
|
|
948
|
+
color: '#333333'
|
|
949
|
+
},
|
|
721
950
|
valuePrimitive: {
|
|
722
951
|
color: '#222222',
|
|
723
952
|
fontSize: 12,
|
|
@@ -780,6 +1009,32 @@ const styles = StyleSheet.create({
|
|
|
780
1009
|
color: '#444444',
|
|
781
1010
|
marginBottom: 2
|
|
782
1011
|
},
|
|
1012
|
+
networkErrorLabel: {
|
|
1013
|
+
color: LOG_THEME.error.color,
|
|
1014
|
+
fontWeight: '600'
|
|
1015
|
+
},
|
|
1016
|
+
networkErrorText: {
|
|
1017
|
+
color: LOG_THEME.error.color,
|
|
1018
|
+
fontSize: 12
|
|
1019
|
+
},
|
|
1020
|
+
filterInputWrap: {
|
|
1021
|
+
borderTopWidth: StyleSheet.hairlineWidth,
|
|
1022
|
+
borderTopColor: '#E1E1E1',
|
|
1023
|
+
paddingHorizontal: 8,
|
|
1024
|
+
paddingTop: 8,
|
|
1025
|
+
paddingBottom: 6
|
|
1026
|
+
},
|
|
1027
|
+
filterInput: {
|
|
1028
|
+
height: 34,
|
|
1029
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
1030
|
+
borderColor: '#D0D0D0',
|
|
1031
|
+
borderRadius: 8,
|
|
1032
|
+
paddingHorizontal: 10,
|
|
1033
|
+
fontSize: 12,
|
|
1034
|
+
color: '#222222',
|
|
1035
|
+
backgroundColor: '#FFFFFF',
|
|
1036
|
+
paddingVertical: 0
|
|
1037
|
+
},
|
|
783
1038
|
actionsRow: {
|
|
784
1039
|
borderTopWidth: StyleSheet.hairlineWidth,
|
|
785
1040
|
borderTopColor: '#E1E1E1',
|