react-native-debug-toolkit 0.1.1
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 +108 -0
- package/android/src/main/java/com/debugtoolkit/BuildTypeModule.java +68 -0
- package/android/src/main/java/com/debugtoolkit/BuildTypePackage.java +24 -0
- package/index.d.ts +155 -0
- package/index.js +10 -0
- package/ios/BuildTypeModule.h +4 -0
- package/ios/BuildTypeModule.m +71 -0
- package/lib/DebugToolKit.js +83 -0
- package/lib/EnvironmentManager.ts +80 -0
- package/lib/features/NetworkFeature.js +330 -0
- package/lib/index.js +6 -0
- package/lib/utils/DebugConst.js +22 -0
- package/lib/views/FloatPanelView.js +491 -0
- package/lib/views/HttpLogDetails.js +666 -0
- package/lib/views/RestartModal.js +75 -0
- package/lib/views/SubViewEnvironment.js +73 -0
- package/lib/views/SubViewHTTPLogs.js +267 -0
- package/lib/views/TabView.js +66 -0
- package/package.json +39 -0
- package/react-native-debug-toolkit-0.1.1.tgz +0 -0
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react'
|
|
2
|
+
import { View, Text, StyleSheet, Clipboard, Dimensions } from 'react-native'
|
|
3
|
+
import { ScrollView, Pressable } from 'react-native-gesture-handler'
|
|
4
|
+
|
|
5
|
+
const { width: SCREEN_WIDTH } = Dimensions.get('window')
|
|
6
|
+
|
|
7
|
+
const CopyButton = ({ text, style }) => {
|
|
8
|
+
const [copied, setCopied] = useState(false)
|
|
9
|
+
|
|
10
|
+
const handleCopy = async () => {
|
|
11
|
+
await Clipboard.setString(text)
|
|
12
|
+
setCopied(true)
|
|
13
|
+
setTimeout(() => setCopied(false), 2000)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Pressable style={[styles.copyButton, style]} onPress={handleCopy}>
|
|
18
|
+
<Text style={styles.copyButtonText}>{copied ? 'Copied!' : 'Copy'}</Text>
|
|
19
|
+
</Pressable>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const CollapsibleSection = ({ title, children, initiallyExpanded = false }) => {
|
|
24
|
+
const [expanded, setExpanded] = useState(initiallyExpanded)
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<View style={styles.collapsibleSection}>
|
|
28
|
+
<Pressable
|
|
29
|
+
style={styles.sectionHeader}
|
|
30
|
+
onPress={() => setExpanded(!expanded)}>
|
|
31
|
+
<Text style={styles.sectionTitle}>{title}</Text>
|
|
32
|
+
<Text style={styles.expandIcon}>{expanded ? '▼' : '▶'}</Text>
|
|
33
|
+
</Pressable>
|
|
34
|
+
{expanded && children}
|
|
35
|
+
</View>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const LongTextContent = ({ text }) => {
|
|
40
|
+
return (
|
|
41
|
+
<View style={styles.longTextContainer}>
|
|
42
|
+
<Text style={styles.jsonString} selectable={true}>
|
|
43
|
+
{text}
|
|
44
|
+
</Text>
|
|
45
|
+
</View>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const JSONValue = ({ value, path = '', level = 0, maxExpandLevel = 2 }) => {
|
|
50
|
+
const [expanded, setExpanded] = useState(level < maxExpandLevel)
|
|
51
|
+
|
|
52
|
+
if (value === null) {
|
|
53
|
+
return <Text style={styles.jsonNull}>null</Text>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (value === undefined) {
|
|
57
|
+
return <Text style={styles.jsonNull}>undefined</Text>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (typeof value === 'boolean') {
|
|
61
|
+
return <Text style={styles.jsonBoolean}>{value.toString()}</Text>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (typeof value === 'number') {
|
|
65
|
+
return <Text style={styles.jsonNumber}>{value}</Text>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof value === 'string') {
|
|
69
|
+
if (value.length > 150) {
|
|
70
|
+
return (
|
|
71
|
+
<CollapsibleSection
|
|
72
|
+
title={`String (${value.length} chars)`}
|
|
73
|
+
initiallyExpanded={false}>
|
|
74
|
+
<LongTextContent text={value} />
|
|
75
|
+
</CollapsibleSection>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Text style={styles.jsonString} selectable={true}>
|
|
81
|
+
{value}
|
|
82
|
+
</Text>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (Array.isArray(value)) {
|
|
87
|
+
if (value.length === 0) {
|
|
88
|
+
return <Text style={styles.jsonArray}>[]</Text>
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<View style={styles.jsonContainer}>
|
|
93
|
+
<Pressable
|
|
94
|
+
onPress={() => setExpanded(!expanded)}
|
|
95
|
+
style={styles.jsonToggle}>
|
|
96
|
+
<Text style={styles.jsonBrackets}>
|
|
97
|
+
[{!expanded && '...'}
|
|
98
|
+
{expanded && value.length > 0 && ''}
|
|
99
|
+
</Text>
|
|
100
|
+
{!expanded && (
|
|
101
|
+
<Text style={styles.jsonCollapsed}> Array({value.length}) </Text>
|
|
102
|
+
)}
|
|
103
|
+
</Pressable>
|
|
104
|
+
|
|
105
|
+
{expanded && (
|
|
106
|
+
<View style={styles.jsonChildren}>
|
|
107
|
+
{value.map((item, index) => (
|
|
108
|
+
<View key={`${path}-${index}`} style={styles.jsonArrayItem}>
|
|
109
|
+
<Text style={styles.jsonKey}>{index}: </Text>
|
|
110
|
+
<View style={styles.jsonValue}>
|
|
111
|
+
<JSONValue
|
|
112
|
+
value={item}
|
|
113
|
+
path={`${path}[${index}]`}
|
|
114
|
+
level={level + 1}
|
|
115
|
+
/>
|
|
116
|
+
</View>
|
|
117
|
+
</View>
|
|
118
|
+
))}
|
|
119
|
+
</View>
|
|
120
|
+
)}
|
|
121
|
+
|
|
122
|
+
{expanded && <Text style={styles.jsonBrackets}>]</Text>}
|
|
123
|
+
</View>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (typeof value === 'object') {
|
|
128
|
+
const keys = Object.keys(value)
|
|
129
|
+
|
|
130
|
+
if (keys.length === 0) {
|
|
131
|
+
return <Text style={styles.jsonObject}>{'{}'}</Text>
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<View style={styles.jsonContainer}>
|
|
136
|
+
<Pressable
|
|
137
|
+
onPress={() => setExpanded(!expanded)}
|
|
138
|
+
style={styles.jsonToggle}>
|
|
139
|
+
<Text style={styles.jsonBrackets}>
|
|
140
|
+
{'{'}
|
|
141
|
+
{!expanded && '...'}
|
|
142
|
+
{expanded && keys.length > 0 && ''}
|
|
143
|
+
</Text>
|
|
144
|
+
{!expanded && (
|
|
145
|
+
<Text style={styles.jsonCollapsed}> Object({keys.length}) </Text>
|
|
146
|
+
)}
|
|
147
|
+
</Pressable>
|
|
148
|
+
|
|
149
|
+
{expanded && (
|
|
150
|
+
<View style={styles.jsonChildren}>
|
|
151
|
+
{keys.map((key) => (
|
|
152
|
+
<View key={`${path}-${key}`} style={styles.jsonProperty}>
|
|
153
|
+
<Text style={styles.jsonKey}>{key}: </Text>
|
|
154
|
+
<View style={styles.jsonValue}>
|
|
155
|
+
<JSONValue
|
|
156
|
+
value={value[key]}
|
|
157
|
+
path={`${path}.${key}`}
|
|
158
|
+
level={level + 1}
|
|
159
|
+
/>
|
|
160
|
+
</View>
|
|
161
|
+
</View>
|
|
162
|
+
))}
|
|
163
|
+
</View>
|
|
164
|
+
)}
|
|
165
|
+
|
|
166
|
+
{expanded && <Text style={styles.jsonBrackets}>{'}'}</Text>}
|
|
167
|
+
</View>
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return <Text>{String(value)}</Text>
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const ApiStatus = ({ status, success }) => {
|
|
175
|
+
let statusColor = '#666'
|
|
176
|
+
let statusText = ''
|
|
177
|
+
|
|
178
|
+
if (typeof status === 'number') {
|
|
179
|
+
statusText = status.toString()
|
|
180
|
+
|
|
181
|
+
if (status >= 200 && status < 300) {
|
|
182
|
+
statusColor = '#00C851'
|
|
183
|
+
} else if (status >= 400) {
|
|
184
|
+
statusColor = '#ff4444'
|
|
185
|
+
}
|
|
186
|
+
} else if (success === false) {
|
|
187
|
+
statusColor = '#ff4444'
|
|
188
|
+
statusText = 'Error'
|
|
189
|
+
} else if (success === true) {
|
|
190
|
+
statusColor = '#00C851'
|
|
191
|
+
statusText = 'Success'
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<Text style={[styles.statusPill, { backgroundColor: statusColor }]}>
|
|
196
|
+
{statusText}
|
|
197
|
+
</Text>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const HttpLogDetails = ({ log }) => {
|
|
202
|
+
const formatDataSize = (data) => {
|
|
203
|
+
if (!data) {
|
|
204
|
+
return '(empty)'
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
const stringData = typeof data === 'string' ? data : JSON.stringify(data)
|
|
209
|
+
// Use string length as an approximation instead of TextEncoder
|
|
210
|
+
const bytes = stringData.length
|
|
211
|
+
|
|
212
|
+
if (bytes < 1024) {
|
|
213
|
+
return `(${bytes} B)`
|
|
214
|
+
} else if (bytes < 1024 * 1024) {
|
|
215
|
+
return `(${(bytes / 1024).toFixed(1)} KB)`
|
|
216
|
+
} else {
|
|
217
|
+
return `(${(bytes / (1024 * 1024)).toFixed(1)} MB)`
|
|
218
|
+
}
|
|
219
|
+
} catch (e) {
|
|
220
|
+
return '(size unknown)'
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const generateCurl = useCallback(() => {
|
|
225
|
+
if (!log.request) {
|
|
226
|
+
return 'curl command unavailable'
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
let curl = `curl -X ${log.request.method || 'GET'} '${log.request.url}'`
|
|
230
|
+
|
|
231
|
+
// Add headers
|
|
232
|
+
if (log.request.headers && Object.keys(log.request.headers).length > 0) {
|
|
233
|
+
Object.entries(log.request.headers).forEach(([key, value]) => {
|
|
234
|
+
if (typeof value === 'string') {
|
|
235
|
+
curl += ` \\\n -H '${key}: ${value}'`
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Add body
|
|
241
|
+
if (log.request.body) {
|
|
242
|
+
try {
|
|
243
|
+
const bodyStr =
|
|
244
|
+
typeof log.request.body === 'string'
|
|
245
|
+
? log.request.body
|
|
246
|
+
: JSON.stringify(log.request.body)
|
|
247
|
+
|
|
248
|
+
curl += ` \\\n -d '${bodyStr.replace(/'/g, "'\\''")}'`
|
|
249
|
+
} catch (e) {
|
|
250
|
+
// Skip body if it can't be stringified
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return curl
|
|
255
|
+
}, [log])
|
|
256
|
+
|
|
257
|
+
if (!log) {
|
|
258
|
+
return (
|
|
259
|
+
<View style={styles.errorContainer}>
|
|
260
|
+
<Text style={styles.errorText}>Log data is missing</Text>
|
|
261
|
+
</View>
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const request = log.request || {}
|
|
266
|
+
const response = log.response || {}
|
|
267
|
+
const status = response.status
|
|
268
|
+
const success = response.success
|
|
269
|
+
const error = log.error
|
|
270
|
+
const duration = log.duration
|
|
271
|
+
|
|
272
|
+
const requestData = request.body
|
|
273
|
+
const responseData = response.data
|
|
274
|
+
const responseSize = formatDataSize(responseData)
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<ScrollView
|
|
278
|
+
style={styles.container}
|
|
279
|
+
contentContainerStyle={styles.contentContainer}
|
|
280
|
+
showsVerticalScrollIndicator={true}
|
|
281
|
+
scrollEventThrottle={16}
|
|
282
|
+
keyboardShouldPersistTaps='handled'
|
|
283
|
+
nestedScrollEnabled={true}>
|
|
284
|
+
<View style={styles.header}>
|
|
285
|
+
<View style={styles.headerInfo}>
|
|
286
|
+
<Text style={styles.url} numberOfLines={2} selectable={true}>
|
|
287
|
+
{request.url || 'Unknown URL'}
|
|
288
|
+
</Text>
|
|
289
|
+
<View style={styles.methodRow}>
|
|
290
|
+
<Text
|
|
291
|
+
style={[
|
|
292
|
+
styles.method,
|
|
293
|
+
{ color: getMethodColor(request.method) },
|
|
294
|
+
]}>
|
|
295
|
+
{(request.method || 'GET').toUpperCase()}
|
|
296
|
+
</Text>
|
|
297
|
+
{status && <ApiStatus status={status} success={success} />}
|
|
298
|
+
</View>
|
|
299
|
+
</View>
|
|
300
|
+
<CopyButton text={request.url || ''} />
|
|
301
|
+
</View>
|
|
302
|
+
|
|
303
|
+
<CollapsibleSection title='Request' initiallyExpanded={true}>
|
|
304
|
+
<View style={styles.content}>
|
|
305
|
+
{requestData && (
|
|
306
|
+
<View style={styles.dataSection}>
|
|
307
|
+
<View style={styles.dataSectionHeader}>
|
|
308
|
+
<Text style={styles.dataSectionTitle}>
|
|
309
|
+
Body {formatDataSize(requestData)}
|
|
310
|
+
</Text>
|
|
311
|
+
<CopyButton
|
|
312
|
+
text={
|
|
313
|
+
typeof requestData === 'string'
|
|
314
|
+
? requestData
|
|
315
|
+
: JSON.stringify(requestData, null, 2)
|
|
316
|
+
}
|
|
317
|
+
/>
|
|
318
|
+
</View>
|
|
319
|
+
<View style={styles.dataContent}>
|
|
320
|
+
<JSONValue value={requestData} maxExpandLevel={1} />
|
|
321
|
+
</View>
|
|
322
|
+
</View>
|
|
323
|
+
)}
|
|
324
|
+
|
|
325
|
+
<CollapsibleSection title='Headers'>
|
|
326
|
+
<View style={styles.dataContent}>
|
|
327
|
+
<JSONValue value={request.headers || {}} maxExpandLevel={0} />
|
|
328
|
+
</View>
|
|
329
|
+
</CollapsibleSection>
|
|
330
|
+
</View>
|
|
331
|
+
</CollapsibleSection>
|
|
332
|
+
|
|
333
|
+
<CollapsibleSection
|
|
334
|
+
title={`Response ${responseSize}`}
|
|
335
|
+
initiallyExpanded={true}>
|
|
336
|
+
<View style={styles.content}>
|
|
337
|
+
<View style={styles.row}>
|
|
338
|
+
<Text style={styles.label}>Status:</Text>
|
|
339
|
+
<Text style={styles.value}>
|
|
340
|
+
{status || (success === false ? 'Error' : 'Unknown')}
|
|
341
|
+
{status && response.statusText ? ` (${response.statusText})` : ''}
|
|
342
|
+
</Text>
|
|
343
|
+
</View>
|
|
344
|
+
|
|
345
|
+
{duration && (
|
|
346
|
+
<View style={styles.row}>
|
|
347
|
+
<Text style={styles.label}>Duration:</Text>
|
|
348
|
+
<Text style={styles.value}>{duration}ms</Text>
|
|
349
|
+
</View>
|
|
350
|
+
)}
|
|
351
|
+
|
|
352
|
+
{error && (
|
|
353
|
+
<View style={styles.errorSection}>
|
|
354
|
+
<Text style={styles.errorLabel}>Error:</Text>
|
|
355
|
+
<Text style={styles.errorValue} selectable={true}>
|
|
356
|
+
{error}
|
|
357
|
+
</Text>
|
|
358
|
+
</View>
|
|
359
|
+
)}
|
|
360
|
+
|
|
361
|
+
{responseData && (
|
|
362
|
+
<View style={styles.dataSection}>
|
|
363
|
+
<View style={styles.dataSectionHeader}>
|
|
364
|
+
<Text style={styles.dataSectionTitle}>Body</Text>
|
|
365
|
+
<CopyButton
|
|
366
|
+
text={
|
|
367
|
+
typeof responseData === 'string'
|
|
368
|
+
? responseData
|
|
369
|
+
: JSON.stringify(responseData, null, 2)
|
|
370
|
+
}
|
|
371
|
+
/>
|
|
372
|
+
</View>
|
|
373
|
+
<View style={styles.dataContent}>
|
|
374
|
+
<JSONValue value={responseData} maxExpandLevel={1} />
|
|
375
|
+
</View>
|
|
376
|
+
</View>
|
|
377
|
+
)}
|
|
378
|
+
|
|
379
|
+
<CollapsibleSection title='Headers'>
|
|
380
|
+
<View style={styles.dataContent}>
|
|
381
|
+
<JSONValue value={response.headers || {}} maxExpandLevel={0} />
|
|
382
|
+
</View>
|
|
383
|
+
</CollapsibleSection>
|
|
384
|
+
</View>
|
|
385
|
+
</CollapsibleSection>
|
|
386
|
+
|
|
387
|
+
<CollapsibleSection title='cURL Command'>
|
|
388
|
+
<View style={styles.content}>
|
|
389
|
+
<View style={styles.codeBlockContainer}>
|
|
390
|
+
<View style={styles.codeBlockHeader}>
|
|
391
|
+
<Text style={styles.codeBlockLabel}>Debug with cURL</Text>
|
|
392
|
+
<CopyButton text={generateCurl()} />
|
|
393
|
+
</View>
|
|
394
|
+
<View style={styles.codeBlock}>
|
|
395
|
+
<Text style={styles.codeText} selectable={true}>
|
|
396
|
+
{generateCurl()}
|
|
397
|
+
</Text>
|
|
398
|
+
</View>
|
|
399
|
+
</View>
|
|
400
|
+
</View>
|
|
401
|
+
</CollapsibleSection>
|
|
402
|
+
|
|
403
|
+
<CollapsibleSection title='Timing'>
|
|
404
|
+
<View style={styles.content}>
|
|
405
|
+
<Text style={styles.label}>Time:</Text>
|
|
406
|
+
<Text style={styles.value}>
|
|
407
|
+
{log.timestamp
|
|
408
|
+
? new Date(log.timestamp).toLocaleString()
|
|
409
|
+
: 'Unknown'}
|
|
410
|
+
</Text>
|
|
411
|
+
|
|
412
|
+
<Text style={styles.label}>Duration:</Text>
|
|
413
|
+
<Text style={styles.value}>
|
|
414
|
+
{log.duration ? `${log.duration}ms` : 'Unknown'}
|
|
415
|
+
</Text>
|
|
416
|
+
</View>
|
|
417
|
+
</CollapsibleSection>
|
|
418
|
+
</ScrollView>
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const getMethodColor = (method) => {
|
|
423
|
+
switch (method?.toUpperCase()) {
|
|
424
|
+
case 'GET':
|
|
425
|
+
return '#0D96F2' // Standard API blue
|
|
426
|
+
case 'POST':
|
|
427
|
+
return '#49CC90' // Swagger green
|
|
428
|
+
case 'PUT':
|
|
429
|
+
return '#FCA130' // Standard PUT orange
|
|
430
|
+
case 'DELETE':
|
|
431
|
+
return '#F93E3E' // Standard DELETE red
|
|
432
|
+
default:
|
|
433
|
+
return '#666666'
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const styles = StyleSheet.create({
|
|
438
|
+
container: {
|
|
439
|
+
flex: 1,
|
|
440
|
+
backgroundColor: '#fff',
|
|
441
|
+
},
|
|
442
|
+
contentContainer: {
|
|
443
|
+
paddingBottom: 20,
|
|
444
|
+
},
|
|
445
|
+
header: {
|
|
446
|
+
flexDirection: 'row',
|
|
447
|
+
padding: 15,
|
|
448
|
+
borderBottomWidth: 1,
|
|
449
|
+
borderBottomColor: '#eee',
|
|
450
|
+
alignItems: 'flex-start',
|
|
451
|
+
},
|
|
452
|
+
headerInfo: {
|
|
453
|
+
flex: 1,
|
|
454
|
+
marginRight: 10,
|
|
455
|
+
},
|
|
456
|
+
url: {
|
|
457
|
+
fontSize: 14,
|
|
458
|
+
color: '#333',
|
|
459
|
+
marginBottom: 6,
|
|
460
|
+
fontWeight: '500',
|
|
461
|
+
},
|
|
462
|
+
methodRow: {
|
|
463
|
+
flexDirection: 'row',
|
|
464
|
+
alignItems: 'center',
|
|
465
|
+
},
|
|
466
|
+
method: {
|
|
467
|
+
fontSize: 14,
|
|
468
|
+
fontWeight: 'bold',
|
|
469
|
+
marginRight: 8,
|
|
470
|
+
},
|
|
471
|
+
statusPill: {
|
|
472
|
+
paddingHorizontal: 8,
|
|
473
|
+
paddingVertical: 2,
|
|
474
|
+
borderRadius: 12,
|
|
475
|
+
color: 'white',
|
|
476
|
+
fontSize: 12,
|
|
477
|
+
fontWeight: 'bold',
|
|
478
|
+
},
|
|
479
|
+
collapsibleSection: {
|
|
480
|
+
marginBottom: 1,
|
|
481
|
+
backgroundColor: '#fff',
|
|
482
|
+
},
|
|
483
|
+
sectionHeader: {
|
|
484
|
+
flexDirection: 'row',
|
|
485
|
+
justifyContent: 'space-between',
|
|
486
|
+
alignItems: 'center',
|
|
487
|
+
padding: 15,
|
|
488
|
+
backgroundColor: '#f5f5f5',
|
|
489
|
+
},
|
|
490
|
+
sectionTitle: {
|
|
491
|
+
fontSize: 15,
|
|
492
|
+
fontWeight: 'bold',
|
|
493
|
+
color: '#333',
|
|
494
|
+
},
|
|
495
|
+
expandIcon: {
|
|
496
|
+
fontSize: 14,
|
|
497
|
+
color: '#666',
|
|
498
|
+
},
|
|
499
|
+
content: {
|
|
500
|
+
padding: 15,
|
|
501
|
+
},
|
|
502
|
+
row: {
|
|
503
|
+
marginBottom: 10,
|
|
504
|
+
},
|
|
505
|
+
label: {
|
|
506
|
+
fontSize: 14,
|
|
507
|
+
fontWeight: 'bold',
|
|
508
|
+
color: '#666',
|
|
509
|
+
marginBottom: 5,
|
|
510
|
+
},
|
|
511
|
+
value: {
|
|
512
|
+
fontSize: 14,
|
|
513
|
+
color: '#333',
|
|
514
|
+
marginBottom: 10,
|
|
515
|
+
},
|
|
516
|
+
errorContainer: {
|
|
517
|
+
flex: 1,
|
|
518
|
+
justifyContent: 'center',
|
|
519
|
+
alignItems: 'center',
|
|
520
|
+
padding: 20,
|
|
521
|
+
},
|
|
522
|
+
errorText: {
|
|
523
|
+
color: '#ff4444',
|
|
524
|
+
fontSize: 16,
|
|
525
|
+
},
|
|
526
|
+
errorSection: {
|
|
527
|
+
backgroundColor: '#fff8f8',
|
|
528
|
+
padding: 10,
|
|
529
|
+
borderRadius: 4,
|
|
530
|
+
borderWidth: 1,
|
|
531
|
+
borderColor: '#ffdddd',
|
|
532
|
+
marginBottom: 15,
|
|
533
|
+
},
|
|
534
|
+
errorLabel: {
|
|
535
|
+
fontSize: 14,
|
|
536
|
+
fontWeight: 'bold',
|
|
537
|
+
color: '#ff4444',
|
|
538
|
+
marginBottom: 5,
|
|
539
|
+
},
|
|
540
|
+
errorValue: {
|
|
541
|
+
fontSize: 14,
|
|
542
|
+
color: '#ff4444',
|
|
543
|
+
},
|
|
544
|
+
dataSection: {
|
|
545
|
+
marginBottom: 15,
|
|
546
|
+
},
|
|
547
|
+
dataSectionHeader: {
|
|
548
|
+
flexDirection: 'row',
|
|
549
|
+
justifyContent: 'space-between',
|
|
550
|
+
alignItems: 'center',
|
|
551
|
+
marginBottom: 5,
|
|
552
|
+
},
|
|
553
|
+
dataSectionTitle: {
|
|
554
|
+
fontSize: 14,
|
|
555
|
+
fontWeight: 'bold',
|
|
556
|
+
color: '#666',
|
|
557
|
+
},
|
|
558
|
+
dataContent: {
|
|
559
|
+
backgroundColor: '#f8f9fa',
|
|
560
|
+
padding: 10,
|
|
561
|
+
borderRadius: 4,
|
|
562
|
+
borderWidth: 1,
|
|
563
|
+
borderColor: '#e9ecef',
|
|
564
|
+
},
|
|
565
|
+
codeBlockContainer: {
|
|
566
|
+
marginBottom: 15,
|
|
567
|
+
},
|
|
568
|
+
codeBlockHeader: {
|
|
569
|
+
flexDirection: 'row',
|
|
570
|
+
justifyContent: 'space-between',
|
|
571
|
+
alignItems: 'center',
|
|
572
|
+
marginBottom: 5,
|
|
573
|
+
},
|
|
574
|
+
codeBlockLabel: {
|
|
575
|
+
fontSize: 12,
|
|
576
|
+
color: '#666',
|
|
577
|
+
fontWeight: 'bold',
|
|
578
|
+
},
|
|
579
|
+
codeBlock: {
|
|
580
|
+
backgroundColor: '#f8f9fa',
|
|
581
|
+
padding: 10,
|
|
582
|
+
borderRadius: 4,
|
|
583
|
+
borderWidth: 1,
|
|
584
|
+
borderColor: '#e9ecef',
|
|
585
|
+
},
|
|
586
|
+
codeText: {
|
|
587
|
+
fontSize: 13,
|
|
588
|
+
color: '#333',
|
|
589
|
+
fontFamily: 'Courier',
|
|
590
|
+
},
|
|
591
|
+
copyButton: {
|
|
592
|
+
backgroundColor: '#e9ecef',
|
|
593
|
+
paddingHorizontal: 10,
|
|
594
|
+
paddingVertical: 5,
|
|
595
|
+
borderRadius: 4,
|
|
596
|
+
},
|
|
597
|
+
copyButtonText: {
|
|
598
|
+
fontSize: 12,
|
|
599
|
+
color: '#666',
|
|
600
|
+
},
|
|
601
|
+
jsonContainer: {
|
|
602
|
+
marginVertical: 2,
|
|
603
|
+
},
|
|
604
|
+
jsonToggle: {
|
|
605
|
+
flexDirection: 'row',
|
|
606
|
+
alignItems: 'center',
|
|
607
|
+
},
|
|
608
|
+
jsonBrackets: {
|
|
609
|
+
color: '#666',
|
|
610
|
+
fontWeight: 'bold',
|
|
611
|
+
},
|
|
612
|
+
jsonCollapsed: {
|
|
613
|
+
color: '#888',
|
|
614
|
+
fontSize: 12,
|
|
615
|
+
fontStyle: 'italic',
|
|
616
|
+
},
|
|
617
|
+
jsonChildren: {
|
|
618
|
+
paddingLeft: 16,
|
|
619
|
+
borderLeftWidth: 1,
|
|
620
|
+
borderLeftColor: '#e0e0e0',
|
|
621
|
+
},
|
|
622
|
+
jsonProperty: {
|
|
623
|
+
flexDirection: 'row',
|
|
624
|
+
flexWrap: 'wrap',
|
|
625
|
+
marginVertical: 2,
|
|
626
|
+
},
|
|
627
|
+
jsonArrayItem: {
|
|
628
|
+
flexDirection: 'row',
|
|
629
|
+
flexWrap: 'wrap',
|
|
630
|
+
marginVertical: 2,
|
|
631
|
+
},
|
|
632
|
+
jsonKey: {
|
|
633
|
+
color: '#7B61AB',
|
|
634
|
+
fontWeight: '500',
|
|
635
|
+
},
|
|
636
|
+
jsonValue: {
|
|
637
|
+
flex: 1,
|
|
638
|
+
},
|
|
639
|
+
jsonString: {
|
|
640
|
+
color: '#CB772F',
|
|
641
|
+
},
|
|
642
|
+
jsonNumber: {
|
|
643
|
+
color: '#2878D0',
|
|
644
|
+
},
|
|
645
|
+
jsonBoolean: {
|
|
646
|
+
color: '#2878D0',
|
|
647
|
+
fontWeight: 'bold',
|
|
648
|
+
},
|
|
649
|
+
jsonNull: {
|
|
650
|
+
color: '#A0A0A0',
|
|
651
|
+
fontStyle: 'italic',
|
|
652
|
+
},
|
|
653
|
+
jsonObject: {
|
|
654
|
+
color: '#666',
|
|
655
|
+
},
|
|
656
|
+
jsonArray: {
|
|
657
|
+
color: '#666',
|
|
658
|
+
},
|
|
659
|
+
longTextContainer: {
|
|
660
|
+
maxHeight: 200,
|
|
661
|
+
paddingHorizontal: 8,
|
|
662
|
+
paddingVertical: 5,
|
|
663
|
+
},
|
|
664
|
+
})
|
|
665
|
+
|
|
666
|
+
export default HttpLogDetails
|