react-native-vconsole 0.3.0 → 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 +17 -2
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/vconsole/VconsoleModule.kt +36 -23
- package/ios/Vconsole.mm +0 -12
- package/lib/module/VConsole.js +333 -60
- package/lib/module/VConsole.js.map +1 -1
- package/lib/module/core/xhrProxy.js +146 -8
- package/lib/module/core/xhrProxy.js.map +1 -1
- package/lib/module/index.js +0 -3
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/VConsole.d.ts +7 -2
- package/lib/typescript/src/VConsole.d.ts.map +1 -1
- package/lib/typescript/src/core/xhrProxy.d.ts +2 -1
- package/lib/typescript/src/core/xhrProxy.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +0 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +3 -1
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/VConsole.tsx +410 -67
- package/src/core/xhrProxy.ts +179 -10
- package/src/index.tsx +0 -4
- package/src/types.ts +3 -1
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, 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 = {
|
|
@@ -45,6 +45,33 @@ function getDisplayValue(value) {
|
|
|
45
45
|
function copyToClipboard(value) {
|
|
46
46
|
Clipboard.setString(value);
|
|
47
47
|
}
|
|
48
|
+
function copyToClipboardWithFeedback(value) {
|
|
49
|
+
copyToClipboard(value);
|
|
50
|
+
if (Platform.OS === 'android') {
|
|
51
|
+
ToastAndroid.show('Copied', ToastAndroid.SHORT);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function formatMemorySize(bytes) {
|
|
55
|
+
if (typeof bytes !== 'number' || !Number.isFinite(bytes) || bytes < 0) {
|
|
56
|
+
return '-';
|
|
57
|
+
}
|
|
58
|
+
const mb = bytes / (1024 * 1024);
|
|
59
|
+
if (mb >= 1024) {
|
|
60
|
+
return `${(mb / 1024).toFixed(2)} GB`;
|
|
61
|
+
}
|
|
62
|
+
return `${mb.toFixed(2)} MB`;
|
|
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
|
+
}
|
|
48
75
|
function prettyText(value) {
|
|
49
76
|
if (value === undefined) {
|
|
50
77
|
return '';
|
|
@@ -58,10 +85,74 @@ function prettyText(value) {
|
|
|
58
85
|
return String(value);
|
|
59
86
|
}
|
|
60
87
|
}
|
|
88
|
+
function isNetworkErrorEntry(item) {
|
|
89
|
+
return item.isError === true;
|
|
90
|
+
}
|
|
61
91
|
function buildNetworkCopyText(item) {
|
|
62
92
|
const status = item.status ?? '-';
|
|
63
93
|
const duration = typeof item.durationMs === 'number' ? `${item.durationMs}ms` : '-';
|
|
64
|
-
|
|
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
|
+
}
|
|
65
156
|
}
|
|
66
157
|
function ObjectTree({
|
|
67
158
|
value,
|
|
@@ -77,10 +168,24 @@ function ObjectTree({
|
|
|
77
168
|
}
|
|
78
169
|
const valueType = typeof value;
|
|
79
170
|
if (valueType !== 'object') {
|
|
171
|
+
const displayValue = getDisplayValue(value);
|
|
172
|
+
if (Platform.OS === 'android') {
|
|
173
|
+
return /*#__PURE__*/_jsx(Pressable, {
|
|
174
|
+
onLongPress: () => copyToClipboardWithFeedback(displayValue),
|
|
175
|
+
delayLongPress: 250,
|
|
176
|
+
android_ripple: {
|
|
177
|
+
color: '#D0D0D0'
|
|
178
|
+
},
|
|
179
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
180
|
+
style: styles.valuePrimitive,
|
|
181
|
+
children: displayValue
|
|
182
|
+
})
|
|
183
|
+
});
|
|
184
|
+
}
|
|
80
185
|
return /*#__PURE__*/_jsx(Text, {
|
|
81
186
|
style: styles.valuePrimitive,
|
|
82
187
|
selectable: true,
|
|
83
|
-
children:
|
|
188
|
+
children: displayValue
|
|
84
189
|
});
|
|
85
190
|
}
|
|
86
191
|
const isArray = Array.isArray(value);
|
|
@@ -136,7 +241,7 @@ function useFlatListRefs() {
|
|
|
136
241
|
}
|
|
137
242
|
export function VConsole({
|
|
138
243
|
enable = true,
|
|
139
|
-
|
|
244
|
+
exclude = EMPTY_EXCLUDE
|
|
140
245
|
}) {
|
|
141
246
|
const nativeModule = NativeModules.Vconsole;
|
|
142
247
|
const {
|
|
@@ -171,6 +276,11 @@ export function VConsole({
|
|
|
171
276
|
const [logSubTab, setLogSubTab] = useState('All');
|
|
172
277
|
const [logEntries, setLogEntries] = useState([]);
|
|
173
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);
|
|
174
284
|
const [expandedMap, setExpandedMap] = useState({});
|
|
175
285
|
const [systemInfo, setSystemInfo] = useState(null);
|
|
176
286
|
const [appInfo, setAppInfo] = useState(null);
|
|
@@ -178,7 +288,8 @@ export function VConsole({
|
|
|
178
288
|
const panelTranslateY = useRef(new Animated.Value(panelHeight)).current;
|
|
179
289
|
const logListRefs = useFlatListRefs();
|
|
180
290
|
const networkListRef = useRef(null);
|
|
181
|
-
const
|
|
291
|
+
const normalizedExcludeDomains = useMemo(() => (exclude.domains ?? []).map(item => item.trim().toLowerCase()).filter(Boolean), [exclude.domains]);
|
|
292
|
+
const shouldExcludeIp = exclude.ip === true;
|
|
182
293
|
useEffect(() => {
|
|
183
294
|
if (!enable) {
|
|
184
295
|
setPanelVisible(false);
|
|
@@ -186,7 +297,8 @@ export function VConsole({
|
|
|
186
297
|
}
|
|
187
298
|
installConsoleProxy();
|
|
188
299
|
installXhrProxy({
|
|
189
|
-
|
|
300
|
+
excludeHosts: normalizedExcludeDomains,
|
|
301
|
+
excludeIp: shouldExcludeIp
|
|
190
302
|
});
|
|
191
303
|
const unsubscribeLog = subscribeLogEntries(setLogEntries);
|
|
192
304
|
const unsubscribeNetwork = subscribeNetworkEntries(setNetworkEntries);
|
|
@@ -198,7 +310,7 @@ export function VConsole({
|
|
|
198
310
|
uninstallConsoleProxy();
|
|
199
311
|
uninstallXhrProxy();
|
|
200
312
|
};
|
|
201
|
-
}, [enable,
|
|
313
|
+
}, [enable, normalizedExcludeDomains, shouldExcludeIp]);
|
|
202
314
|
useEffect(() => {
|
|
203
315
|
dragPosition.stopAnimation(value => {
|
|
204
316
|
const nextX = clamp(value.x, minX, maxX);
|
|
@@ -221,6 +333,32 @@ export function VConsole({
|
|
|
221
333
|
nativeModule?.getAppInfo?.().then(result => setAppInfo(result)).catch(() => undefined);
|
|
222
334
|
}
|
|
223
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]);
|
|
224
362
|
const panResponder = useMemo(() => PanResponder.create({
|
|
225
363
|
onMoveShouldSetPanResponder: () => true,
|
|
226
364
|
onPanResponderGrant: () => {
|
|
@@ -270,13 +408,27 @@ export function VConsole({
|
|
|
270
408
|
}
|
|
271
409
|
});
|
|
272
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]);
|
|
273
425
|
const logDataByTab = useMemo(() => ({
|
|
274
|
-
All:
|
|
275
|
-
log:
|
|
276
|
-
info:
|
|
277
|
-
warn:
|
|
278
|
-
error:
|
|
279
|
-
}), [
|
|
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]);
|
|
280
432
|
const onToggleNode = key => {
|
|
281
433
|
setExpandedMap(prev => ({
|
|
282
434
|
...prev,
|
|
@@ -305,6 +457,27 @@ export function VConsole({
|
|
|
305
457
|
animated: true
|
|
306
458
|
});
|
|
307
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
|
+
};
|
|
308
481
|
const renderRootTab = tab => /*#__PURE__*/_jsx(Pressable, {
|
|
309
482
|
style: [styles.topTabButton, activeTab === tab && styles.topTabButtonActive],
|
|
310
483
|
onPress: () => setActiveTab(tab),
|
|
@@ -335,7 +508,10 @@ export function VConsole({
|
|
|
335
508
|
style: [styles.logLevelText, {
|
|
336
509
|
color: levelTheme.color
|
|
337
510
|
}],
|
|
338
|
-
children: ["[", item.level.toUpperCase(), "]"
|
|
511
|
+
children: ["[", item.level.toUpperCase(), "]", /*#__PURE__*/_jsxs(Text, {
|
|
512
|
+
style: styles.logTimeText,
|
|
513
|
+
children: [' ', formatLogTime(item.timestamp)]
|
|
514
|
+
})]
|
|
339
515
|
}), /*#__PURE__*/_jsx(View, {
|
|
340
516
|
style: styles.logPayload,
|
|
341
517
|
children: item.args.map((arg, index) => /*#__PURE__*/_jsx(ObjectTree, {
|
|
@@ -347,10 +523,10 @@ export function VConsole({
|
|
|
347
523
|
})]
|
|
348
524
|
}), /*#__PURE__*/_jsx(Pressable, {
|
|
349
525
|
style: styles.copyButton,
|
|
350
|
-
onPress: () =>
|
|
526
|
+
onPress: () => copyToClipboardWithFeedback(item.text),
|
|
351
527
|
children: /*#__PURE__*/_jsx(Text, {
|
|
352
528
|
style: styles.copyButtonText,
|
|
353
|
-
children: "
|
|
529
|
+
children: "Copy"
|
|
354
530
|
})
|
|
355
531
|
})]
|
|
356
532
|
});
|
|
@@ -358,8 +534,13 @@ export function VConsole({
|
|
|
358
534
|
const renderNetworkItem = ({
|
|
359
535
|
item
|
|
360
536
|
}) => {
|
|
537
|
+
const isError = isNetworkErrorEntry(item);
|
|
538
|
+
const startedTime = formatLogTime(item.startedAt);
|
|
539
|
+
const finishedTime = typeof item.finishedAt === 'number' ? formatLogTime(item.finishedAt) : '-';
|
|
361
540
|
return /*#__PURE__*/_jsxs(View, {
|
|
362
|
-
style: styles.listItem,
|
|
541
|
+
style: [styles.listItem, isError ? {
|
|
542
|
+
backgroundColor: LOG_THEME.error.backgroundColor
|
|
543
|
+
} : null],
|
|
363
544
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
364
545
|
style: styles.listItemMain,
|
|
365
546
|
children: [/*#__PURE__*/_jsxs(Text, {
|
|
@@ -367,7 +548,10 @@ export function VConsole({
|
|
|
367
548
|
children: [item.method, " ", item.url]
|
|
368
549
|
}), /*#__PURE__*/_jsxs(Text, {
|
|
369
550
|
style: styles.networkLabel,
|
|
370
|
-
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 ?? '-']
|
|
371
555
|
}), /*#__PURE__*/_jsxs(View, {
|
|
372
556
|
style: styles.networkBlock,
|
|
373
557
|
children: [/*#__PURE__*/_jsx(Text, {
|
|
@@ -390,44 +574,62 @@ export function VConsole({
|
|
|
390
574
|
expandedMap: expandedMap,
|
|
391
575
|
onToggle: onToggleNode
|
|
392
576
|
})]
|
|
393
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
577
|
+
}), isError ? /*#__PURE__*/_jsxs(View, {
|
|
394
578
|
style: styles.networkBlock,
|
|
395
579
|
children: [/*#__PURE__*/_jsx(Text, {
|
|
396
|
-
style: styles.networkLabel,
|
|
397
|
-
children: "
|
|
398
|
-
}), /*#__PURE__*/_jsx(
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
expandedMap: expandedMap,
|
|
402
|
-
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'
|
|
403
585
|
})]
|
|
404
|
-
})
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
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`,
|
|
414
595
|
expandedMap: expandedMap,
|
|
415
596
|
onToggle: onToggleNode
|
|
416
|
-
})
|
|
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
|
+
})]
|
|
417
612
|
})]
|
|
418
613
|
})]
|
|
419
614
|
}), /*#__PURE__*/_jsx(Pressable, {
|
|
420
615
|
style: styles.copyButton,
|
|
421
|
-
onPress: () =>
|
|
616
|
+
onPress: () => copyToClipboardWithFeedback(buildNetworkCopyText(item)),
|
|
422
617
|
children: /*#__PURE__*/_jsx(Text, {
|
|
423
618
|
style: styles.copyButtonText,
|
|
424
|
-
children: "
|
|
619
|
+
children: "Copy"
|
|
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"
|
|
425
627
|
})
|
|
426
628
|
})]
|
|
427
629
|
});
|
|
428
630
|
};
|
|
429
|
-
const renderLogPanel =
|
|
430
|
-
style: styles.contentArea,
|
|
631
|
+
const renderLogPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
632
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
431
633
|
children: [/*#__PURE__*/_jsx(View, {
|
|
432
634
|
style: styles.subTabRow,
|
|
433
635
|
children: LOG_SUB_TABS.map(tab => /*#__PURE__*/_jsx(Pressable, {
|
|
@@ -450,6 +652,16 @@ export function VConsole({
|
|
|
450
652
|
ItemSeparatorComponent: ListSeparator
|
|
451
653
|
})
|
|
452
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
|
+
})
|
|
453
665
|
}), /*#__PURE__*/_jsxs(View, {
|
|
454
666
|
style: styles.actionsRow,
|
|
455
667
|
children: [renderActionButton('Clear', () => {
|
|
@@ -458,14 +670,23 @@ export function VConsole({
|
|
|
458
670
|
}), renderActionButton('Top', scrollLogTop), renderActionButton('Bottom', scrollLogBottom), renderActionButton('Hide', closePanel)]
|
|
459
671
|
})]
|
|
460
672
|
});
|
|
461
|
-
const renderNetworkPanel =
|
|
462
|
-
style: styles.contentArea,
|
|
673
|
+
const renderNetworkPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
674
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
463
675
|
children: [/*#__PURE__*/_jsx(FlatList, {
|
|
464
676
|
ref: networkListRef,
|
|
465
|
-
data:
|
|
677
|
+
data: filteredNetworkEntries,
|
|
466
678
|
keyExtractor: item => `network-${item.id}`,
|
|
467
679
|
renderItem: renderNetworkItem,
|
|
468
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
|
+
})
|
|
469
690
|
}), /*#__PURE__*/_jsxs(View, {
|
|
470
691
|
style: styles.actionsRow,
|
|
471
692
|
children: [renderActionButton('Clear', () => {
|
|
@@ -474,39 +695,39 @@ export function VConsole({
|
|
|
474
695
|
}), renderActionButton('Top', scrollNetworkTop), renderActionButton('Bottom', scrollNetworkBottom), renderActionButton('Hide', closePanel)]
|
|
475
696
|
})]
|
|
476
697
|
});
|
|
477
|
-
const renderSystemPanel =
|
|
478
|
-
style: styles.contentArea,
|
|
698
|
+
const renderSystemPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
699
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
479
700
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
480
701
|
style: styles.infoCard,
|
|
481
702
|
children: [/*#__PURE__*/_jsxs(Text, {
|
|
482
703
|
style: styles.infoText,
|
|
483
|
-
children: ["
|
|
704
|
+
children: ["Brand: ", systemInfo?.manufacturer ?? '-']
|
|
484
705
|
}), /*#__PURE__*/_jsxs(Text, {
|
|
485
706
|
style: styles.infoText,
|
|
486
|
-
children: ["
|
|
707
|
+
children: ["Model: ", systemInfo?.model ?? '-']
|
|
487
708
|
}), /*#__PURE__*/_jsxs(Text, {
|
|
488
709
|
style: styles.infoText,
|
|
489
|
-
children: ["
|
|
710
|
+
children: ["System Version: ", Platform.OS === 'android' ? 'Android' : 'iOS', ' ', systemInfo?.osVersion ?? '-']
|
|
490
711
|
}), Platform.OS === 'android' ? /*#__PURE__*/_jsxs(Text, {
|
|
491
712
|
style: styles.infoText,
|
|
492
|
-
children: ["
|
|
713
|
+
children: ["Network Type: ", systemInfo?.networkType ?? '-']
|
|
493
714
|
}) : null, Platform.OS === 'android' ? /*#__PURE__*/_jsxs(Text, {
|
|
494
715
|
style: styles.infoText,
|
|
495
|
-
children: ["
|
|
716
|
+
children: ["Network Reachable: ", systemInfo?.isNetworkReachable ?? 'unknown']
|
|
496
717
|
}) : null, /*#__PURE__*/_jsxs(Text, {
|
|
497
718
|
style: styles.infoText,
|
|
498
|
-
children: ["
|
|
719
|
+
children: ["Total Memory: ", formatMemorySize(systemInfo?.totalMemory)]
|
|
499
720
|
}), Platform.OS === 'android' ? /*#__PURE__*/_jsxs(Text, {
|
|
500
721
|
style: styles.infoText,
|
|
501
|
-
children: ["
|
|
722
|
+
children: ["Available Memory: ", formatMemorySize(systemInfo?.availableMemory)]
|
|
502
723
|
}) : null]
|
|
503
724
|
}), /*#__PURE__*/_jsx(View, {
|
|
504
725
|
style: styles.actionsRow,
|
|
505
726
|
children: renderActionButton('Hide', closePanel)
|
|
506
727
|
})]
|
|
507
728
|
});
|
|
508
|
-
const renderAppPanel =
|
|
509
|
-
style: styles.contentArea,
|
|
729
|
+
const renderAppPanel = visible => /*#__PURE__*/_jsxs(View, {
|
|
730
|
+
style: [styles.contentArea, visible ? {} : styles.hidden],
|
|
510
731
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
511
732
|
style: styles.infoCard,
|
|
512
733
|
children: [/*#__PURE__*/_jsxs(Text, {
|
|
@@ -548,6 +769,7 @@ export function VConsole({
|
|
|
548
769
|
}), /*#__PURE__*/_jsxs(Animated.View, {
|
|
549
770
|
style: [styles.panel, {
|
|
550
771
|
height: panelHeight,
|
|
772
|
+
marginBottom: keyboardHeight,
|
|
551
773
|
transform: [{
|
|
552
774
|
translateY: panelTranslateY
|
|
553
775
|
}]
|
|
@@ -555,7 +777,7 @@ export function VConsole({
|
|
|
555
777
|
children: [/*#__PURE__*/_jsx(View, {
|
|
556
778
|
style: styles.topTabRow,
|
|
557
779
|
children: ROOT_TABS.map(renderRootTab)
|
|
558
|
-
}), activeTab === 'Log'
|
|
780
|
+
}), renderLogPanel(activeTab === 'Log'), renderNetworkPanel(activeTab === 'Network'), renderSystemPanel(activeTab === 'System'), renderAppPanel(activeTab === 'App')]
|
|
559
781
|
})]
|
|
560
782
|
}) : null]
|
|
561
783
|
});
|
|
@@ -568,7 +790,7 @@ const styles = StyleSheet.create({
|
|
|
568
790
|
floatingButton: {
|
|
569
791
|
width: BUTTON_WIDTH,
|
|
570
792
|
height: BUTTON_HEIGHT,
|
|
571
|
-
borderRadius:
|
|
793
|
+
borderRadius: 8,
|
|
572
794
|
backgroundColor: '#22A455',
|
|
573
795
|
justifyContent: 'center',
|
|
574
796
|
alignItems: 'center'
|
|
@@ -618,7 +840,7 @@ const styles = StyleSheet.create({
|
|
|
618
840
|
},
|
|
619
841
|
contentArea: {
|
|
620
842
|
flex: 1,
|
|
621
|
-
paddingBottom: 16
|
|
843
|
+
paddingBottom: Platform.OS === 'android' ? 42 : 16
|
|
622
844
|
},
|
|
623
845
|
subTabRow: {
|
|
624
846
|
flexDirection: 'row',
|
|
@@ -671,6 +893,11 @@ const styles = StyleSheet.create({
|
|
|
671
893
|
fontWeight: '700',
|
|
672
894
|
marginBottom: 4
|
|
673
895
|
},
|
|
896
|
+
logTimeText: {
|
|
897
|
+
fontSize: 11,
|
|
898
|
+
fontWeight: '400',
|
|
899
|
+
color: '#888888'
|
|
900
|
+
},
|
|
674
901
|
logPayload: {
|
|
675
902
|
flex: 1
|
|
676
903
|
},
|
|
@@ -688,11 +915,31 @@ const styles = StyleSheet.create({
|
|
|
688
915
|
fontSize: 11,
|
|
689
916
|
color: '#333333'
|
|
690
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
|
+
},
|
|
691
932
|
valuePrimitive: {
|
|
692
933
|
color: '#222222',
|
|
693
934
|
fontSize: 12,
|
|
694
935
|
flexShrink: 1
|
|
695
936
|
},
|
|
937
|
+
valuePrimitiveInput: {
|
|
938
|
+
paddingVertical: 0,
|
|
939
|
+
paddingHorizontal: 0,
|
|
940
|
+
margin: 0,
|
|
941
|
+
textAlignVertical: 'top'
|
|
942
|
+
},
|
|
696
943
|
treeNode: {
|
|
697
944
|
flexDirection: 'column',
|
|
698
945
|
marginBottom: 4
|
|
@@ -744,6 +991,32 @@ const styles = StyleSheet.create({
|
|
|
744
991
|
color: '#444444',
|
|
745
992
|
marginBottom: 2
|
|
746
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
|
+
},
|
|
747
1020
|
actionsRow: {
|
|
748
1021
|
borderTopWidth: StyleSheet.hairlineWidth,
|
|
749
1022
|
borderTopColor: '#E1E1E1',
|